Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

repo sync #513

Merged
merged 2 commits into from
Oct 14, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 20 additions & 7 deletions content/developers/webhooks-and-events/securing-your-webhooks.md
Original file line number Diff line number Diff line change
Expand Up @@ -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'
Expand All @@ -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
Expand All @@ -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
Original file line number Diff line number Diff line change
Expand Up @@ -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/`.

Expand All @@ -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
Expand Down
2 changes: 1 addition & 1 deletion data/reusables/webhooks/secret.md
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/)."