UCP 藏了第四招:一組簽名,同時通過自己人跟 Web Bot Auth 兩種驗證
掃完 Cart、Catalog、Order 這些格式相似的規格後,Signatures 這頁讓我停下來:UCP 藏了一招,讓同一組簽名同時通過自己人跟 Web Bot Auth 兩種驗證。
三篇寫完(上一篇是UCP 藏了一個「找門市」的能力),我照上一篇的承諾,快速掃了一輪剩下的頁面:Cart、Catalog、Order、Payment Handlers、Reference。
老實說,大部分都是標準的 CRUD 規格文件,跟前面幾篇比起來沒什麼新意,我不打算硬拆成一篇一篇。但掃到 Signatures(訊息簽章)這頁的時候,我停下來了。
簽章要防的四件事
UCP 用一個叫 RFC 9421(HTTP Message Signatures,HTTP 訊息簽章)的規範替每一則訊息簽名,官方講得很白話,列了四種要防的攻擊:
- 冒充:攻擊者發訊息假裝自己是合法的一方
- 竄改:訊息內容在傳輸過程被修改
- 重放攻擊:把攔截到的訊息重新送到不同的地方或不同的時間點
- 方法/端點混淆:把簽過名的內容套到不同的 HTTP 方法或路徑上重放
這四條聽起來像是資安課本的標準清單,但接下來的設計,才是我想寫這篇的原因。
一組簽名,同時滿足自己人跟另一套標準的驗證
業界還有另一個獨立的標準,叫 Web Bot Auth(WBA),目的是讓網站能驗證「來訪問我的這個機器人或 agent,到底是誰」。這是一個獨立的 IETF 草案,跟 UCP 是兩套不同的東西。
UCP 允許整合者把自己的簽名做成一種「雙受眾」格式:一把金鑰、一次簽名操作、線路上只有一組簽章,同時被 UCP 驗證方跟 WBA 驗證方接受。官方原文一句話講完:「One signature on the wire, two audiences.」
具體怎麼做到?簽署者要多做幾件事:額外帶一個 Signature-Agent 的標頭(跟原本的 UCP-Agent 並存,不是取代)、把這個欄位也納入簽章覆蓋範圍、把金鑰 ID 設成這把金鑰的 SHA-256 指紋、帶上效期參數(最多 24 小時)、最好再加一個隨機亂數防重放,最後貼一個 tag="web-bot-auth" 的標籤讓 WBA 那邊認得出來。
想像一下,你原本要進兩個不同的場館,各自要出示一張證件,現在有一張證件同時符合兩邊的驗證標準,安檢口只要掃一次。
有意思的是,這個互通是單向的。一個 UCP 簽署者的簽名可以拿去騙過(不是我說,官方用詞就是滿足)WBA 驗證方,因為 UCP 本來要求覆蓋的欄位範圍就比 WBA 的最低門檻更完整。但反過來不成立:一個只滿足 WBA 最低要求的簽名,套進 UCP 這邊會直接被拒絕,因為 UCP 檢查的覆蓋範圍更嚴格。
以前你要嘛做兩套簽名邏輯應付兩套系統,要嘛乾脆只選一邊放棄另一邊的相容性。現在有辦法一次到位,前提是你選對演算法、多帶幾個欄位。

重放攻擊,UCP 刻意不在簽章層處理
這裡有一個我覺得很清楚的架構決定。UCP 把工作拆成兩層:
簽章負責「這是誰、內容有沒有被改」;重放攻擊防護,官方刻意放到商業層的冪等鍵(idempotency key)去處理,不是簽章本身的責任。
運作邏輯是這樣:狀態變更的操作要帶一組冪等鍵,這組鍵本身也被納入簽章覆蓋範圍,攻擊者不能在不弄壞簽章的前提下偷改這組鍵。重複的請求會直接拿到快取的回應,不會被重新執行一次。
冪等鍵的要求也寫得很具體:至少 128 bits 的亂數強度(例如一組 UUID v4)、伺服器至少要保存 24 小時、內容相同的重複請求回快取結果、內容不同但鍵相同就直接拒絕(回 409 Conflict)、如果儲存這組鍵本身失敗了,系統要選擇「寧可拒絕請求」而不是照樣放行。
重點是什麼? 只要你改了請求內容,比如換了付款方式、改了收件地址,就必須生一把全新的冪等鍵,不能沿用舊的去矇混過關。這條規則把「防止重複扣款」這件事做得比一般想像中更嚴謹。

一個真的會讓工程團隊踩到的坑
官方用粗體特別警告了一件事:中間的代理伺服器、API gateway,絕對不能重新序列化 JSON body。
原因很直接:簽章綁定的是原始的位元組,不是重新排版過的 JSON。哪怕只是欄位順序被調整、多了一個空白字元,簽章驗證都會直接失敗。
我自己這幾年看過不少團隊在導入新協定的時候,中間會多加一層 API gateway 做流量控管或格式轉換,這一類架構很容易在不知情的狀況下把 JSON body 重新序列化一次。如果你的團隊以後要接 UCP,這條規則值得貼在牆上提醒自己。
金鑰怎麼換,官方寫得很具體
輪替流程是四步:先把新金鑰發布到清單裡跟舊金鑰並存,開始用新金鑰簽名,給一段至少 7 天的寬限期讓舊金鑰的簽名還能被接受,最後才把舊金鑰從清單移除。
官方建議每 90 天輪替一次。如果金鑰真的外洩了,處理順序也寫清楚:立刻把外洩的金鑰從清單移除,發一把全新 ID 的金鑰,拒絕所有用舊金鑰簽過的訊息。
這幾條合起來看,你會發現這份規格不只是定義資料格式,連「營運上這件事該怎麼做」都幫你想好了流程。
哪些情境一定要簽章
Webhook 通知一定要簽章,因為收件的一方沒有別的辦法確認這則「商家主動推過來」的訊息是不是真的。付款授權、結帳完成的回應,官方建議簽章。購物車操作、商品目錄查詢、錯誤回應,簽章是選配的,因為這些場景本身價值低或者是唯讀操作。
這件事對你來說,該做什麼?
如果你是做技術、做產品的人:
► 如果你的團隊未來要接 UCP,先確認架構裡有沒有 API gateway 或反向代理,去查它會不會重新序列化 JSON body,這個坑現在先查比上線後除錯便宜很多。
► 去讀 ucp.dev 的 Signatures 規格全文,「簽章管身份與完整性、冪等鍵管重放防護」這個分層思路,值得直接搬到你自己設計的 API 安全機制裡。
如果你是關注 SEO、關注 AI 爬蟲議題的人:
► Web Bot Auth 這類讓網站驗證機器人身份的機制,跟這一兩年「AI 該不該被允許抓你的內容、抓了要不要付費」的產業討論是同一條線上的事情,UCP 選擇跟它相容而不是自己另起爐灶,這個選擇本身就是一個值得持續關注的訊號。
收尾:三篇該收,第四篇值得寫,界線是「有沒有新東西」
我這幾天寫的四篇 UCP,回頭看是一條很清楚的脈絡:第一篇測介面,第二篇讀治理,第三篇挖出一個沒人提過的能力,這一篇挖到一個真正巧妙的技術設計。
前面被問「內容真的夠完整嗎」,我後來想通一件事:完整不是把每一頁都讀過一遍,是每一次你多讀一頁,都要老實問自己「這裡有沒有真的值得告訴讀者的東西」。有就寫,沒有就跳過,不是為了湊字數硬拆成連載。
這年頭就是查證、查證、再查證,但查證的終點不是讀完所有文件,是讀到你能對讀者交代清楚為止。
協作聲明與免責
這篇文章由王董與 AI 一起整理製作完成。文中引用的第三方資料、研究或工具都會標註來源名稱;若原始出處有公開連結,會以 [來源名稱](URL) 形式附上,方便你進一步查找。若文中內容與原始出處有任何出入,請以原文為準。
內容僅供參考與學習交流,不構成任何專業、商業或投資建議,請依自身情況判斷並自行承擔行動風險。文中提及的工具功能、數據與平台政策可能隨時間異動,請以各官方最新公告為準。