Skip to main content

Sichern deiner Webhooks

Stelle aus Sicherheitsgründen sicher, dass dein Server nur die erwarteten Anforderungen von GitHub erhält.

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:

  1. Navigiere zu dem Repository, in dem du den Webhook einrichtest.
  2. Fülle das Textfeld „Geheimnis“ aus. Verwende eine zufällige Zeichenfolge mit hoher Entropie, z. B. durch die Ausgabe von ruby -rsecurerandom -e 'puts SecureRandom.hex(20)' am Terminal. Das Feld für das geheime Token des Webhooks
  3. 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 verwendet, um eine Hashsignatur für alle Nutzdaten zu erstellen. Diese Hashsignatur ist in den Headern jeder Anforderung als x-hub-signature-256 enthalten.

Hinweis: Aus Gründen der Abwärtskompatibilität fügen wir auch den x-hub-signature-Header ein, der mithilfe der SHA-1-Hashfunktion generiert wird. Wenn möglich, solltest du den x-hub-signature-256-Header verwenden, um mehr Sicherheit zu gewährleisten. Im Beispiel unten wird die Verwendung des x-hub-signature-256-Headers veranschaulicht.

Wenn du beispielsweise über einen einfachen Server verfügst, der auf Webhooks lauscht, kann er folgendermaßen konfiguriert sein:

require 'sinatra'
require 'json'

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

Mithilfe deines SECRET_TOKEN soll ein Hash berechnet und sichergestellt werden, dass das Ergebnis mit dem Hash von GitHub übereinstimmt. GitHub verwendet einen HMAC-Digest mit hexadezimalen Ziffern, um den Hash zu berechnen, sodass du deinen Server so neu konfigurieren können, dass er wie folgt aussieht:

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

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

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 diesem Beispielcode 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 wie secure_compare führt einen „constant time“-Zeichenfolgenvergleich durch, wodurch bestimmte Zeitangriffe gegen Gleichheitsoperatoren verringert werden.