M04 · 階梯 2 · L2
Gatekeeper、quarantine 與 XProtect
com.apple.quarantine 四欄位、各下載通道是否附旗標、Gatekeeper 首次執行評估(簽章→公證→stapling)、App Translocation、XProtect,與 Sequoia 起的政策變更。
簽章只回答一半:「能不能信」
M03 的 CDHash 與 entitlements 回答「這支東西是不是它宣稱的樣子」。Gatekeeper 回答另一半:「這支東西怎麼來的、該不該讓它第一次跑」。兩者正交——一支簽得好好的程式,若帶著「下載自網路」的記號且未經 Apple 公證,照樣被擋。
關鍵字只有一個:quarantine。
Gatekeeper 評估實驗室
瀏覽器啟用 LSFileQuarantineEnabled,下載即附 com.apple.quarantine。
- flags
- 0x0081 · 未評估
- 時間
- 2020-04-05T17:58:24.000Z
- agent
- Safari
- UUID
- A1B2C3D4-0000-4000-8000-000000000001
- 旗標位
- 0x0001 LaunchServices 內部旗標(下載來源/類型相關)。0x0080 LaunchServices 內部旗標(常見於瀏覽器下載)。
UUID 是 LaunchServices QuarantineEventsV2 資料庫的鍵,存原始下載 URL/來源。
quarantine:有(由①通道決定)
- quarantine有 com.apple.quarantine 且為首次執行 → 觸發 Gatekeeper 評估。
- code signing簽章有效。
- notarization未經 Apple 公證(notarize)→「Apple 無法驗證其不含惡意軟體」。
被 Gatekeeper 擋下。
XProtect(簽章式惡意程式掃描,yara)在執行時比對;XProtect Remediator 週期掃描。 模型邊界:本流程為教學決策模型,非真實 syspolicyd 逐位元;quarantine flags 部分位元為 LaunchServices 內部、標為推測。驗證於 macOS 26.3.1(見章末真機卡)。
com.apple.quarantine:一個 xattr,四個欄位
當「會負責的」App 把檔案落地時,它替檔案加一個延伸屬性 com.apple.quarantine,四欄、分號分隔:
0081;5e8a1c40;Safari;A1B2C3D4-0000-4000-8000-0000000000001
└┬─┘ └───┬──┘ └─┬──┘ └──────────────┬──────────────────┘
flags 時戳(hex) 來源 App 事件 UUID
- flags:LaunchServices 內部位元(部分未公開)。常見解讀:
0x0040代表「已通過 Gatekeeper 評估/使用者已核可」,之後不再提示。 - 時戳:十六進位的 Unix 秒數。
- agent:把檔案落地的程式(Safari、
sharingd=AirDrop、Mail…)。 - UUID:
~/Library/Preferences/com.apple.LaunchServices.QuarantineEventsV2這個資料庫的鍵,存原始下載 URL/來源。
實驗室左欄可貼任意 quarantine 字串解碼。
哪些通道會附旗標?(繞過面的起點)
這是 M04 最重要的直覺:不是所有下載都會被 quarantine。
| 通道 | 附 quarantine? | 為什麼 |
|---|---|---|
Safari/Arc/Chrome、Mail、Messages、AirDrop(sharingd) | ✅ | 啟用 LSFileQuarantineEnabled,落地即附旗標 |
| Archive Utility 解壓 | ✅(繼承) | 壓縮檔本身被 quarantine → 解出的檔案傳播旗標 |
curl / wget / scp / git clone | ❌ | CLI 工具不附 quarantine |
沒有 quarantine 旗標 → 首次執行不觸發 Gatekeeper。所以「叫使用者用 curl 抓、或先用會去旗標的工具處理」是真實世界繞過 Gatekeeper 的常見起點。防禦面(M14)反過來把「執行了沒有 quarantine 來源的新二進位」當訊號。
Gatekeeper 首次執行評估
有 quarantine 且是第一次跑時,Gatekeeper(syspolicyd)逐關評估:
- 簽章:未簽 →「未識別的開發者」;簽了但無效(被竄改,cdhash 不符)→ 拒絕。
- 公證 notarization:Developer ID 程式必須經 Apple 公證掃過惡意特徵。未公證 →「Apple 無法驗證其不含惡意軟體」。
- 票根來源:
stapler staple把票根釘進程式 → 離線可驗;否則 Gatekeeper 向 Apple 線上查票根——離線又沒 staple 就驗不了。 - 使用者覆寫:被擋時,可在「系統設定 → 隱私與安全性」按「仍要打開」,per-app 放行(簽章損毀者通常仍不行)。
通過後首次仍可能提示「此 App 下載自網路,確定打開?」,確認後就把 0x0040 記上、不再問。實驗室右欄可逐項切換看判定怎麼變。
⚠ Sequoia 起的政策變更(DESIGN.md §11 P1):macOS 15 Sequoia 起,
spctl修改全域評估狀態的操作(舊稱--master-disable,新版 man page 為--global-disable)已不再受支援——指令還在、但會要你去系統設定確認,CLI 無法再一鍵把 Gatekeeper 設成「任何來源」;要改全域只能透過 MDM 設定描述檔(systempolicycontrol)。日常仍是逐 App 在「隱私與安全性」按「仍要打開」。本機 macOS 26.3.1 實測spctl --master-disable回「needs to be confirmed in System Settings」。
App Translocation:路徑也會騙你
被 quarantine 的 App 若直接從非標準位置(例如 ~/Downloads)執行、且使用者沒把它搬走,macOS 會把它「translocate」到一個唯讀的隨機路徑執行:
/private/var/folders/<xx>/<yy>/T/AppTranslocation/<UUID>/d/Foo.app
目的:瓦解「把惡意 dylib 放在 App 旁、靠相對路徑載入」的詭計——因為 App 看到的自身路徑是隨機唯讀的,旁邊沒有攻擊者放的檔案。把 App 搬進 /Applications(使用者明確移動)即解除 translocation。
XProtect:簽章式掃描
Gatekeeper 管「來源信任」,XProtect 管「像不像已知惡意」:以 yara 規則在執行時比對已知惡意特徵;XProtect Remediator 週期性掃描並清除。它是簽章式(已知威脅),不是行為偵測——新型/客製惡意可能漏網,這就是 M14 端點偵測要補的。
🟢 真機操作卡
xattr -l ~/Downloads/某檔 # 看所有 xattr(含 com.apple.quarantine 四欄)
xattr -p com.apple.quarantine ~/Downloads/某檔 # 只印 quarantine 值
xattr -d com.apple.quarantine ./foo # 移除 quarantine(你自己的檔案才做)
spctl --status # Gatekeeper 是否啟用(assessments enabled)
spctl -a -vvv /path/App.app # 評估某 App:accepted/rejected + source
stapler validate /path/App.app # 票根是否已 staple
system_profiler SPInstallHistoryDataType | head # 安裝史
defaults read /Library/Apple/System/Library/CoreServices/XProtect.bundle/Contents/Info.plist CFBundleShortVersionString
實測對照:
spctl -a -vvv /System/Applications/Calculator.app→「accepted / source=Apple System」。spctl --status→「assessments enabled」。本機 XProtect 版本 5347(macOS 26.3.1)。⚠ 只對自己的檔案做xattr -d;別動系統檔(DESIGN.md §10)。
下一步:M05 SIP / rootless — 為什麼連 root 都寫不進 /System?從 csr bitmask 與 SSV 封印談「執行期 MAC」與「開機期 seal」兩層獨立防線。