forked from github/docs
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add content for new X-Hub-Signature-256 webhook header (github#15968)
Co-authored-by: Martin Lopes <[email protected]>
- Loading branch information
1 parent
2f2608a
commit d9a23d5
Showing
3 changed files
with
27 additions
and
12 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -34,9 +34,17 @@ $ export SECRET_TOKEN=<em>your_token</em> | |
|
||
### Validating payloads from GitHub | ||
|
||
When your secret token is set, GitHub uses it to create a hash signature with each payload. | ||
When your secret token is set, {% data variables.product.product_name %} uses it to create a hash signature with each payload. This hash signature is included with the headers of each request as {% if currentVersion == "free-pro-team@latest" or currentVersion ver_gt "[email protected]" or currentVersion == "private-instances@latest" %}`X-Hub-Signature-256`{% else if currentVersion ver_lt "[email protected]" %}`X-Hub-Signature`{% endif %}. | ||
|
||
This hash signature is passed along with each request in the headers as `X-Hub-Signature`. Suppose you have a basic server listening to webhooks that looks like this: | ||
{% if currentVersion == "free-pro-team@latest" or currentVersion ver_gt "[email protected]" or currentVersion == "private-instances@latest" %} | ||
{% note %} | ||
|
||
**Note:** For backward-compatibility, we also include the `X-Hub-Signature` header that is generated using the SHA-1 hash function. If possible, we recommend that you use the `X-Hub-Signature-256` header for improved security. The example below demonstrate using the `X-Hub-Signature-256` header. | ||
|
||
{% endnote %} | ||
{% endif %} | ||
|
||
For example, if you have a basic server that listens for webhooks, it might be configured similar to this: | ||
|
||
``` ruby | ||
require 'sinatra' | ||
|
@@ -48,7 +56,7 @@ post '/payload' do | |
end | ||
``` | ||
|
||
The goal is to compute a hash using your `SECRET_TOKEN`, and ensure that the hash from GitHub matches. GitHub uses an HMAC hexdigest to compute the hash, so you could change your server to look a little like this: | ||
The intention is to calculate a hash using your `SECRET_TOKEN`, and ensure that the result matches the hash from {% data variables.product.product_name %}. {% data variables.product.product_name %} uses an HMAC hex digest to compute the hash, so you could reconfigure your server to look a little like this: | ||
|
||
``` ruby | ||
post '/payload' do | ||
|
@@ -59,16 +67,21 @@ post '/payload' do | |
"I got some JSON: #{push.inspect}" | ||
end | ||
|
||
{% if currentVersion == "free-pro-team@latest" or currentVersion ver_gt "[email protected]" or currentVersion == "private-instances@latest" %} | ||
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_2']) | ||
end{% else if currentVersion ver_lt "[email protected]" %} | ||
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 | ||
end{% endif %} | ||
``` | ||
Obviously, your language and server implementations may differ than this code. There are a couple of very important things to point out, however: | ||
Your language and server implementations may differ from this example code. However, there are a number of very important things to point out: | ||
* No matter which implementation you use, the hash signature starts with `sha1=`, using the key of your secret token and your payload body. | ||
* No matter which implementation you use, the hash signature starts with {% if currentVersion == "free-pro-team@latest" or currentVersion ver_gt "[email protected]" or "private-instances@latest" %}`sha256=`{% else if currentVersion ver_lt "[email protected]" %}`sha1=`{% endif %}, using the key of your secret token and your payload body. | ||
|
||
* Using a plain `==` operator is **not advised**. A method like [`secure_compare`][secure_compare] performs a "constant time" string comparison, which renders it safe from certain timing attacks against regular equality operators. | ||
* Using a plain `==` operator is **not advised**. A method like [`secure_compare`][secure_compare] performs a "constant time" string comparison, which helps mitigate certain timing attacks against regular equality operators. | ||
|
||
[secure_compare]: http://rubydoc.info/github/rack/rack/master/Rack/Utils.secure_compare |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -49,8 +49,9 @@ Header | Description | |
`X-GitHub-Event`| Name of the event that triggered the delivery. | ||
`X-GitHub-Delivery`| A [GUID](http://en.wikipedia.org/wiki/Globally_unique_identifier) to identify the delivery.{% if currentVersion != "free-pro-team@latest" %} | ||
`X-GitHub-Enterprise-Version` | The version of the {% data variables.product.prodname_ghe_server %} instance that sent the HTTP POST payload. | ||
`X-GitHub-Enterprise-Host` | The hostname of the {% data variables.product.prodname_ghe_server %} instance that sent the HTTP POST payload.{% endif %} | ||
`X-Hub-Signature`| The HMAC hex digest of the response body. This header will be sent if the webhook is configured with a [`secret`](/v3/repos/hooks/#create-hook-config-params). The HMAC hex digest is generated using the `sha1` hash function and the `secret` as the HMAC `key`. | ||
`X-GitHub-Enterprise-Host` | The hostname of the {% data variables.product.prodname_ghe_server %} instance that sent the HTTP POST payload.{% endif %}{% if currentVersion != "private-instances@latest" %} | ||
`X-Hub-Signature`| This header is sent if the webhook is configured with a [`secret`](/v3/repos/hooks/#create-hook-config-params). This is the HMAC hex digest of the request body, and is generated using the SHA-1 hash function and the `secret` as the HMAC `key`.{% if currentVersion == "free-pro-team@latest" or currentVersion ver_gt "[email protected]" %} `X-Hub-Signature` is provided for compatibility with existing integrations, and we recommend that you use the more secure `X-Hub-Signature-256` instead.{% endif %}{% endif %}{% if currentVersion == "free-pro-team@latest" or currentVersion ver_gt "[email protected]" or currentVersion == "private-instances@latest" %} | ||
`X-Hub-Signature-256`| This header is sent if the webhook is configured with a [`secret`](/v3/repos/hooks/#create-hook-config-params). This is the HMAC hex digest of the request body, and is generated using the SHA-256 hash function and the `secret` as the HMAC `key`.{% endif %} | ||
|
||
Also, the `User-Agent` for the requests will have the prefix `GitHub-Hookshot/`. | ||
|
||
|
@@ -62,8 +63,9 @@ Also, the `User-Agent` for the requests will have the prefix `GitHub-Hookshot/`. | |
> Host: localhost:4567 | ||
> X-GitHub-Delivery: 72d3162e-cc78-11e3-81ab-4c9367dc0958{% if currentVersion != "free-pro-team@latest" %} | ||
> X-GitHub-Enterprise-Version: 2.15.0 | ||
> X-GitHub-Enterprise-Host: example.com{% endif %} | ||
> X-Hub-Signature: sha1=7d38cdd689735b008b3c702edd92eea23791c5f6 | ||
> X-GitHub-Enterprise-Host: example.com{% endif %}{% if currentVersion != "private-instances@latest" %} | ||
> X-Hub-Signature: sha1=7d38cdd689735b008b3c702edd92eea23791c5f6{% endif %}{% if currentVersion == "free-pro-team@latest" or currentVersion ver_gt "[email protected]" or currentVersion == "private-instances@latest" %} | ||
> X-Hub-Signature-256: sha256=d57c68ca6f92289e6987922ff26938930f6e66a2d161ef06abdf1859230aa23c{% endif %} | ||
> User-Agent: GitHub-Hookshot/044aadd | ||
> Content-Type: application/json | ||
> Content-Length: 6615 | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1 @@ | ||
Setting a webhook secret allows you to ensure that `POST` requests sent to the payload URL are from GitHub. When you set a secret, you'll receive the `X-Hub-Signature` header in the webhook `POST` request. For more details on how to use the secret and the `X-Hub-Signature` header to secure your webhook payloads, see "[Securing your webhooks](/webhooks/securing/)." | ||
Setting a webhook secret allows you to ensure that `POST` requests sent to the payload URL are from {% data variables.product.product_name %}. When you set a secret, you'll receive the {% if currentVersion == "free-pro-team@latest" or currentVersion ver_gt "[email protected]" %}`X-Hub-Signature` and `X-Hub-Signature-256` headers{% else if currentVersion ver_lt "[email protected]" %}`X-Hub-Signature` header{% else if currentVersion == "private-instances@latest" %}`X-Hub-Signature-256` header{% endif %} in the webhook `POST` request. For more information on how to use a secret with a signature header to secure your webhook payloads, see "[Securing your webhooks](/webhooks/securing/)." |