iT邦幫忙

2026 iThome 鐵人賽

DAY 17
0

昨天 Day 16 我們攔掉了第一種髒輸入——夾帶「ignore previous instructions」這類想覆寫系統指令的提示注入。注入是「惡意」的,被命中就直接短路擋下、不往下走。但還有另一種輸入,不是惡意、卻同樣不能原封不動往下傳:個資。小林那句「我的員編是 123456…」,員編本身沒有任何攻擊性,可是它一旦流進模型上下文、流進稽核紀錄(audit log),就是一筆裸露的個資。今天這篇就講守門的第二件事——PII 遮罩(PII 即個資),以及一個比想像中棘手的工程細節:規則套用的順序。

本篇結構:

  • 個資不能以原始形態往下傳
  • 規則的套用順序才是真正的難題
  • 這套設計的代價:純數字規則的誤判風險

個資不能以原始形態往下傳

把問題講清楚:使用者輸入裡的個資,不能以原始形態往下傳

「往下傳」有兩個具體去向:

  1. 傳給 LLM——你不會希望員編、手機、身分證號就這樣進到某家外部模型供應商的請求裡。
  2. 寫進 audit log——稽核紀錄要長期保存、要給法遵稽查,裡面躺著一堆明文個資,本身就是合規破口。

所以遮罩不是「美化輸出」,是「防止個資外洩」的硬需求。

《神隱少女》裡,湯婆婆奪走名字就能操縱人,千尋一度連怎麼回家都忘了——真實個資也是這種「真名」:員編、身分證號一旦外流,別人就能拿它冒用你、對上你的身分。遮罩要做的,就是讓你的真名自始至終鎖在門內,對外一律只以代號(***)示人。

這套企業 AI 助理平台要辨識的個資有八類,每一類有自己固定的判別規則與遮罩樣式:

PII 類別 代號 判別規則 遮罩樣式
員編 EMPLOYEE_ID 6 位純數字(無檢核碼) ***
手機 PHONE 09 開頭 09**-***-***
市話 LANDLINE 0 區碼 + 7–8 碼 0*-****-****
身分證 NATIONAL_ID 1 碼英文 + 9 碼數字(過檢核碼) A***
信用卡 CREDIT_CARD 13–19 位數字(過 Luhn 檢核) ****-****-****-****
Email EMAIL @、有網域 ***@***.***
統編 TAX_ID 8 位數字(過統編檢核碼) ********
生日 BIRTHDAY 帶分隔符的日期 ****-**-**

先釐清一個常被混淆的點:這裡要遮的「員編」,指的是使用者在訊息裡打出來的那串行員編號——像小林手敲的 123456,純文字、無檢核碼。它跟 Day 8、Day 11、Day 20 講的「登入身分」不是同一個東西。登入身分是 SSO 驗章確立的 8 碼集團識別碼(corpId),改不動,也不靠這套遮罩去抓。一個是「輸入內容裡的個資」,一個是「請求背後的可信身分」,後面 confused deputy 那道關用的正是後者。

聽起來只是「對每一類各寫一條正規表示式,逐一掃過去遮掉」——如果八類彼此井水不犯河水,確實這麼簡單。問題就出在它們會互相重疊。

規則的套用順序才是真正的難題

先看小林那題遮罩前後的對照,這是最直觀的:

原始: 我的員編是 123456,AD 帳號被鎖了,順便想查內湖分行的營業時間。
遮罩: 我的員編是 ***,AD 帳號被鎖了,順便想查內湖分行的營業時間。
偵測: [EMPLOYEE_ID]

員編 123456 被替成 ***,並標記偵測到 EMPLOYEE_ID 這一類。其餘文字原樣保留——「內湖分行」「AD 帳號」這些不是個資,不該動。看起來乾淨俐落。

但把規則攤開來看,麻煩就浮現了。員編的規則是「6 位數字」。那如果使用者打的是一個 Email,例如 user123456@corp.example?這串裡剛好有連續 6 位數字 123456。要是我們先套員編規則去掃,這 6 碼會先被吃掉、變成 user***@corp.example,於是這個 Email 就被「張冠李戴」遮成了一個殘缺的字串——員編規則誤傷了 Email,而真正的 EMAIL 規則後來想再認它,已經認不出完整形狀了。

解法是給這八類規則排一個固定的套用順序,原則總綱:先具特異性、後泛用

順序 PII 類別 為什麼排這裡
1 EMAIL 形狀最明確(有 @、有網域),如 user123456@corp.example
2 BIRTHDAY(生日/日期) 有分隔符,形狀也明確,如 1990-01-01
3 NATIONAL_ID(身分證) 1 碼英文 + 9 碼數字,有字母錨點、又過檢核碼
4 PHONE(手機) 有固定的 09 前綴特徵
5 LANDLINE(市話) 0 區碼前綴,形狀辨識度高
6 CREDIT_CARD(信用卡) 純數字串、最長(13–19 位),且過 Luhn 檢核
7 TAX_ID(統編) 純數字串、8 位,過統編檢核碼
8 EMPLOYEE_ID(員編) 純數字串、6 位,最短,且無檢核碼

第 6–8 類都是純數字串,只能靠長度互相區分,因此這三類之間再依由長到短排序:信用卡(13–19 位)> 統編(8 位)> 員編(6 位)。

關鍵在「有形狀的先吃、純數字的後吃」。EMAILBIRTHDAYNATIONAL_IDPHONELANDLINE 這些「有特殊符號、字母錨點或固定前綴、辨識度高」的,擺前面先認——先把 user123456@corp.example 整串認定為 Email 遮掉,那它裡頭那 6 碼數字就再也輪不到員編規則去誤傷。等這些有形狀的都認完、從輸入裡「拿走」了,剩下的純數字串才交給 CREDIT_CARDTAX_IDEMPLOYEE_ID 去比。

為什麼長度也要排序?因為短的會是長的子串。一張 16 位的信用卡號裡,隨便切都能切出一段 6 位數字。要是員編(6 位)先掃,它會在信用卡號中間咬掉一段、把卡號遮得支離破碎,而完整的信用卡遮罩樣式根本套不上了。先認長的、整段遮掉,短的規則就沒有殘料可咬。

這跟斷詞時「長 token 優先」的規則是同一個道理:誰先比、誰比得長,決定了最終誰吃到哪一段。順序排錯,遮罩就會張冠李戴——不是漏遮,是「遮錯地方、還把對的形狀破壞掉」,更難回頭補救。

Day 16 講提示注入時提過一個次序:注入要攔在遮罩之前。把兩件事接起來看,整個入境守門的順序就完整了:

  1. 先判注入——命中就短路擋下,不往下走。
  2. 通過了才進到 PII 遮罩——跑這裡的八類偵測。
  3. 遮罩內部又有它自己這套「先特異後泛用」的八步次序

一層套一層,每一步的先後都是刻意排的。

順帶一提,這套偵測規則在 Portal 裡是「一份」共用的——入境守門,跟後面送模型前那道閘,用的是同一套規則,不是各寫各的。共用的好處是規則只有一個事實來源,不會兩邊慢慢漂移、出現「入口遮了、別處沒遮」這種裂縫。為什麼同一份規則要在不只一個地方跑,那是 Day 18 縱深防禦的主題,這裡先按下不表。

這套設計的代價:純數字規則的誤判風險

得誠實講一個邊界:純數字、又沒有「形狀」可抓的規則,只能靠「剛好幾位數」去猜,而長度會撞車。為了壓低誤判,信用卡、統編、身分證這幾類其實多加了一道檢核碼驗證——信用卡走 Luhn、統編走統編檢核碼、身分證走身分證檢核碼。意思是:一串數字光「位數對」還不夠,得連檢核碼也算得過,才會被認成那一類。所以丟一個剛好 8 位的訂單編號進來,過不了統編檢核碼,就不會被誤遮成統編。

但有一類沒有檢核碼可靠:員編。它就是「6 位純數字」,再沒有別的特徵。於是任何剛好 6 位的數字串——訂單編號、分機號碼——都可能被當成員編遮成 ***。這是「純數字、又無檢核碼」這類規則逃不掉的先天限制。

那為什麼還是這麼做?因為在「漏遮真員編」和「誤遮非員編」之間,遮罩這道關刻意偏保守:

  • 漏遮是合規破口——一個真的員編就這樣往下流。
  • 誤遮的代價則常被低估。遮罩發生在送進模型之前,所以誤遮污染的是送進模型的問句本身:使用者問「訂單 100245 出了什麼問題」「分機 123456 一直打不通」,那串 6 碼被遮成 ***,模型收到的是殘缺的提問,答出來的東西就可能跟著錯。所以誤遮不是「日誌裡某個數字變星號」這麼輕,它是一筆功能正確性的損失。比起漏遮,這個代價更可預期、也承受得起。

兩害相權,取可預期的那一個。這個「拿不準時往安全那邊倒」的取向,其實就是 Day 10 那套「高風險操作偏保守」思維的延續。

兩道入境機制的現況與各自限制:

機制 狀態 備註
八類 PII 遮罩、這套順序與檢核碼 已上線 真的在跑的
提示注入偵測 已上線 中英文常見句式都涵蓋、且先做正規化(全形/隱形字元);但仍是句式比對,擋不掉編碼變形與純語義改寫(Day 16 講過)

遮罩規則本身是中性的、不分語言,認的是數字與符號的形狀。這也劃出了它最該講清楚的天花板:這八類個資全都是「有形狀」的——員編是幾位數字,手機 09 開頭,信用卡過 Luhn。但行務對話裡真正最常見的個資,有一大類根本沒有固定形狀:中文姓名(「我是王小明」「幫我查李美華的工單」)、住家地址、用白話講出來的帳戶餘額。這些 regex 天生抓不到——它能認出 123456 長得像員編,卻認不出「王小明」是個姓名。這不是規則調得不夠細,是形狀比對這個方法本身的邊界:要抓沒有形狀、只能靠語意判斷的個資,得換成具名實體辨識(NER)或模型化的內容分類器那一類,而那一層目前還沒做。

好消息是,這道關跟 Day 14、Day 15 那套抽換框架是接通的:本地 regex 規則只是其中一檔,真要補上語意級偵測,換的是這顆零件,上層流程不動。它是 PoC 階段務實的起點,但別把「八類遮乾淨」當成「個資都遮乾淨了」——沒形狀的那一大類,現在是漏的。

把這道關的價值歸結起來:個資從入口就被遮掉,於是不管是傳給模型還是寫進日誌,原始的 123456 自始至終沒有落地。小林全程無感,但他的員編一次都沒離開過 Portal 的入口。

明天 Day 18,我們把鏡頭拉遠——這裡的注入兩攔、PII 兩遮,加上稽核寫入前的保底遮罩,合起來其實是同一個更大的設計:縱深防禦,當任何單一層被關掉或漏掉時,為什麼系統還守得住。


上一篇
Day 16|入境守門壹:誰敢亂問問題
下一篇
Day 18|縱深防禦
系列文
轉生到全端工程師沒多久就要負責公司的大平台??18
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言