Une fois que votre serveur est configuré pour recevoir des charges utiles, il écoute toutes les charges utiles envoyées au point de terminaison que vous avez configuré. Pour des raisons de sécurité, vous pouvez limiter les demandes à celles envoyées par GitHub. Il existe plusieurs moyens de le faire (par exemple, vous pouvez choisir d’autoriser les demandes envoyées par l’adresse IP de GitHub), mais la méthode la plus facile est de configurer un jeton secret et de valider les informations.
Vous pouvez utiliser l’API REST pour gérer les webhooks de dépôt, d’organisation et d’application. Vous pouvez lister les livraisons d’un webhook, ou obtenir et refaire une livraison individuelle d’un webhook, qui peut être intégré dans une application ou un service externe. Vous pouvez également utiliser l’API REST pour changer la configuration du webhook. Par exemple, vous pouvez modifier l’URL de charge utile, le type de contenu, la vérification SSL et le secret. Pour plus d'informations, consultez les pages suivantes :
Définition de votre jeton secret
Vous devez configurer votre jeton secret à deux endroits : GitHub et votre serveur.
Pour définir votre jeton sur GitHub :
-
Accédez au dépôt dans lequel vous avez configuré votre webhook.
-
Sous le nom de votre dépôt, cliquez sur Paramètres. Si vous ne voyez pas l’onglet « Paramètres », sélectionnez le menu déroulant , puis cliquez sur Paramètres.
-
Dans la barre latérale gauche, cliquez sur Webhooks.
-
À côté du webhook, cliquez sur Modifier.
-
Dans le champ « Secret », tapez une chaîne aléatoire avec une entropie élevée. Vous pouvez générer une chaîne avec
ruby -rsecurerandom -e 'puts SecureRandom.hex(20)'
dans le Terminal, par exemple. -
Cliquez sur Mettre à jour le webhook.
Ensuite, configurez une variable d’environnement sur votre serveur pour stocker ce jeton. En règle générale, ça revient à simplement exécuter :
$ export SECRET_TOKEN=YOUR-TOKEN
Ne codez jamais en dur le jeton dans votre application !
Validation des charges utiles provenant de GitHub
Quand votre jeton secret est défini, GitHub l’utilise pour créer une signature de hachage avec chaque charge utile. Cette signature de hachage est ajoutée aux en-têtes de chaque demande sous la forme x-hub-signature-256
.
Remarque : Pour la compatibilité descendante, nous ajoutons également l’en-tête x-hub-signature
qui est généré avec la fonction de hachage SHA-1. Si possible, nous vous recommandons d’utiliser l’en-tête x-hub-signature-256
pour améliorer la sécurité. Les exemples ci-dessous montrent l’utilisation de l’en-tête x-hub-signature-256
.
Vous devez calculer un hachage en utilisant votre SECRET_TOKEN
et vérifier que le résultat correspond au hachage de GitHub. GitHub utilise un code de hachage hexadécimal HMAC pour calculer le hachage.
Remarque : Les charges utiles de webhook peuvent contenir des caractères Unicode. Si votre implémentation de langage et de serveur spécifie un codage de caractères, vérifiez que vous traitez la charge utile en UTF-8.
Vos implémentations de langage et de serveur peuvent différer des exemples suivants. Toutefois, il y a un certain nombre de choses très importantes à souligner :
-
Quelle que soit l’implémentation que vous utilisez, la signature de hachage commence par
sha256=
, et utilise la clé de votre jeton secret et le corps de votre charge utile. -
L’utilisation d’un opérateur
==
brut n’est pas recommandée. Une méthode commesecure_compare
effectue une comparaison de chaînes de « temps constant », qui permet d’atténuer certaines attaques de minutage contre les opérateurs d’égalité classiques.
Exemple Ruby
Par exemple, vous pouvez définir la fonction verify_signature
suivante :
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
Vous pouvez ensuite l’appeler quand vous recevez une charge utile de 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
Exemple Python
Par exemple, vous pouvez définir la fonction verify_signature
suivante et l’appeler quand vous recevez une charge utile de 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!")