Webhooks 安全性

当您配置好您的服务器后,就可以接收到 WebHook 服务发送给您的事件内容。但是,由于您的服务接下来将作出一些列动作,这里有可能会被恶意请求伪造。出于安全的考虑,您应该会希望能够确保接收到的请求是由 Coding 发出。可以通过在新建或编辑 WebHook 时,设置令牌,已用来验证。

设置 WebHook 令牌

您需要在两个地方设置您的令牌:项目的 WebHook 页面以及您的服务端。

在 WebHook 上设置您的令牌:

  1. 在 WebHook 列表页面,点击编辑您的 WebHook。
  2. 填写令牌字段,您可以设置任意字符串,当然我们更加推荐您设置成一个随机串。 (例如,通过在终端输入 ruby -rsecurerandom -e'puts SecureRandom.hex(20)' 获取的输出)
  3. 点击『更新 WebHook』. 设置

接下来,您要在您的服务端储存这个令牌,您可以存在您服务程序的配置文件中,或者存在您服务器的环境变量中。在此,示范为存在环境变量中,运行命令:

export SECRET_TOKEN=your_token

我们不推荐您将令牌作为死代码写在您的服务端程序中。

验证请求的真实性

设置好令牌后,Coding 将会对每个请求进行哈希签名。这个签名会放在请求头 X-Coding-Signature 中。

那么如何进行验证呢?我们举个简单的例子,假设原先有一个监听 WebHook 的基本服务如下:

require 'sinatra'
require 'json'

post '/payload' do
  push = JSON.parse(params[:payload])
  "I got some JSON: #{push.inspect}"
end

假设我们已经按照上面的做法,将令牌以 SECRET_TOKEN 为名字存储在了环境变量中。前面介绍过 Coding 会以令牌作为 KEY 将发送的内容进行 HMAC SHA1 散列加密后以十六进制显示,并加上前缀 sha1=,就要对上面的服务代码进行修改,使得以进行认证:

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

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

以上就是一个用以验证签名的例子。当然,不同的语言或外部服务在实现上可定不相同,但是大多数语言都会有相应的 HAMC 的算法库来使用。