iT邦幫忙

2026 iThome 鐵人賽

DAY 19
0

昨天講到掃描:掃什麼、用什麼工具、結果怎麼分成 Pass / Review / Block。

但自動掃描通過,不代表所有東西都可以直接上架。

因為 Scanner 可以幫我們找問題、套規則,但有些事情不是 Scanner 可以替企業決定的。

所以今天進入 Phase 6:送審與人工審核。

Phase 6:送審與審核流程

原本開發計畫只有寫審核但展開後裡面大概是這些:

→ 建立送審功能
→ 定義審核狀態
→ 建立審核畫面
→ 控制誰具有審核權限
→ 實作通過
→ 實作退回
→ 實作退回後修改
→ 實作重新送審
→ 防止申請人自己審核自己的案件
→ 防止使用者直接修改狀態跳過審核
→ 建立多階層審核流程

乍看之下好像就是做幾顆「送審」、「核准」、「退回」按鈕。

但真的開始拆,就會發現這一段真正麻煩的不是按鈕怎麼做,而是:

誰可以決定?什麼情況可以決定?決定之後可以往哪裡走?

為什麼掃過了還要人審?

Scanner 能判斷的是「有沒有命中規則」。

它看得出這個 HTML 從外部 CDN 載入東西、程式裡用了 innerHTML、有哪些外部連線,也可以依照我們昨天定義的 Policy 判斷哪些項目需要 Block、哪些需要 Review。

但它一定不知道: 「這個工具到底是拿來幹嘛的?」

同樣是一個外部 API,可能是業務上必要的服務,也可能根本不應該連;同樣使用 localStorage,裡面可能只放介面設定,也可能有人拿來存不該放在瀏覽器裡的資料。

例如 Scanner 的結果是 Review:使用了一個第三方 CDN,也有一段 innerHTML

這兩件事情本身不代表一定有漏洞,但如果這只是一個算加班費的小工具,跟一個會處理個人資料的表單,我要確認的事情顯然不會一樣。

所以 Scanner 可以告訴我:

「我發現了什麼。」

但有些事情還是需要人根據實際用途回答:

「在這個使用情境下,這件事情可不可以接受?」

而且還有責任的問題。前面講過,真的出事時,我們必須能回頭知道:「當初是依據什麼資訊、由誰做出放行決定?」

Scanner 可以提供判斷依據,但最後的決策與責任,不能全部丟給 Scanner。

為什麼掃過了還要人審

人工審核不是再把程式全部看一次

講到人工審核,很容易讓人想到另一個極端:

「所以 Scanner 掃完,最後還是要找一個人把所有程式碼重新看一次?」

如果是這樣,那前面做那麼多自動化也沒什麼意義。

我的想法不是讓人工重新做一次 Scanner 做過的事情,而是讓 Scanner 先把能自動處理的東西整理好。

Malware、Secret、SAST、SCA、SBOM、外部連線、Policy Check,這些先跑完,再把真正需要人判斷的 Review Finding 整理出來。

審查員看到的不應該只是一包 ZIP,而是一份已經整理好的資料,例如:

  • 這個工具是誰申請的、用途是什麼
  • 預計給哪些人使用
  • 會處理什麼資料
  • Scanner 跑了哪些檢查
  • 有哪些 Finding
  • 哪些項目已經 Block
  • 哪些項目需要 Review
  • 會連到哪些外部 Domain
  • 使用哪些第三方元件

甚至 Scanner 如果發現 innerHTML,可以直接告訴審查者:

哪個檔案、哪個位置、發現什麼、為什麼值得注意。

審查的人真正要做的,是針對這些資訊判斷:

「這個情境可不可以接受?」

我要減少的是人工找資料、整理資料的時間,而不是把真正需要負責的判斷一起拿掉。

審核流程是一台狀態機,不是幾個按鈕

再來是我覺得很容易被忽略的地方。

審核流程不是做三顆: 送審|核准|退回 就結束了。

它其實比較像一台 State Machine(狀態機)。

概念上可能是:草稿 → 送審 → 掃描中 → 待審 → 通過/退回 → 後續流程

如果被退回,修改之後又會重新進入:退回 → 修改 → 重新掃描 → 重新送審 → 待審

每個狀態可以轉去哪裡、誰有資格讓它轉、轉移的時候要留下什麼紀錄,都要先定義清楚。

而且這些規則一定要由後端控制。

假設前端送出:

status=approved

後端不能看到 approved 就真的把資料庫改成核准。

它應該先確認:

現在是不是可以被核准的狀態?

這個使用者有沒有審核權限?

這個人是不是這件案子的申請人?

前面的必要流程是不是都已經完成?

全部符合,才允許狀態轉移。

不然使用者只要自己呼叫 API,把 status 改成 approved,整套審核流程就只剩畫面上的幾顆按鈕。

這種問題跟 SQL Injection、XSS 不太一樣。

功能可能全部都正常,只是有人用了一個原本不應該允許的順序,把正常流程繞過去了。

這就是 Business Logic / Workflow Abuse 這類問題。

審核流程

階層跟著風險走

前面 Day 10 已經談過風險分級,所以到了這裡,我不會讓所有工具全部走完全相同的審核流程。

不然一個完全不碰資料的小計算機,跟一個會處理機敏資料的工具走一樣的流程,最後大家只會覺得這個平台很麻煩。

所以我的想法是讓審核階層跟著風險走。

低風險:使用者 → 審查員

例如純前端、不碰敏感資料、使用範圍很小的工具,由審查員確認後進入下一階段。

中風險:使用者 → 單位主管知會/確認 → 審查員

如果開始碰內部資料、跨單位使用,除了技術審查之外,原單位主管也應該知道這個工具的存在與用途。

高風險:使用者 → 單位主管 → 資訊單位審核 → 資訊單位主管核准

如果涉及個資、機敏資料或較高影響範圍,就增加必要的審核層級。

實際要分幾級、每一級由誰審,當然還是要依企業自己的治理制度決定。

但有一個原則應該要先定下來:

使用者可以提供風險判斷需要的資料,但不能自己決定最後的風險等級。

使用者可以告訴平台:「我的工具會不會處理資料、使用範圍多大、會不會連外、給哪些人使用。」

再搭配前面的掃描結果與平台規則決定最後走哪一條審核流程。

不然如果風險等級直接讓使用者自己選,我猜最後大家都會很有默契:

「 低風險,謝謝 」

階層跟著風險走

職責分離

接下來還有一個很重要的問題: 誰可以審?

最基本的規則就是: 申請人不能審自己的案子。

不然整套流程會變成: 我做的 → 我送的 → 我審的 → 我核准的。

看起來每一關都有走,實際上還是同一個人在做決定。

這就是 Separation of Duties(職責分離) 的概念,也是 ISO 27001 控制措施中會關注的方向。目的不是為了多設一關,而是避免同一個人同時具有申請與核准的權力。

所以不能只做: 「有 Reviewer Role → 顯示核准按鈕」

後端在真正執行核准時,還要再確認: Reviewer ≠ Submitter

這種規則我會直接寫進專案需求與開發規則裡,而不是期待 AI 每次都會主動想到。

因為 AI 很可能把「Reviewer 可以核准案件」這個功能做得完全正確,但如果需求沒有講清楚,它未必會替我補上一條:

「Reviewer 不能核准自己送的案件。」

這也是我一直強調需求跟規則要先寫清楚的原因。

核准的是這一版,不是永久通過

接下來是版本問題。

假設審查員今天看到的是 Version A,Scanner 掃的也是 Version A,最後審查員核准 Version A。

那最後進入後續流程的,就應該是 Version A。

不能核准完之後,申請人偷偷把 JavaScript 換掉,畫面還繼續顯示:

「已核准。」

所以只要內容修改,就應該產生新的版本。

例如: Version A → 掃描 → 審核 → 通過

後來修改內容: Version B → 重新掃描 → 重新審核

Version A 的掃描與核准結果,不能直接套到 Version B。

系統實作上,可以利用版本 ID 搭配 SHA-256 Hash,把掃描結果與核准紀錄綁定到實際檔案內容。後續真正使用這個版本時,也能確認目前的 Artifact 跟當初被掃描、被核准的是同一份內容。

這裡真正重要的其實只有一句: 通過的是「這一版」,不是這個工具從此取得永久通行證。

審核紀錄不能被偷偷改掉

既然開始有人做決定,就一定會產生紀錄。

例如:

誰送審的?
什麼時候送審?
送的是哪一版?
當時 Scanner 的結果是什麼?
有哪些 Review Finding?
誰審核?
什麼時間審核?
最後是通過還是退回?
審查員留下什麼意見?

這些東西都應該被保留下來。

而且原始的審核紀錄不能被直接覆寫。

假設審查員昨天寫:

「確認用途後,同意使用。」

今天發現自己寫錯了,不應該直接把昨天那筆紀錄 UPDATE 成另外一句,讓原本發生過的事情消失。

比較合理的方式是再新增一筆更正或補充紀錄,讓前後變化都留得下來。

因為真的發生問題時,我想知道的不是: 「系統現在顯示什麼?」

而是: 「當時到底發生了什麼?」

這些紀錄之後也會成為整個平台 Audit Trail 的一部分。

Phase 6 做完就可以來測試

跟前面一樣,功能做完之後,我不會只測正常流程:

送審 → 審核 → 通過

這條一定可以跑。

我反而會開始故意做一些不應該成功的事情:

  • 能不能跳過主管,直接進下一關?
  • 申請人能不能自己審自己的案件?
  • 沒有審核權限的人,直接呼叫核准 API 會怎樣?
  • 能不能自己修改 status 變成 Approved?
  • 被退回之後,能不能正常修改再重新送審?
  • Version A 核准後換成 Version B,原本的核准還在不在?
  • 使用者能不能把自己的風險等級改低?
  • 已經核准的紀錄能不能被直接修改或刪除?

因為這一階段真正要測的,已經不只是: 「按鈕按下去有沒有反應?」

而是: 「不該走的路,到底走不走得通?」

這裡主要想避免的就是 Broken Access Control、Workflow Bypass、Business Logic Abuse,以及審核狀態與實際版本對不起來等問題。

小結

Phase 5 的 Scanner 回答的是: 「這個檔案有沒有命中我們設定的規則?」

Phase 6 的人工審核回答的則是: 「根據這些資訊與實際使用情境,我們要不要允許它繼續往下走?」

所以人工審核不是把 Scanner 做過的事情重新做一次。

Scanner 負責把 Malware、Secret、SAST、SCA、外部連線、Policy Check 等資訊整理出來;人負責處理那些需要情境、權限、用途與風險判斷的事情。

而審核流程本身,也不是幾顆「送審、核准、退回」按鈕。

它背後其實還有:

狀態、風險分級、審核階層、職責分離、版本綁定、Audit Trail。

這些規則都不能只期待 AI 自己補齊,是要在需求與規則裡先定義清楚,再讓 AI 幫我把它實作出來。
做到這裡,這個工具已經走完:

上傳 → 自動掃描 → 人工審核

但「審核通過」仍然不代表可以直接丟進正式環境。

因為到目前為止,我們花了很多時間回答:

「它能不能被允許?」

還有另一個問題沒有真正回答:

「通過之後,使用者要在哪裡看到它?它跑起來之後,會不會影響到平台本身?」


上一篇
Day 18|六個階段怎麼套進 Vibe Coding -6
系列文
只要有心,人人都是食神—做得出來,就能端給別人吃嗎?19
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言