6 min read

GitHub WebHook 使用教程

这篇文章介绍 GitHub Web Hooks 的使用。

什么是 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 按钮。

配置 GitHub Web Hook

配置完成后,点击 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 安全密钥了。

具体步骤如下:

  1. GitHub WebHook 使用 Secret 对 Post Body 内容进行哈希(HMAC 十六进制摘要)计算,得到一个哈希值,如 xxyyzz
  2. 将哈希值存入请求头 X-Hub-Signature-256 中,值以 sha256= 开头,如 sha256=xxyyzz
  3. Web 服务收到请求,使用相同的 Secret 对 Post Body 进行相同哈希算法计算。得到一个摘要。
  4. 取出 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 最佳实践可以提高其安全性和性能,下面是一些常用建议。

  1. 只订阅关注的事件,减少事件推送次数。
  2. 使用 HTTPS 提高安全性,HTTPS 已经是 Web 服务的标配。
  3. 配置白名单或验证策略,确保消息发送方可信,比如文中提到的秘钥哈希验证。
  4. 快速响应请求,很多 WebHook 推送对响应耗时有要求,比如 GitHub 是 10 秒,因此如果你的处理逻辑过于耗时,可以考虑异步处理,优先响应。

最后推荐一下必应壁纸网站https://bing.wdbyte.com/ ,这是一个使用 GitHub Action 自动抓取壁纸,然后通过 WebHook 自动构建部署的项目,近期会对其网站进行升级,增加收藏,不同尺寸壁纸下载功能,可以蹲下我的公众号

欢迎 Star:https://github.com/niumoo/bing-wallpaper

相关文章:如何使用 Github Actions 自动抓取每日必应壁纸?