JOVANA
Explore Library Glossary Getting Started Three Levels Fields How it works Mission
Join the mission
All guides

保護與安全的分別,以及最小權限

保護與安全,這兩個常被當成同義詞的字,其實指的是作業系統必須做的兩件不同的工作。這篇導覽會把兩者的差別釘牢,交給你一條值得刺在手腕上的設計原則(最小權限),並攤開一張威脅與防禦的地圖——本階接下來會逐一細看其中每一站。

兩件工作,兩個字:保護與安全

你爬這整道階梯時,一路都在看作業系統把東西彼此隔開。它給每個行程自己的位址空間,讓一個程式沒法在另一個的記憶體上亂塗;它翻動模式位元,讓一般的程式碼不能執行特權指令;它在讓你寫入之前先檢查檔案的權限位元。這一切,是同一件工作。但在第一件工作背後,藏著第二件、更尖銳的工作,而安全這一階,正是我們終於把兩者分開的地方。這兩件工作甚至有不同的名字——保護(protection)與安全(security)——而把它們混為一談的人,最後往往蓋出防錯了對象的系統。

這裡有個最乾淨的方式去把握這個差別,它也是保護與安全的核心。保護是內部的:它是作業系統用來控制「哪個行程或使用者可以存取哪個資源」的一整套機制——讓誠實的各方不會不小心踩到彼此。權限位元、雙模式的界線、分開的位址空間:這些都是保護。安全是外部的:它是「防禦系統、抵抗一個刻意的對手」這整個問題——那個對手正積極地試圖打破你的假設——而它涵蓋的是政策、以及機器之外的整個世界,不只是程式碼。保護問的是「這次存取有沒有遵守規則?」安全問的是「這些規則、以及它們所立足的一切,面對一個真心想闖進來的人,到底夠不夠好?」

我們到底在守護什麼?CIA 三要素

在你能守護一套系統之前,你得先說清楚「安全」是什麼意思,而這個領域的答案,是一張俐落的三段式檢查表,叫CIA 三要素——跟那個情報局無關,只是三個字首。機密性(Confidentiality):祕密保持祕密;只有被允許的人才能讀那份資料(你的密碼檔、你的私訊)。完整性(Integrity):資料不被任何未授權的人竄改;你讀到的位元組,就是本該在那裡的位元組,不是攻擊者偷換進來的東西。可用性(Availability):系統對有權使用它的人保持可用;一個刪掉你檔案、或把你的伺服器灌爆到倒下的攻擊者,所破壞的可用性,跟一個讀走你祕密的攻擊者所破壞的,一樣確鑿。

三要素之所以好用,正是因為攻擊通常瞄準它的某一個角,而幫上某一角的防禦,對另一角可能毫無作用。把磁碟加密,能在它被偷走時保護機密性,但要是有人絆到電源線,它對可用性毫無幫助。一個檢查碼守護完整性,卻一個祕密都不保。所以,往後三篇導覽裡每讀到一種威脅或一道防禦,請養成習慣問問:它講的是哪個字母?也要對它的極限誠實:三要素是一面透鏡,不是一份證明——它幫你注意到自己在保護什麼,但它本身並不告訴你,你的機制夠不夠強。

一條值得奉行的原則:最小權限

如果你從這整一階只記住一個想法,就讓它是最小權限原則:每個行程、使用者與元件,都應該只被賦予它完成工作所需的那些權利——一個多的都不給。一台只負責從某個資料夾送出檔案的網頁伺服器,沒有道理握著重新格式化磁碟的權力。一個看照片的應用程式,不需要你的通訊錄。最小權限不會阻止臭蟲或攻擊發生;它做的,是當這些事真的發生時,把爆炸半徑縮小。如果那個照片檢視器被攻破,但它從頭到尾只擁有讀一個資料夾的權限,那麼劫持它的攻擊者,繼承到的就剛好是那個——一個資料夾——而不是整台機器的鑰匙。

最小權限並不孤單;它身處一個值得逐一叫得出名字的設計原則小家族裡。安全預設(fail-safe defaults):拿不定主意時就拒絕——從「一切都禁止」開始、再明確地授予存取,而不是從敞開開始、再試著堵漏洞。機制節約(economy of mechanism):把安全關鍵的部分保持得小而簡單,因為你沒法稽核你看不懂的東西。完全仲裁(complete mediation):檢查每一次存取,而不只是第一次,這樣一個被撤銷的權限才會真的生效。權限分立(separation of privilege):要授予最危險的權力,得滿足不只一個條件(這跟「發射要兩把鑰匙」背後是同一種直覺)。這些不是物理定律——它們是得來不易的經驗法則,而真實系統在壓力下時時刻刻都在打破它們。認得它們,能讓你察覺一個設計是不是正悄悄發出遠超它該有的權力。

我們信任誰?可信計算基礎

每一個安全論證,私底下都立足在某個你決定不去質疑的東西上——而假裝並非如此,正是系統垮掉的方式。誠實的做法是把那個東西大聲說出來:可信計算基礎(trusted computing base,TCB),是「為了讓你的安全成立、絕對必須正確運作」的所有硬體、韌體與軟體的集合。只要 TCB 裡有任何一塊有臭蟲或被顛覆,蓋在它上頭的每一個保證,都可能悄悄垮掉,不管系統的其餘部分有多小心。所以 TCB 不是「你因為它安全而信任的」那部分;它是「你被迫去信任的」那部分——而這正是你會想讓它小的原因。

在一套正常的作業系統上,核心穩穩地位在 TCB 之內,因為它跑在核心模式、擁有碰任何記憶體與任何裝置的權力;你很早就學到的那道雙模式界線,正是把不受信任的使用者模式程式碼擋在外面的那堵牆。這也是「微核心」這個想法(你在核心結構那一階見過)之所以誘人的一個深層理由:把驅動程式與服務推出核心、放進一般的使用者行程,它就縮小了那塊「絕對必須正確」的程式碼。但要誠實——比較小的 TCB 不會自動就是比較安全的系統。微核心用額外的訊息傳遞成本,換來那份小巧;而一個塞滿微妙臭蟲的小 TCB,比一個較大、卻久經沙場的還糟。小巧是通往「可稽核」的手段,本身並不是一份保證。

本階的地圖:威脅、機制、防禦

詞彙就位之後,這裡是接下來四篇導覽要走的疆域,好讓你看出各塊怎麼拼在一起。首先我們需要一種方式去寫下「誰可以做什麼」:那就是存取矩陣——一張巨大的表,把主體(使用者、行程)對上客體(檔案、裝置),說明每個主體可以做哪些操作——以及把它切開的兩種實務做法:要嘛遞給每個主體一張它的能力(capabilities)清單,要嘛在每個客體上附一張存取控制清單。第二篇導覽會拆解這個取捨,連同那些硬體保護環——它把權限等級像同心圓那樣層層相套,核心位在最中心的第 0 環,越不受信任的東西放在越外圈。

接著我們轉向對手。第三篇導覽巡視威脅全貌:各個惡意軟體家族(一隻搭在別的程式裡頭的病毒、一隻能自己跨網路擴散的蠕蟲、一隻謊報自己是什麼的木馬、一隻藏得夠深、深到能騙過作業系統本身的 rootkit),以及它們底下那些經典的技術性攻擊——寫過陣列尾端、藉以劫持控制流的緩衝區溢位,以及把一個小立足點變成完全掌控的權限提升。第四篇導覽講的是證明你是誰——身分驗證、為什麼密碼是以雜湊加鹽而非明文的形式儲存,以及第二個因子到底替你買到了什麼。第五篇導覽則是反擊:那些現代防禦(ASLR、DEP/NX、堆疊金絲雀、安全啟動、沙箱、SELinux 與 AppArmor)——今天的作業系統把它們層層疊起,好讓任何單一個失誤都不至於致命。

最後這個想法,是把整一階串起來的那條線,而它有個名字:縱深防禦。沒有哪一堵牆能撐到永遠,所以你蓋很多堵——而且你把它們排列成「每一堵都假設它外面那幾堵或許已經失守」。最小權限縮小了每一次破口值多少;一個小小的 TCB 縮小了「什麼必須完美無瑕」;分層防禦則確保:闖過第一把鎖,仍會讓攻擊者面對第二把、第三把。握住這幅畫面,本階接下來就不再是一串嚇人的縮寫,而成了一套連貫的策略:假設事情會出錯,並且把系統蓋成「出錯時,損害很小」。