Sobald dein Server für das Erhalten von Nutzdaten konfiguriert ist, lauscht dieser auf jegliche Nutzdaten, die zu dem von dir konfigurierten Endpunkt gesendet werden. Aus Sicherheitsgründen solltest du ausschließlich Anforderungen von GitHub zulassen. Dafür gibt es verschiedene Möglichkeiten. Beispielsweise kannst du bestimmen, dass nur Anforderungen von der IP-Adresse von GitHub angenommen werden. Es ist jedoch weitaus einfacher, ein geheimes Token einzurichten und die Informationen zu überprüfen.
Du kannst die REST-API verwenden, um Repository, Organisation und App-Webhooks zu verwalten. Du kannst Webhookübermittlungen für einen Webhook auflisten oder eine individuelle Übermittlung für einen Webhook abrufen und erneut ausführen, der in eine externe App oder einen Dienst integriert werden kann. Du kannst die REST-API auch verwenden, um die Konfiguration des Webhooks zu ändern. Du kannst beispielsweise die Nutzlast-URL, den Inhaltstyp, die SSL-Überprüfung und das Geheimnis ändern. Weitere Informationen findest du unter:
Einrichten des geheimen Tokens
Du musst dein geheimes Token an zwei Orten einrichten: auf GitHub und auf deinem Server.
So richtest du dein Token auf GitHub ein:
-
Navigiere zu dem Repository, in dem du den Webhook einrichtest.
-
Wähle unter dem Namen deines Repositorys die Option Einstellungen aus. Wenn die Registerkarte „Einstellungen“ nicht angezeigt wird, wähle im Dropdownmenü die Option Einstellungen aus.
-
Wähle auf der linken Randleiste Webhooks aus.
-
Wähle neben dem Webhook die Option Bearbeiten aus.
-
Gib im Feld „Geheimnis“ eine zufällige Zeichenfolge mit hoher Entropie ein. Du kannst beispielsweise am Terminal mit
ruby -rsecurerandom -e 'puts SecureRandom.hex(20)'
eine Zeichenfolge generieren. -
Klicke auf Webhook aktualisieren.
Richte als Nächstes eine Umgebungsvariable auf deinem Server ein, die dieses Token speichert. Dazu musst du in der Regel nur Folgendes ausführen:
$ export SECRET_TOKEN=YOUR-TOKEN
Du solltest das Token niemals in deine App hartcodieren.
Überprüfen von GitHub-Nutzlasten
Wenn dein geheimes Token eingerichtet ist, wird es von GitHub AE verwendet, um eine Hashsignatur für alle Nutzdaten zu erstellen. Diese Hashsignatur ist in den Headern jeder Anforderung als x-hub-signature-256
enthalten.
Du solltest mithilfe deines SECRET_TOKEN
einen Hash berechnen und sicherstellen, dass das Ergebnis mit dem Hash von GitHub AE übereinstimmt. GitHub AE verwendet einen hexadezimalen HMAC-Digest (Hash-based Message Authentication Code), um den Hash zu berechnen.
Hinweis: Webhook-Nutzdaten können Unicode-Zeichen enthalten. Wenn deine Sprach- und Serverimplementierung eine Zeichencodierung angibt, musst du sicherstellen, dass diese Nutzdaten als UTF-8 behandelt werden.
Deine Sprach- und Serverimplementierungen können sich von denen in den folgenden Beispielen unterscheiden. Einige wichtige Dinge solltest du jedoch beachten:
-
Unabhängig von der verwendeten Implementierung beginnt die Hashsignatur mit
sha256=
und verwendet den Schlüssel deines geheimen Tokens sowie deinen Nutzdatentext. -
Die Verwendung eines einfachen
==
-Operators wird nicht empfohlen. Eine Methode wiesecure_compare
führt einen „constant time“-Zeichenfolgenvergleich durch, wodurch bestimmte Zeitangriffe gegen Gleichheitsoperatoren verringert werden.
Ruby-Beispiel
Beispielsweise kannst du die folgende verify_signature
-Funktion definieren:
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
Anschließend kannst du die Funktion aufrufen, wenn du eine Webhooknutzlast empfängst:
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
Beispiel für Python
Du kannst beispielsweise die folgende verify_signature
-Funktion definieren und aufrufen, wenn du eine Webhooknutzlast empfängst:
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!")