前面幾天講的 scope,本質上是一個爆炸半徑控制機制。
假設最壞情況發生了:某個 Token 的對應關係洩漏了。損害範圍是多少?
隔離不能防止洩漏,但它決定了洩漏的規模。這跟網路分段是同一個思路。
維度一:範圍隔離(scope)。 已經講過,用 scope_id 混進 HMAC 實現。
維度二:金鑰隔離。 不同的資料分類用不同的 DEK。
DEK-general → 一般個資(姓名、電話、地址)
DEK-financial → 金融資訊(帳號、卡號)
DEK-sensitive → 特種個資(如果有需要還原的話)
好處是一把金鑰洩漏不等於全部洩漏。而且可以對不同金鑰設定不同的存取權限——例如只有特定角色能用 DEK-financial 解密。
維度三:時間隔離。 Token 有有效期,過期後即使有金鑰也還原不了(因為 Vault 裡的對應已被刪除)。
三個維度組合起來,一次洩漏的損害被限制在「某個案件、某個資料分類、某個時間區間」的交集。
比起單純把 scope 放進 HMAC 輸入,更強的做法是每個 scope 派生一把獨立的子金鑰:
from cryptography.hazmat.primitives.kdf.hkdf import HKDF
from cryptography.hazmat.primitives import hashes
def derive_scope_key(master_key: bytes, scope_id: str) -> bytes:
hkdf = HKDF(
algorithm=hashes.SHA256(),
length=32,
salt=None,
info=f"pii-vault:scope:{scope_id}".encode(),
)
return hkdf.derive(master_key)
這樣的好處是可以單獨銷毀一個 scope:把該 scope 的派生金鑰標記為失效,該案件的所有 Token 就再也還原不了,不需要去 Vault 裡逐筆刪除。
這叫做 crypto-shredding,對於「案件結案後應銷毀資料」這類要求非常實用——尤其是當備份難以逐筆修改的時候。你不需要刪掉備份裡的資料,只要確保金鑰沒了。
問題一:律師換案件時看到不同的假名。
同一個客戶,在案件 A 裡叫「林建成」,在案件 B 裡叫「陳志豪」。律師會混淆。
處理方式是在 UI 層做提示,或者提供一個「這個 Token 在其他案件的對應」的查詢功能——但那個查詢本身要走授權流程(等於 D17 的 scope merge)。
問題二:Vault 膨脹。
同一個人在 50 個案件裡,就有 50 筆對應。這是隔離的必然代價。
緩解方式是 D11 提到的:能用 FPE 的欄位都用 FPE(無狀態,不進 Vault)。只有人名、地址這類自由文字才進 Vault。這樣即使膨脹,體積也可控。
問題三:跨案件統計分析做不了。
例如「本行今年被同一批人重複申訴幾次」這種分析,需要跨案件關聯。
正解不是放寬隔離,而是另外建立一個專供統計的、單向不可還原的識別碼:
def analytics_id(real_value: str, analytics_key: bytes) -> str:
"""單向雜湊,只能比對相同性,不能還原"""
return hmac.new(
analytics_key, real_value.encode(), hashlib.sha256
).hexdigest()[:16]
這個 ID 全域一致(可以做統計),但它沒有對應表——沒有任何機制可以從它還原出原值。用它做統計,用 scoped Token 做文件處理,兩者不互通。
這是一個很好用的模式:把「需要關聯」和「需要還原」這兩個需求分開,用兩套不同的識別碼滿足。
有些設計會把 scope 設成 session ID——每次使用者開啟一個新的對話,就是一個新的 Token 空間。
好處是隔離最徹底。壞處是:
我的建議是不要用 session 級,除非你的場景是純一次性的查詢。法務工作是持續性的,案件級才符合工作模式。
明天談還原授權:誰能按下那個按鈕。
我是 Fngi,專注在 AI 資安、LLM 紅隊與 AI 治理框架落地。
IG:@aid3fend
有想討論的架構細節或不同意見,留言或私訊都歡迎。