iT邦幫忙

2026 iThome 鐵人賽

DAY 15
0

LEVEL 5 聽起來最強,為什麼權限卻是零?

如果只看到 LEVEL_5,很容易把它想成系統管理員:數字最大,能做的事應該最多。但在目前的心理支持契約裡,LEVEL_5_CRISIS_PROTOCOL 對「一般支持回應」的許可其實是零;LEVEL_2_LOW_RISK_SKILL_SUPPORT 反而是三。這不是編號排錯,而是我今天必須先拆掉的一個直覺:這裡的 level 描述回應模式,不是職位、專業資格或萬用通行證。

昨天留下的問題是,政策說「不允許」之後,哪一道邊界能阻止其他元件把決定改回來。今天往下追,我發現單靠一個名為 authority 的欄位還回答不了這件事。它至少混合了三種不同問題:這次回應可以說到哪裡、這個呼叫者可以操作哪份資料,以及某項破壞性動作是否得到另一份核准。若三者共用同一把「高低權限」尺,名稱越威風,越容易讓人誤以為它什麼都能做。

回應模式不是身分授權

src/psychological_support/safety/policy.py 沒有直接拿 level 的數字比較大小,而是另外定義一般支持的許可排序:

_PERMISSION_RANK = {
    AuthorityLevel.LEVEL_0_GENERAL_SUPPORT: 1,
    AuthorityLevel.LEVEL_1_PSYCHOEDUCATION: 2,
    AuthorityLevel.LEVEL_2_LOW_RISK_SKILL_SUPPORT: 3,
    AuthorityLevel.LEVEL_3_SUPERVISED_SENSITIVE_SUPPORT: 1,
    AuthorityLevel.LEVEL_4_RESTRICTED_RESPONSE: 0,
    AuthorityLevel.LEVEL_5_CRISIS_PROTOCOL: 0,
}

這張表刻意讓較高風險或較高不確定性只能維持或減少一般支持範圍。今天的四項安全不變量測試重新確認:風險從低往上移時,許可排序是 3、2、0、0;未知或缺少必要輸入也不會被當成低風險。它驗證的是本地規則對合成輸入的單調性,不是臨床風險評估,也不代表危機情境已由系統處理完成。

這也說明為什麼 AuthorityLevel 不能直接拿去當登入角色。回應模式回答的是「這次內容生成應受什麼限制」,身分授權回答的則是「誰能對哪一項資源做哪個動作」。前者即使是 LEVEL_2,也不會因此取得讀取資料、寫入狀態或執行刪除的資格;後者即使辨識出合法擁有者,也不能自行放寬安全回應。

名字、資料與序列化都不能自己生出權限

目前的本地編排邊界每次呼叫都先請受信任的 resolver 解析一個不透明 handle,再比對 owner。呼叫者若直接送入 owner ID、看起來合法的 context,甚至自己建立一個帶有 OWNER 字樣的物件,都不會因此通過。測試也刻意偽造 ADMIN context、跨 owner 讀寫與未登錄 handle,確認這些輸入在接觸儲存操作前被拒絕。

這個設計背後有一條簡單規則:可被複製、改字或序列化的資料,只能描述一項宣稱,不能成為宣稱成立的證明。真正的授權來自主機預先安裝的綁定與當次解析;系統也不快取上一次解析結果,所以 handle 被撤銷後,下一次呼叫必須重新被拒絕。換句話說,「我是誰」和「我說我是誰」必須是兩件不同的事。

把解析放在每次操作之前,也是在處理時間問題。昨天有效的身分不必然今天仍有效;若程式只在建立連線時查一次,後續操作就可能繼續沿用已失效的判斷。這裡的本地 lease 讓撤銷與同步操作有明確先後,但它仍不是跨程序、跨主機的正式 session 機制。

到了動作層,政策使用明確 allowlist。讀取、寫入、狀態變更、撤回、儲存存取與管理操作是不同 action;沒有符合 owner、tenant、resource 與 action 的完整 grant,就走 default deny。即使 principal 的種類叫作 system,也沒有隱含的管理員權限。這比替角色排一條由低到高的隊伍更繁瑣,卻能回答真正重要的問題:誰、在什麼範圍、被允許做哪一件事。

危險動作需要另一把鑰匙

光把 action 拆開仍不夠。一般應用程式拿到的 facade 只有 execute,合成 bridge 只有 submit;它們沒有公開任意資料庫操作,也沒有 recovery 入口。當資料損壞而撤回流程需要破壞性復原時,除了原本的 owner 身分,還必須提供另一種 recovery assertion,而且只能匹配預先核准的同一份 request、用途與有效時間窗。

這不是在物件名稱上寫「recovery」而已。一般身分不能冒充 recovery authority,recovery assertion 也不能拿來當一般身分;複製核准內容、改 request ID、改時間或換用途都會失敗。今天執行的另一組 234 項本地合成測試,涵蓋狀態轉移、owner 編排、預設拒絕、撤銷、跨 owner 操作、facade 分離與 recovery 負向案例,全部通過。這些測試沒有連接正式 IAM、真實使用者、模型、網路服務或正式環境。

已有可執行邊界,不等於完整權限系統

本日尚未完成此部分,以下先整理目前設計與下一步。現有程式已能在本地參考實作中強制部分邊界:拒絕自稱身分、逐次解析、明確 action grant、owner 隔離、facade 分工與第二份復原核准。可是 roadmap 所要求的完整 Authority Levels 還包括正式身分提供者、可治理的角色與 capability model、核准生命週期、撤銷與稽核驗收,以及每條實際產品路徑都無法繞過這些限制。今天沒有這些正式環境證據,也沒有修改產品程式。

目前的 ReferenceIdentityAuthority 與 process-local handle 只適合說明契約和執行順序,不能被包裝成 production IAM。記憶體中的 audit event 也不等於不可竄改、可長期查驗的稽核系統;測試通過只支持測到的本地行為,不能證明所有部署方式與程序權限都受到隔離。

Authority Levels 真正要管理的,從來不是誰的數字比較大,而是每個元件最少需要哪一個能力,並且在能力缺席、過期、被撤銷或資料不一致時確實停下來。今天我能回答的是:限制可以被寫進 resolver、action policy、facade 與雙重核准,而不只留在一個欄位名稱裡。接下來必須追問的是:當這些限制放進真實產品組成後,每一條入口都能守住嗎?


上一篇
# Day 14|Safety Policy Engine:模型回得出來,不代表可以交出去
下一篇
# Day 16|Anti-Sycophancy:同理不代表認同
系列文
《從心出發:30 天打造一套具 RAG、心理支持決策、安全治理與 ARCI 自適應能力的 AI 心理支持平台》17
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言