Skip to main content
我们经常发布文档更新,此页面的翻译可能仍在进行中。 有关最新信息,请访问英语文档

保护 Webhook

出于安全原因,请确保您的服务器仅接收预期的 GitHub 请求。

一旦服务器配置为接收有效负载,它将侦听发送到您配置的端点的任何有效负载。 出于安全原因,您可能需要将请求限制为来自 GitHub 的请求。 有几种方法可以做到这一点(例如,可以选择允许来自 GitHub 的 IP 地址的请求),但更简单的方法是设置一个密钥令牌并验证信息。

可以使用 REST API 来管理存储库、组织和应用 Webhook。 可以列出 Webhook 的 Webhook 交付,获取并重新交付 Webhook 的个别交付,该交付可以集成到外部应用或服务中。 还可使用 REST API 更改 Webhook 的配置。 例如,您可以修改有效负载 URL、内容类型、SSL 验证和机密。 有关详细信息,请参阅:

设置密钥令牌

您需要在两个地方设置您的密钥令牌:GitHub 和您的服务器。

要在 GitHub 上设置令牌:

  1. 导航到要在其中设置 Webhook 的存储库。

  2. 在存储库名称下,单击 “设置”。 如果看不到“设置”选项卡,请选择 下拉菜单,然后单击“设置” 。

    存储库标头的屏幕截图,其中显示了选项卡。 “设置”选项卡以深橙色边框突出显示。

  3. 在左侧边栏中,单击 “Webhook”。

  4. 在 Webhook 旁,单击“编辑”。

  5. 在“机密”字段中,键入具有高熵的随机字符串。 例如,可在终端中使用 ruby -rsecurerandom -e 'puts SecureRandom.hex(20)' 生成一个字符串。

  6. 单击“更新 Webhook”****。

接下来,在服务器上设置存储此令牌的环境变量。 通常,这简单如运行以下命令:

$ export SECRET_TOKEN=YOUR-TOKEN

切勿将令牌硬编码到应用中!

验证来自 GitHub 的有效负载

设置密钥令牌后,GitHub Enterprise Cloud 使用它为每个有效负载创建一个哈希签名。 此哈希签名作为 x-hub-signature-256 包含在每个请求的标头中。

注意:为了向后兼容,我们还会包含使用 SHA-1 哈希函数生成的 x-hub-signature 标头。 如果可能,建议使用 x-hub-signature-256 标头来提高安全性。 以下示例演示了如何使用 x-hub-signature-256 标头。

你应使用你的 SECRET_TOKEN 计算哈希值,并确保结果与来自 GitHub Enterprise Cloud 的哈希匹配。 GitHub Enterprise Cloud 使用 HMAC 十六进制摘要来计算哈希值。

注意:Webhook 有效负载可以包含 unicode 字符。 如果您的语言和服务器实现指定了字符编码,请确保您将有效负载处理为 UTF-8。

你的语言和服务器实现可能与以下示例不同。 但是,需要指出一些非常重要的事情:

  • 无论使用哪种实现方式,哈希签名都使用机密令牌和有效负载主体的密钥,以 sha256= 开头。

  • 不建议使用普通的 == 运算符。 像 secure_compare 这样的方法会执行“恒定时间”字符串比较,这有助于缓解针对常规相等运算符的某些定时攻击。

Ruby 示例

例如,可以定义以下 verify_signature 函数:

def verify_signature(payload_body)
  signature = 'sha256=' + OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha256'), ENV['SECRET_TOKEN'], payload_body)
  return halt 500, "Signatures didn't match!" unless Rack::Utils.secure_compare(signature, request.env['HTTP_X_HUB_SIGNATURE_256'])
end

然后,可以在收到 Webhook 有效负载时调用它:

post '/payload' do
  request.body.rewind
  payload_body = request.body.read
  verify_signature(payload_body)
  push = JSON.parse(payload_body)
  "I got some JSON: #{push.inspect}"
end

Python 示例

例如,可以定义以下 verify_signature 函数,并在收到 Webhook 有效负载时调用它:

import hashlib
import hmac
def verify_signature(payload_body, secret_token, signature_header):
    """Verify that the payload was sent from GitHub by validating SHA256.
    
    Raise and return 403 if not authorized.
    
    Args:
        payload_body: original request body to verify (request.body())
        secret_token: GitHub app webhook token (WEBHOOK_SECRET)
        signature_header: header received from GitHub (x-hub-signature-256)
    """
    if not signature_header:
        raise HTTPException(status_code=403, detail="x-hub-signature-256 header is missing!")
    hash_object = hmac.new(secret_token.encode('utf-8'), msg=payload_body, digestmod=hashlib.sha256)
    expected_signature = "sha256=" + hash_object.hexdigest()
    if not hmac.compare_digest(expected_signature, signature_header):
        raise HTTPException(status_code=403, detail="Request signatures didn't match!")