一般的系統驗收是打分數:功能覆蓋 80%、效能達標、可用性 99.9%,加權平均過門檻就通過。
資料防護系統不能這樣驗。因為某些失敗的性質是不可逆且不可補償的——你不能用「其他 95 項都做得很好」來補償「原文外洩了一次」。
所以驗收標準需要兩層:量化指標(打分數)和重大失敗模式(一票否決)。
今天定義後者。
F1:原文外洩。
任何情況下,未經去識別化的個資離開了受控邊界。
包含:偵測漏抓導致明文送出、管線異常時 fail-open 放行、OCR 路徑繞過偵測、日誌或錯誤訊息夾帶原文。
判定方式:在測試環境對所有外送流量做全量掃描,任何一筆命中即為 F1。
def check_f1(outbound_payloads, gold_pii_list):
"""外送流量中不得出現任何測試個資的原值"""
for payload in outbound_payloads:
for pii in gold_pii_list:
if pii in payload:
return Failure("F1", pii_type=classify(pii),
payload_id=payload.id)
return Pass()
F2:靜默失效。
系統在功能異常的情況下回報成功。
包含:掃描 PDF 抽不出文字但回傳成功、偵測器未載入但回傳空 findings、去識別化失敗但輸出原文。
判定方式:注入故障(拿掉規則檔、關閉模型服務、餵損壞檔案),系統必須明確失敗,不得靜默通過。
F3:Vault 明文暴露。
Vault 中的對應關係以明文形式可被讀取。
包含:資料庫未加密、備份未加密、應用服務帳號能直接查詢、日誌記錄了 Token 原值與對應。
F4:越權還原。
不具還原權限的身分成功取得明文。
包含:一般使用者透過 API 直接呼叫還原端點、跨案件存取未被阻擋、憑證未過期檢查、前端隱藏但後端未驗證。
這一項的測試必須從 API 層做,不是從 UI。UI 上把按鈕藏起來完全不算防護。
F5:稽核軌跡缺失。
敏感操作未被記錄,或記錄無法歸屬到具體的人。
包含:還原操作沒有日誌、日誌只記服務帳號、日誌可被業務身分修改或刪除、trace 無法串接。
F6:一致性錯誤導致實體混淆。
同一實體在同一 scope 內得到不同 Token,或不同實體得到相同 Token。
前者造成模型誤判為多人,後者造成誤判為同一人。兩者都會讓法律分析出錯,而且錯得很難發現。
def check_f6(entity_map, deidentified_docs):
# 一對多:同一實體多個 Token
for entity, tokens in group_by_entity(entity_map).items():
if len(set(tokens)) > 1:
return Failure("F6", kind="split", entity=entity)
# 多對一:不同實體同一 Token
for token, entities in group_by_token(entity_map).items():
if len(set(entities)) > 1:
return Failure("F6", kind="collision", token=token)
return Pass()
F7:特種個資被 Token 化而非遮罩。
健康、犯罪、性生活等第 6 條個資被設定為可還原。
這一項是設計層的失敗,不是執行層的。它代表有人在設定去識別化政策時,把不該留還原路徑的欄位留了。
判定方式:檢查 deidentify 設定檔,任何特種個資 infoType 對應到 crypto_replace_ffx_fpe_config 即為 F7。
SENSITIVE_TYPES = {"HEALTH_INFO", "CRIMINAL_RECORD", "GENETIC_INFO"}
REVERSIBLE = {"crypto_replace_ffx_fpe_config",
"crypto_deterministic_config"}
def check_f7(deidentify_config):
for t in deidentify_config["transformations"]:
types = {it["name"] for it in t["info_types"]}
method = next(iter(t["primitive_transformation"]))
if types & SENSITIVE_TYPES and method in REVERSIBLE:
return Failure("F7", types=list(types & SENSITIVE_TYPES))
return Pass()
在驗收時:任何一項成立,整體不通過。不論其他指標多好。
在開發時:這七項應該是 CI 的 gate。每次 commit 都跑,不過就擋。
在維運時:F1、F2、F5 應該有線上偵測(D20 的告警設計)。
會有人說:「Recall 不可能 100%,你怎麼能要求 F1 零容忍?」
這是兩件事。
Recall 是統計指標,衡量的是偵測能力的平均表現。它確實不可能 100%。
F1 是驗收測試,衡量的是「在這組定義好的測試案例中,有沒有原文外洩」。這組測試案例是有限的、已知的,系統應該全部通過。
如果系統連你設計的測試案例都過不了,那它在真實資料上的表現只會更差。
換句話說:F1 零容忍不是在保證真實世界零外洩,是在確保系統對已知風險有正確行為。 真實世界的殘餘風險,靠 D21 的 fail-closed、D20 的偵測告警、D12 的 Vault 隔離來承接。
驗收文件裡的寫法建議:
重大失敗模式(一票否決)
以下情形任一成立者,本次驗收不通過,不因其他項目表現而抵銷:
F1 原文外洩|F2 靜默失效|F3 Vault 明文暴露|F4 越權還原 F5 稽核軌跡缺失|F6 實體混淆|F7 特種個資可還原
每一項應附測試方法、測試案例編號與判定依據。
最後一句很重要。「不通過」必須有客觀依據,不能是主觀判斷。 否則驗收會變成爭論。
明天把這七項變成自動化的回歸測試。
我是 Fngi,專注在 AI 資安、LLM 紅隊與 AI 治理框架落地。
IG:@aid3fend
有想討論的架構細節或不同意見,留言或私訊都歡迎。