技術實戰

Webhook 簽章除錯實錄:官方文件不會告訴你的三個坑

串接客服對話平台的 Webhook,把對話事件收回自有資料庫——聽起來是一天的工作,實際上文件沒寫清楚的簽章規則、被編碼兩次的 payload、還有壞資料的補救機制,每一個都是坑。真實除錯紀錄。

Kai Wu

凱吳科技 負責人
發布於 2026年7月17日
5 分鐘閱讀
Webhook 簽章除錯實錄:官方文件不會告訴你的三個坑

先交代為什麼要做這件事。我們在幫一個醫療產業的廣告代理商打通「廣告 → 聊天 → 預約 → 成交」的歸因鏈:廣告被點擊之後,客人進到聊天室,從這一刻起廣告平台就看不見了。要知道哪支廣告真的帶來成交,就得把客服對話平台的事件即時收回自有資料庫,跟廣告點擊、預約、成交資料串成一條鏈。

對話平台是 SaleSmartly,提供 Open API 和 Webhook。文件看起來齊全,評估時想著「串個 webhook,一天的事」。

然後我們花了兩天在三個文件沒寫清楚的地方。這篇把它們記下來——不是抱怨,是因為這三個坑在各家平台的 webhook 串接裡反覆出現,值得變成 checklist。

坑一:簽章驗不過——body 到底哪些欄位有進簽名?

Webhook 的基本安全機制是簽章:平台用共享密鑰對 payload 算一個雜湊(這家用 MD5),你收到後用同樣規則重算,對得上才處理。概念簡單,魔鬼在「同樣規則」四個字。

文件告訴你簽章演算法,但沒有把「body 的哪些欄位、用什麼順序、什麼格式進入簽名」寫清楚。欄位要不要排序?空值算不算?巢狀物件怎麼序列化?任何一個猜錯,算出來的簽章就是對不上——而錯誤訊息只有一種:驗證失敗。

我們的解法是 A/B 校準法:構造多組只差一個變因的請求,觀察簽章是否變化,逆向推回簽名規則。

請求 A:欄位 x = 1,其餘固定  →  簽章 S1
請求 B:欄位 x = 2,其餘固定  →  簽章 S2

S1 不等於 S2  →  欄位 x 有參與簽名
S1 等於 S2    →  欄位 x 沒參與簽名

一個欄位一個欄位校準,把「文件沒寫的簽名規則」實測出來。笨方法,但它終結猜測——比對著文件反覆試錯快得多。

坑二:payload 被編碼了兩次

簽章通了,資料開始進來,接著出現兩個看似無關的症狀:部分事件解析失敗(parse_error),以及不同事件被算成同一把 event key、互相覆蓋(key 碰撞)。

追下去發現root cause 是同一個:double-encoded JSON。有些 payload 送來的不是 JSON 物件,而是「被字串化兩次的 JSON」——你解開一層,得到的還是一個字串,得再解一層才是真正的資料。

只解一層的下游邏輯拿到的是一坨字串:從裡面抽事件識別欄位抽不到,就退回預設值——於是不同事件撞成同一把 key;試著當物件處理,就直接 parse_error。

處理方式是在入口做防禦性解碼:解完一層檢查型別,拿到的還是字串就再解一層。醜,但外部系統的行為不是你能控制的,入口層的職責就是把混亂擋在門外

坑三:驗不過、解不開的資料,往哪裡去?

前兩個坑修好之後,還剩一個問題:修好之前那幾天進來的壞資料怎麼辦?

如果你的 webhook handler 在驗證或解析失敗時直接丟棄請求,那答案是:沒救了,事件永遠消失。歸因鏈斷在這裡——某幾天的對話對不到廣告,報表出現一個永遠解釋不了的洞。

我們的設計是先留存、再處理:原始 payload 一律先落地保存,解析和入庫是後面的步驟。所以 parser 修好之後,跑一輪 replay——把當初失敗的原始資料重新灌回處理流程,補回缺口。這要求整條處理管線是可重複執行的(idempotent):同一筆事件跑兩次,結果不會重複也不會寫壞。

Webhook 串接的成敗,不在 happy path 通不通,在你怎麼對待每一筆「進不來」的資料。

通用教訓:把 webhook 當資安邊界設計

整理成四條,下次串任何平台都適用:

  1. 簽章規則不清楚就實測,A/B 校準比讀十遍文件有效。
  2. 入口做防禦性解析,外部系統送什麼格式你無法保證。
  3. 原始 payload 先落地,處理失敗要能 replay,管線要 idempotent。
  4. 驗簽失敗要記錄而不是靜默丟棄——它既可能是攻擊,也可能是你的規則錯了,兩種都需要被看見。

這條 webhook 管線是整套廣告歸因系統的其中一段。如果你的公司也在跟「數據進不來、對不上」奮戰——不管是廣告、客服還是內部系統——歡迎聊聊。

預約 30 分鐘免費流程診斷 →

文章標籤

#Webhook#API 串接#簽章驗證#SaleSmartly#廣告歸因

相關文章

探索更多 AI 自動化與流程改造的實戰內容