使用者請求
│
├─ 從請求文字抽出授權範圍(email、IBAN、動作詞)───┐
│ │
規劃器產生程式碼 │
│ │
↓ │
CaMeL直譯器逐個呼叫執行 │
│ │
├─ 每個呼叫 → 動態權限層 ───────────────────────┤
│ ↓ │
│ ①偵測繞道 → ②看威脅等級 → ③依等級選授權來源 ←┘
│ ↓
│ 放行 or 拒絕
│ ↓
└─ 被拒絕 → 累積訊號 → 有界重擬 or 放棄
三層分別各做一件事,累積訊號、依等級決定授權來源、被擋之後有界地再試。
CaMeL執行過程中會產生一些資訊,但原本用完就丟,這一層把它們留下來,三種訊號,分數到2是可疑,到4是已被操縱,各有權重:
| 訊號 | 權重 | 什麼時候記 |
|---|---|---|
| 政策拒絕 | 2 | 某個呼叫被擋下來 |
| 隔離區拒絕回答 | 3 | 隔離模型判斷內容可疑而不回答 |
| 參數帶不可信資料 | 0 | 呼叫的參數來自工具輸出 |
等級決定什麼東西可以替一個呼叫背書:
| 等級 | 可用的授權來源 |
|---|---|
| 乾淨 | 使用者授權範圍 或 可讀者檢查 |
| 可疑 | 只剩可讀者檢查 |
| 已被操縱 | 全部拒絕,會改變狀態的呼叫一律停用 |
乾淨層比靜態政策寬,這是整個設計的關鍵。
乾淨層必須能放行靜態政策擋掉的東西,授權來源就是使用者自己在請求裡指名的目的地,要把檔案寄給某個地址,那個地址就是被授權的,就算可讀者檢查答不出來也算,這個「寬」有嚴格邊界,只有is_trusted那一類的拒絕可以被翻掉。直譯器自己的資訊流檢查不能翻。
被拒絕之後不直接失敗,給重新規劃的機會,但有三道界線:
| 界線 | 預設 | 防什麼 |
|---|---|---|
| 總重擬次數 | 3 | 無限重試 |
| 單一工具拒絕上限 | 2 | 在同一個工具上反覆試參數 |
| 繞道偵測 | — | 換個寫法瞄準同一個被擋過的目的地 |
Progent被擋之後給模型的訊息是「試試其他工具或參數繼續完成任務」,等於把政策引擎變成一個可以無限查詢的預言機——攻擊者靠反覆試探就能摸出邊界在哪。有界就是不讓它問到底,把隔離區的拒絕當成一般錯誤丟回去除錯,模型會被告知「換個參數再試一次」,然後把額度全部燒在同一個問題上。
每次執行的結果分五類,沒觸發、被救回、預算耗盡、繞道被擋、隔離區拒絕後停止。只看utility分不出「任務成功是因為機制有效」還是「根本沒觸發」。
Day22到Day25每天研究一個,當時看起來是四件事,收斂成同一件事:
| 天 | 洞 | 問題出在 |
|---|---|---|
| 22 | 字面值冒充使用者授權 | is_trusted分不出使用者打的字與模型寫的常數 |
| 23 | 授權範圍蓋過資訊流檢查 | 使用者指名一個目的地,不代表授權把整個硬碟送過去 |
| 24 | 可讀者檢查形同虛設 | 所有欄位都是公開常數時,迴圈跑完沒觸發拒絕就算通過 |
| 25 | 修完第24天反而擋掉合法目的地 | 沒有敏感資料可背書,不等於這個呼叫可疑 |
Day22抓的是常數被錯誤放行,Day25抓的是非常數被錯誤擋下,同一條線的兩端。
一、收權限只能減不能加。 原本政策拒絕的,這一層不放行,除非拒絕理由屬於is_trusted那一類可翻的。
二、使用者授權不能蓋過資訊流檢查。 使用者指名的目的地能翻掉身分判斷,不能翻掉直譯器對資料依賴的判斷。
三、只觀測模式的行為要跟原版完全相同。 掛上這一層但不改任何判斷,結果應該一模一樣,這條可以用來確認這層本身沒有副作用。
| 檔案 | 行數 | 職責 |
|---|---|---|
threat_state.py |
199 | 訊號累積、等級判定、執行結果分類 |
adaptive_policy.py |
311 | 包在原本政策引擎外面,依等級決定授權來源 |
改動的是規劃器那一端(有界重擬、兩條拒絕路徑)與命令列參數。
測試193個,分五層:
| 檔案 | 測試函式 | 守什麼 |
|---|---|---|
test_adaptive_policy.py |
32 | 權限格的每條分支與四個洞的回歸 |
test_bypass_and_outcomes.py |
11 | 繞道偵測與結果分類 |
test_security_replan.py |
8 | 重擬預算與界線 |
test_threat_state.py |
8 | 訊號累積與等級判定 |
test_count_tokens.py |
6 | 既有功能不受影響 |
訊號記錄與政策判斷必須拆開,原本在政策檢查之後才記訊號,導致政策看不到當下這個呼叫的污染狀況。拆成「檢查前記錄參數污染」與「檢查後記錄拒絕」兩步。
看不見的風險類型。訊號全部來自能力標籤與政策拒絕,都是確定性的,好處是不會誤判,代價是視野窄,參數值是不是模型幻想出來的、工具描述跟名稱符不符,能力標籤回答不了。
閾值是設出來的,不是學出來的。2跟4這兩個門檻來自觀察,沒有經過校準。
狀態可以被惡意推升。等級會升代表攻擊者可以想辦法把它推上去,推到已被操縱之後使用者的正常工作就被擋了。這是這個設計自己造出來的攻擊面,成本多少沒有量過。
適用面窄。昨天的數字是40個workspace任務裡5個觸發、16個banking任務裡7個,符合「需要判斷目的地」這個形狀的任務本來就不多。
這套機制的核心只有一句話:權限應該是執行過程的函數,不是工具定義的函數。
靜態政策看的是「這個工具在什麼條件下可以用」,一開始決定,全程不變,動態權限看的是「到目前為止發生了什麼」,因此同一個呼叫在不同時刻會得到不同答案。