本文收錄於 Github.com/niumoo/JavaNotes,Java 系列文件,資料結構與演算法!
本文收錄於網站:https://www.wdbyte.com/,我的公眾號:程式猿阿朗
什麼是 WebHook
WebHook 直譯是網路鉤子,可以把 WebHook 看做一種通知方式,只要發生關注的事件,就會傳送通知到我們指定的 Web 服務。使用 WebHook 可以讓我們在關注的事件發生時收到通知,而不是不斷輪訓 API 確認事件是否發生,
GitHub 允許我們配置 WebHook ,它允許我們配置某個倉庫發生某個事件時,通知指定的外部服務。比如當指定倉庫有提交程式碼時,GitHub 將向我們配置的 API 傳送 POST 請求。以此可以實現相應的自動化操作,如持續整合 CI,請求程式碼稽核,拉取新程式碼編譯打包部署等。
發揮想象力,GitHub 的 WebHook 結合 GitHub Action 可以做很多事情,文末有具體例子。
這篇文章介紹 GitHub Web Hooks 的使用。
WebHook 配置
訪問
訪問 GitHub 倉庫的 Webhooks 設定頁面,開啟倉庫的 Settings
配置頁面,點選 Webhook
Tab 頁。
也可以直接訪問連結:https://github.com/使用者/倉庫/settings/hooks
配置
點選 Add webhook
按鈕。
配置完成後,點選 Add webhook
,GitHub 會傳送一個 POST 請求到配置的 web 服務用於驗證是否正常。Web Hook 的事件會在請求頭 X-GitHub-Event
中進行標識。
如上面說到的 ping
,會在請求頭中進行標識:X-GitHub-Event: ping
。’
一些說明:
- Payload URL:此處填寫你的 Web 服務地址,最好已經存在,這樣
ping
事件才能正常響應。 - Secret:安全金鑰,用於對請求體進行雜湊計算,用於驗證是否為 GitHub 傳送。後面部分會詳細介紹紹。
- SSL Verification:是否啟用 SSL 驗證,如果你的 Web 服務啟用了 HTTPS,這裡應該選擇啟用,也建議啟用。
- Just the push event:只訂閱倉庫 push 事件。
Ping 測試
點選 Add webhook
後傳送一個請求到配置的 Web 服務,下面是一個真實的 ping
事件請求頭資訊。
Request URL: https://www.wdbyte.com/api/github/webhook
Request method: POST
Accept: */*
Content-Type: application/x-www-form-urlencoded
User-Agent: GitHub-Hookshot/eb2eabb
X-GitHub-Delivery: 10957020-e918-11ee-8a3e-e0754488dbc
X-GitHub-Event: ping
X-GitHub-Hook-ID: 468323437
X-GitHub-Hook-Installation-Target-ID: 33701056
X-GitHub-Hook-Installation-Target-Type: repository
X-Hub-Signature: sha1=1877dfa1d840bdd5583af33718cea722d825ed7
X-Hub-Signature-256: sha256=addaf81ed2f5795f06ba096b1c863b00188d3444367b5125d2036e17ca324e3
WebHook 訊息驗證
因為配置的 Web 服務 URL 是一個開放的 URL,任何人都可以訪問,為了防止有人惡意構造 WebHook 訊息請求,我們應該對收到的請求進行驗證,判斷是否為來自 GitHub Web Hook 的請求。
如何驗證呢?是怎麼樣的一個流程呢?這時就要用到上面配置的 Secret
安全金鑰了。
具體步驟如下:
- GitHub WebHook 使用 Secret 對 Post Body 內容進行雜湊(HMAC 十六進位制摘要)計算,得到一個雜湊值,如
xxyyzz
。 - 將雜湊值存入請求頭
X-Hub-Signature-256
中,值以sha256=
開頭,如sha256=xxyyzz
。 - Web 服務收到請求,使用相同的 Secret 對 Post Body 進行相同雜湊演算法計算。得到一個摘要。
- 取出
X-Hub-Signature-256
請求頭的值進行比較,如果相同則表示請求來自 GitHub Web Hook。
下面是官方給出的 JavaScript 語言的驗證實現:
let encoder = new TextEncoder();
async function verifySignature(secret, header, payload) {
let parts = header.split("=");
let sigHex = parts[1];
let algorithm = { name: "HMAC", hash: { name: 'SHA-256' } };
let keyBytes = encoder.encode(secret);
let extractable = false;
let key = await crypto.subtle.importKey(
"raw",
keyBytes,
algorithm,
extractable,
[ "sign", "verify" ],
);
let sigBytes = hexToBytes(sigHex);
let dataBytes = encoder.encode(payload);
let equal = await crypto.subtle.verify(
algorithm.name,
key,
sigBytes,
dataBytes,
);
return equal;
}
function hexToBytes(hex) {
let len = hex.length / 2;
let bytes = new Uint8Array(len);
let index = 0;
for (let i = 0; i < hex.length; i += 2) {
let c = hex.slice(i, i + 2);
let b = parseInt(c, 16);
bytes[index] = b;
index += 1;
}
return bytes;
}
這種對內容進行摘要計算的驗證方式其實很常見,在之前介紹過的 JWT 的原理中也有提到,感興趣的可以檢視:JSON Web Token 入門教程
注意:Secret 十分重要,應該妥善儲存,防止洩漏。更不要儲存到公開倉庫之中。要天不知地不知,GitHub 知你知。
Java 驗證 WebHook
網上有很多使用 Java 語言驗證 GitHub WebHook 訊息的程式碼實現,這裡使用第三方依賴進行驗證,省去雜湊演算法的編寫。
引入依賴:
<dependency>
<groupId>am.ik.webhook</groupId>
<artifactId>webhook-verifier</artifactId>
<version>0.1.2</version>
</dependency>
訊息驗證:
private void verify(HttpServletRequest request, String body) {
HmacWebhookSigner webhookSigner = new HmacWebhookSigner("SHA256", secret);
WebhookVerifier verifier = new WebhookVerifier(webhookSigner, WebhookSigner.Encoder.HEX);
String signature = request.getHeader(WebhookHttpHeaders.X_HUB_SIGNATURE_256);
verifier.verify(body, signature);
}
驗證透過沒有任何返回,如果驗證失敗,會丟擲 WebhookAuthenticationException
異常。
WebHook 最佳實踐
遵循 WebHook 最佳實踐可以提高其安全性和效能,下面是一些常用建議。
- 只訂閱關注的事件,減少事件推送次數。
- 使用 HTTPS 提高安全性,HTTPS 已經是 Web 服務的標配。
- 配置白名單或驗證策略,確保訊息傳送方可信,比如文中提到的秘鑰雜湊驗證。
- 快速響應請求,很多 WebHook 推送對響應耗時有要求,比如 GitHub 是 10 秒,因此如果你的處理邏輯過於耗時,可以考慮非同步處理,優先響應。
最後推薦一下必應桌布網站https://bing.wdbyte.com/ ,這是一個使用 GitHub Action 自動抓取桌布,然後透過 WebHook 自動構建部署的專案,近期會對其網站進行升級,增加收藏,不同尺寸桌布下載功能,可以蹲下我的公眾號。
歡迎 Star:https://github.com/niumoo/bing-wallpaper
相關文章:如何使用 Github Actions 自動抓取每日必應桌布?
本文收錄於 Github.com/niumoo/JavaNotes,Java 系列文件,資料結構與演算法!
本文收錄於網站:https://www.wdbyte.com/,我的公眾號:程式猿阿朗