權限分離(privilege separation)
如果一家銀行讓每個櫃員都能打開主金庫,一個被攻陷的櫃員就能把它搬空。實際上,只有少數受信任的職員握有金庫鑰匙,而面對大眾的人幾乎不握任何鑰匙。權限分離就是程式的這個組織原則:把程式切成數塊,讓接觸危險、不受信任輸入的元件以「盡可能少」的權限執行,而真正需要權力的罕見操作,則隔離在一個小而謹慎撰寫的元件裡。
具體而言,它的做法是把一個程式劃分成兩個以上、權限層級不同的行程(或網域),透過一個狹窄、定義良好的通道溝通。經典例子是 OpenSSH:一個小而有特權的「監視者」行程保有需要 root 的權力(例如驗證使用者),而一個龐大、「無特權」的子行程——以 nobody 使用者身分執行、常在 chroot 或命名空間內——負責沉重而危險的工作:剖析來自未經驗證之用戶端的網路協定資料。兩者透過一個帶有微小、受稽核訊息集的管線交談。關鍵點子是最小權限:每一部分只持有其工作所需的權利。所以若攻擊者在網路剖析程式碼(最暴露於敵意輸入的部分)找到漏洞,他們落進無特權的沙箱,沒有 root、幾乎沒有檔案系統、只有通往監視者的那道狹窄通道——而監視者會驗證每一個請求——於是漏洞並不直接授予系統控制。
它之所以重要,是因為它把一個漏洞的後果,從「全面淪陷」改變為「最不受信任之隔間的淪陷」,這正是縱深防禦的核心:假設暴露的部分「將會」被攻破,並安排讓那次攻破被圍堵。誠實的說法:權限分離不防止漏洞;它限制漏洞的觸及範圍,而它的強度只與隔間之間通道的狹窄與正確程度一樣好。一個草率的介面——讓無特權那側能要求有特權那側做太多事——會把你試圖分離的權限又重新合併。它自然地與能力、seccomp、命名空間搭配,那些才是實際在每一部分上施行「少權限」的機制。
[ 監視者行程:root ] <-- 狹窄受稽核管線 --> [ 工作者:nobody、chroot ] 保有驗證 + 金鑰存取 剖析不受信任的網路資料 // 工作者裡的漏洞落進一個無權的沙箱,而非 root 監視者
有風險的剖析器以無權方式執行;有特權的工作隔離在一個微小、受驗證的介面之後。
權限分離限制漏洞的觸及範圍而非防止它,並且只與隔間之間的通道一樣強——過於慷慨的介面會讓無特權那側重新取回你分離出去的權限。