iT邦幫忙

2026 iThome 鐵人賽

DAY 20
1

新單元第一天。前面寫的是日常運轉,這個單元寫系統怎麼壞。先從一個我寫進規則、也寫進程式碼的態度開始。

允許清單的另一面

我處理敏感資料的規則,視覺上叫做分級:資料分 public、internal、sensitive、等級再高的拒絕外送。聽起來就是要「把每一份資料歸類,照等級放行」。

真正把這套規則立起來的,是反方向的一句話:分級做得再細,只要有一個「分不出來」的狀態被硬放行,整個系統就白做了。所以我的規則裡最重的一條不是「X 可以進 public」,是:無法確定等級的,一律不准出去。

具體進到程式時,我有個真實的案例。有一個設置檔要讀 privacy 等級,當時示意占主流的解析器是現成的 YAML。我沒有用它,自己寫了一個嚴格的版本。原因是 YAML 有一個語法特性:同一個 key 出現第二次時,後面的值覆蓋前面的。放在我的場景,這一行的代價是這樣發生的:

privacy: student-private   # 我標的
privacy: public            # 任何來源的這一行會贏

後補的那行不會有任何錯誤訊息,最後讀到的等級是 public。等級的基本性質是「只能維持或提高,不能降低」,而這個 parser 天生就會執行降級,而且全程無聲。

labeled 未定就分兩種:拒絕 vs 出錯?

自己寫的 parser,第一個決策是所有我不認得的形状──縮排不對、重複 key、邊界空白、大小写錯──的命運。可以嘗試「善意解讀」或判為不合法;或全部走一種中性的「無法確定」輸出。我的取捨是後兩種合一:無法確定就是拒絕,没有任何「先放行、事後再查」的路徑。這不友善,但我喜歡它的代價結構:錯誤的方向永遠是往外(被拒的人在明亮處),不是往內(被放行的東西在暗處)。

同一個態度在第二個地方出場。我有一個「封印」機制:一筆資料被某個程序核准後,會帶著簽章,之後不能被改。第一版的封印只粘在資料上,不粘欄位;測試的時候我一行 dataclasses.replace() 就帶著未過檢的舊封印,把核過的欄位偷改成另一個等級。改法是讓封印綁定它核准的具體值(路徑+等級),欄位一變封印就斷。这个修法的原則和 parser 相同:對「確定」的要求,要比對「方便」的要求高。

讀者可以自己跑的一個例子

這套作為態其實就是這個系列送出前的閘門:scripts/privacy-check.sh。它有八類規則,其中一類是私有網段 IP、一類是絕對路徑。認得的我沒有例外,不確定的照樣禁。它沒有辦法擋語意層面的問題──這個弱點我到下一個單元才會正面處理──但在它的適用範圍內,fail closed 保持得很乾淨。

它也有需要被測試的地方。假的守衛比沒有守衛更危險,它降低人的警覺、也給人虛假的安全感。跟 training 一樣,我為這支腳本做過反向的測試:故意放入該被擋的內容,確認它真的會擋。守衛先要被證明有牙,才能被信任。

還沒解決的

拒絕要附理由,否則下一次崩潰會因為「它又拒了,我一直進不去」而開始抱怨我自己的守衛。穩定錯誤碼的設計我還在打磨,兩個版本之間 code 變動時,錯誤碼也會跟著動。

明天

態度講完了,接下來五天寫真實的壞法。第一個故事是逾時:一個我觀察了很久的逾時,我猜的兩個根因,全錯了。


上一篇
19 stale 不等於死掉:十二小時的人工出口
下一篇
21 逾時的兩個根因,我都猜錯了
系列文
國小教師的 Agent OS:30 天讓 AI 的「做完了」有證據 共 21 篇
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言