API 驗證機制怎麼設計?從金流串接學到的三層防護實戰

教學指南

AI 文章延伸

AI 幫你讀這篇文章

選擇平台後可直接帶入閱讀脈絡,快速整理重點、補齊盲點,並延伸到同站相關文章。

我們最近在做一個專案,兩個網站之間需要透過 REST API 互相溝通——A 站負責下指令,B 站負責執行。兩邊各自獨立部署,靠 API 串起來。

問題來了:API 端點是公開的。只要有人知道網址格式,就能嘗試呼叫。如果驗證機制不夠嚴謹,別人拿到 API Key 就能對你的網站做任何事——讀取資料、修改設定、觸發操作。

這篇分享我們怎麼設計這套 API 驗證機制,以及背後的思考脈絡。

只有 API Key 不夠嗎?

最直覺的做法是發一組 API Key,每次請求帶上這組 Key,後端驗證通過就放行。很多服務都這樣做,簡單有效。

但光靠 API Key 有幾個風險:

  • Key 外洩就全完了。 一旦 Key 被截取,攻擊者可以無限次使用,直到你發現並撤銷。
  • 中間人攻擊。 如果有人在傳輸過程中攔截到請求,他拿到的不只是 Key,還有完整的請求內容,可以原封不動地重送。
  • 重送攻擊(Replay Attack)。 即使用了 HTTPS,攻擊者如果在任何環節拿到一個合法請求的副本,就能反覆重送這個請求來執行操作。

我們需要的是:即使有人拿到了 API Key,甚至截取了一個完整的合法請求,他也沒辦法拿這些東西來搞事。

從 WooCommerce 金流學到的做法

這個設計其實不是我們原創。靈感來自之前串接 WooCommerce 金流的經驗。

做過金流串接的人應該都知道,不管是綠界、藍新還是其他台灣的金流服務商,他們在處理付款通知(通常叫 callback 或 webhook)時,都不會只用一組 API Key 來驗證。他們的做法通常是:把請求裡的關鍵欄位串在一起,加上一組只有雙方知道的密鑰,算出一個雜湊值(Hash),然後把這個 Hash 附在請求裡一起送過來。

收到請求的那一方,用同樣的欄位、同樣的密鑰、同樣的算法重新算一次。兩邊的 Hash 一致,才代表這個請求是真的。

這個機制叫做「請求簽章(Request Signature)」。金流業者用它來保護每一筆交易通知的真實性。我們把同樣的概念套用在兩個網站之間的 API 通訊上。

三層驗證設計

最後我們設計了三層驗證,每一層解決不同的問題。

第一層:API Key

這是基本的身份識別。A 站和 B 站之間透過一組 Key 配對——管理員在 B 站產生一組 64 字元的隨機金鑰,複製貼到 A 站完成配對。B 站只儲存 Key 的 Hash 值,不存明文。

這一層解決的是「你是誰」的問題。沒有 Key,連門都進不了。

第二層:SHA-256 簽章

光有 Key 不夠。每次請求,A 站會把三個東西串在一起:

目標網站網址 | API Key | 當前時間戳

然後用 SHA-256 算出一個 Hash,放在請求的 Header 裡送過來。

B 站收到請求後,用同樣的三個值重新算一次 Hash。兩邊結果一致,才代表這個請求沒有被竄改過,而且確實來自知道 Key 的那一方。

為什麼要把網站網址也加進去?因為同一組 Key 如果能用在不同網站上就麻煩了。把網址綁進簽章裡,就算有人拿到 Key,也只能對特定網站發請求。

第三層:時間戳驗證

簽章裡包含了時間戳,但我們還額外做了一件事:檢查這個時間戳是不是太舊了。

規則很簡單——時間戳和伺服器當前時間的差異超過 5 分鐘,直接拒絕。

這一層專門對付重送攻擊。假設有人截取了一個合法請求,他拿到的 Hash 裡面包含了當時的時間戳。等他試圖重送這個請求的時候,時間戳已經過期了。他沒辦法修改時間戳,因為改了時間戳,Hash 就對不上。他也沒辦法重新算 Hash,因為他不知道 API Key。

5 分鐘的容許範圍是考慮到兩台伺服器之間可能有時間差,太短會誤判,太長又失去防護效果。金流服務商的做法也差不多是這個範圍。

實際的請求長什麼樣子

A 站呼叫 B 站 API 時,會帶三個自訂 Header:

  • API Key:用來做第一層身份驗證
  • Hash:用網站網址、Key、時間戳算出來的 SHA-256 簽章
  • Timestamp:發送請求的 Unix 時間戳

B 站收到請求後的驗證順序:

  1. 先看有沒有帶 API Key,沒有就直接擋掉
  2. 驗證 API Key 是否正確
  3. 檢查時間戳是否在 5 分鐘以內
  4. 用同樣的材料算一次 Hash,比對是否一致

四關都過了,才放行。任何一關失敗,都會回傳對應的錯誤碼,讓呼叫方知道是哪裡出了問題。

Key 的管理方式

安全機制設計完了,還有一個問題:管理員怎麼管理這組 Key?

我們的做法是在 B 站的後台加一個管理介面。管理員點「產生」,系統生成一組 Key,完整顯示一次。管理員複製下來貼到 A 站,之後這組 Key 就再也不會以明文出現了——後台只會顯示前 8 碼加後 4 碼的遮罩版本。

如果 Key 外洩了,管理員可以「重新產生」,舊的 Key 立刻失效,A 站需要重新配對。也可以直接「撤銷」,切斷所有 API 連線。

這個設計參考了 GitHub Personal Access Token 的做法——產生時看一次,之後只能看到局部。原因很實際:如果後台隨時能看到完整 Key,那任何能進後台的人都能拿到 Key。只顯示一次,能降低 Key 被二次外洩的風險。

這個設計不是萬無一失

幾個我們知道的限制:

依賴 HTTPS。 簽章機制保護的是請求的真實性和時效性,不是機密性。如果不用 HTTPS,所有 Header 都是明文傳輸,簽章的意義就大打折扣。不過現在幾乎所有正式環境都有 SSL 了,這個前提條件算合理。

時間同步。 兩台伺服器的時間如果差太多,合法請求也會被拒絕。5 分鐘的容許範圍在大部分情境下夠用,但如果遇到時間嚴重漂移的伺服器,可能需要排查。

Key 管理靠人。 系統能做的是產生夠強的隨機 Key、安全儲存、提供撤銷機制。但管理員把 Key 貼在 Slack 公開頻道或存在記事本裡,系統也管不了。

回頭看這個設計

整個驗證機制其實沒有用到什麼高深的技術。SHA-256 是標準的雜湊算法,時間戳驗證是基本的防重送手段,API Key 更是最常見的身份識別方式。真正的關鍵是把這三層組合在一起,讓每一層各自負責不同的安全面向。

金流業者用這套做法保護每一筆交易通知,已經經過多年的實戰驗證。我們只是把同樣的邏輯搬到兩個網站之間的 API 通訊上。根據我們的經驗,這個組合在「安全性」和「實作複雜度」之間取得了不錯的平衡——不需要導入 OAuth 或 JWT 這類重量級框架,用幾個簡單的元件就能達到足夠的防護等級。

如果你也在做類似的雙站 API 通訊,不妨參考金流串接的驗證模式。那些被大量交易驗證過的設計,通常比自己從頭發明的方案更可靠。

作品案例

看看我們打造的產品與專案。從 WordPress 外掛到 AI 客服方案,每一個作品都是實戰經驗的累積。

瀏覽作品案例

服務項目

WordPress 開發、WooCommerce 電商、LINE 整合、AI 解決方案,依據你的需求提供最適合的技術服務。

瀏覽服務項目

Contact

聯絡我們

若你有任何技術需求、專案諮詢或合作想法,歡迎隨時與我們聊聊(首次諮詢免費)。

  • 想打造 WordPress 網站或 WooCommerce 電商
  • 需要 LINE 整合或 AI 功能導入
  • 有產品點子想找技術合夥人一起實現
  • 既有網站需要改版升級或效能優化
  • 尋找長期穩定的技術顧問合作夥伴