{"meta":{"title":"Partnerprogramm für die Geheimnisüberprüfung","intro":"Als Dienstanbieter können Sie eine Partnerschaft mit GitHub eingehen, um Ihre geheimen Tokenformate durch die Geheimnisüberprüfung zu sichern, die nach versehentlichen Commits Ihres geheimen Formats sucht und an den Überprüfungsendpunkt eines Dienstanbieters gesendet werden kann.","product":"Sicherheit und Codequalität","breadcrumbs":[{"href":"/de/code-security","title":"Sicherheit und Codequalität"},{"href":"/de/code-security/tutorials","title":"Anleitungen"},{"href":"/de/code-security/tutorials/secret-scanning-partner-program","title":"Partnerprogramm"}],"documentType":"article"},"body":"# Partnerprogramm für die Geheimnisüberprüfung\n\nAls Dienstanbieter können Sie eine Partnerschaft mit GitHub eingehen, um Ihre geheimen Tokenformate durch die Geheimnisüberprüfung zu sichern, die nach versehentlichen Commits Ihres geheimen Formats sucht und an den Überprüfungsendpunkt eines Dienstanbieters gesendet werden kann.\n\nGitHub durchsucht Repositorys nach bekannten geheimen Formaten, um die betrügerische Verwendung von Anmeldeinformationen zu verhindern, die versehentlich begangen wurden.\nSecret scanning erfolgt standardmäßig in öffentlichen Repositorys und öffentlichen npm-Paketen. Administratoren von Repositorys und Organisationsbesitzer können secret scanning auch für private Repositorys aktivieren. Als Dienstleister können Sie mit GitHub zusammenarbeiten, damit Ihre proprietären Formate in unser secret scanning aufgenommen werden.\n\nWird in einer öffentlichen Quelle eine Übereinstimmung mit deinem Geheimnisformat gefunden, wird eine Payload an einen HTTP-Endpunkt Ihrer Wahl gesendet.\n\nWenn eine Übereinstimmung mit Ihrem geheimen Format in einem für secret scanning konfigurierten privaten Repository gefunden wird, werden Repository-Administratoren und der Committer benachrichtigt und können das secret scanning-Ergebnis auf GitHub anzeigen und verwalten. Weitere Informationen finden Sie unter [Verwalten von Warnungen zur Geheimnisüberprüfung](/de/code-security/how-tos/manage-security-alerts/manage-secret-scanning-alerts).\n\nIn diesem Artikel wird beschrieben, wie Sie als Dienstanbieter eine Partnerschaft mit GitHub eingehen und dem secret scanning-Partnerprogramm beitreten können.\n\n## Der secret scanning Prozess\n\nDas folgende Diagramm fasst den secret scanning Prozess für öffentliche Repositorys zusammen, wobei alle Übereinstimmungen an den Überprüfungsendpunkt eines Dienstanbieters gesendet werden. Ein ähnlicher Prozess sendet Dienstanbietertoken, die in öffentlichen Paketen in der npm-Registrierung verfügbar gemacht werden.\n\n![Diagramm: Prozess der Geheimnisüberprüfung und Senden von Übereinstimmungen an den Überprüfungsendpunkt eines Dienstanbieters.](/assets/images/help/security/secret-scanning-flow.png)\n\n## Dem secret scanningProgramm auf GitHub beitreten\n\n1. Wenden Sie sich an GitHub, um den Prozess zu starten.\n2. Identifiziere die relevanten Geheimnisse, die du überprüfen möchtest, und erstelle reguläre Ausdrücke, um diese zu erfassen. Ausführlichere Informationen und Empfehlungen finden Sie unten unter [Identifizieren Ihrer geheimen Schlüssel und Erstellen regulärer Ausdrücke](#identify-your-secrets-and-create-regular-expressions) unten.\n3. Erstellen Sie für Geheimnisübereinstimmungen, die öffentlich gefunden wurden, einen geheimen Benachrichtigungsdienst, der Webhooks von GitHub akzeptiert, die die Nachrichtennutzlast secret scanning enthalten.\n4. Implementieren Sie im Benachrichtigungsdienst für Geheimnisse eine Signaturüberprüfung.\n5. Implementieren Sie im Benachrichtigungsdienst die Sperrung von Geheimnissen sowie Benutzerbenachrichtigungen.\n6. Stelle für falsch positive Ergebnisse Feedback bereit (optional).\n\n### Kontaktieren Sie GitHub, um den Prozess zu starten\n\nSenden Sie eine E-Mail an <a href=\"mailto:secret-scanning@github.com\"><secret-scanning@github.com></a>, um den Registrierungsvorgang zu starten.\n\nSie erhalten Details zum secret scanning Programm, und Sie müssen den Teilnahmebedingungen zustimmen GitHub, bevor Sie fortfahren.\n\n### Identifizieren von Geheimnissen und Erstellen regulärer Ausdrücke\n\nZum Scannen Ihrer Geheimnisse benötigt GitHub die folgenden Informationen für jedes Geheimnis, das Sie in das secret scanning-Programm aufnehmen möchten:\n\n* Ein eindeutig lesbarer Name für den Geheimnistyp. Dieser wird später zur Angabe des `Type`-Werts in der Nachrichtennutzlast verwendet.\n\n* Einen regulären Ausdruck für die Suche des Geheimnistyps. Wir empfehlen Ihnen, so genau wie möglich zu sein, da dies dazu beiträgt, die Zahl der falsch positiven Ergebnisse zu verringern. Einige bewährte Methoden für hochwertige, identifizierbare Geheimnisse sind:\n\n  * Ein eindeutig definiertes Präfix\n  * Zufällige Zeichenfolgen mit hoher Entropie\n  * Eine 32-Bit-Prüfsumme\n\n  ![Screenshot, der die Aufschlüsselung eines Geheimnisses in ein Präfix und eine 32-Bit-Prüfsumme zeigt.](/assets/images/help/security/regular-expression-guidance.png)\n\n* Ein Testkonto für Ihren Dienst. Dies ermöglicht es uns, Beispiele für die Geheimnisse zu generieren und zu analysieren, um falsch positive Ergebnisse weiter zu reduzieren.\n\n* Die URL des Endpunkts, der Nachrichten von GitHub empfängt. Die URL muss nicht für jeden Geheimnistyp eindeutig sein.\n\nSenden Sie diese Informationen an <a href=\"mailto:secret-scanning@github.com\"><secret-scanning@github.com></a>.\n\n### Erstellen eines Benachrichtigungsdiensts für Geheimnisse\n\nErstelle einen öffentlichen, über das Internet zugänglichen HTTP-Endpunkt unter der bereitgestellten URL. Wenn öffentlich eine Übereinstimmung mit Ihrem regulären Ausdruck gefunden wird, sendet GitHub eine HTTP-`POST`-Nachricht an Ihren Endpunkt.\n\n#### Beispiel für Anforderungstext\n\n```json\n[\n  {\n    \"token\":\"NMIfyYncKcRALEXAMPLE\",\n    \"type\":\"mycompany_api_token\",\n    \"url\":\"https://github.com/octocat/Hello-World/blob/12345600b9cbe38a219f39a9941c9319b600c002/foo/bar.txt\",\n    \"source\":\"content\"\n  }\n]\n```\n\nBeim Nachrichtentext handelt es sich um ein JSON-Array, das ein oder mehrere Objekte enthält. Jedes davon stellt eine einzelne Geheimnisübereinstimmung dar. Dein Endpunkt sollte Anforderungen mit vielen Übereinstimmungen ohne Timeout verarbeiten können. Die Schlüssel für jede Geheimnisübereinstimmung lauten:\n\n* **token:** der Wert der Geheimnisübereinstimmung.\n* **type:** der bereitgestellte eindeutige Name, den Sie für Ihren regulären Ausdruck angegeben haben.\n* **url:** die öffentliche URL, unter der die Übereinstimmung gefunden wurde (kann leer gelassen werden).\n* **Quelle:** Wo das Token auf GitHub gefunden wurde.\n\nDie Liste der gültigen Werte für `source` lautet:\n\n* Content\n* Commit\n* Pull\\_request\\_title\n* Pull\\_request\\_description\n* Pull\\_request\\_comment\n* Issue\\_title\n* Issue\\_description\n* Issue\\_comment\n* Discussion\\_title\n* Discussion\\_body\n* Discussion\\_comment\n* Commit\\_comment\n* Gist\\_content\n* Gist\\_comment\n* Wiki\\_Inhalt\n* Wiki\\_commit\n* Npm\n* Manuelle Einreichung\n* Unbekannt\n\n### Implementieren einer Signaturüberprüfung im Benachrichtigungsdienst für Geheimnisse\n\nDie HTTP-Anfrage an Ihren Dienst enthält außerdem Header, deren Verwendung wir dringend empfehlen, um zu überprüfen, dass die von Ihnen empfangenen Nachrichten tatsächlich von GitHub stammen und nicht manipuliert wurden.\n\nDie beiden HTTP-Header, nach denen du suchen solltest, lauten:\n\n* `Github-Public-Key-Identifier`: der `key_identifier`, der von Ihrer API verwendet werden soll.\n* `Github-Public-Key-Signature`: die Signatur der Payload.\n\nSie können den GitHub öffentlichen Schlüssel für Secret Scanning von <https://api.github.com/meta/public_keys/secret_scanning> abrufen und die Nachricht mithilfe des `ECDSA-NIST-P256V1-SHA256`-Algorithmus validieren. Der Endpunkt stellt mehrere `key_identifier` und öffentliche Schlüssel bereit. Du kannst anhand des Werts von `Github-Public-Key-Identifier` bestimmen, welcher öffentliche Schlüssel verwendet werden soll.\n\n> \\[!NOTE]\n> Wenn Sie eine Anforderung an den oben genannten Endpunkt für den öffentlichen Schlüssel senden, überschreiten Sie möglicherweise Grenzwerte für Datenübertragungsraten. Um Ratenbegrenzungen zu vermeiden, können Sie ein personal access token (classic) (keine Berechtigungsbereiche erforderlich) oder ein fine-grained personal access token (nur der automatische Lesezugriff auf öffentliche Repositories ist erforderlich) verwenden, wie in den folgenden Beispielen vorgeschlagen, oder eine bedingte Anfrage verwenden. Weitere Informationen finden Sie unter [Bewährte Methoden für die Verwendung der REST-API](/de/rest/using-the-rest-api/best-practices-for-using-the-rest-api#use-conditional-requests-if-appropriate).\n\n> \\[!NOTE]\n> Die Signatur wurde mithilfe des unformatierten Nachrichtentexts generiert. Daher musst du auch für die Signaturüberprüfung den unformatierten Nachrichtentext verwenden, anstatt das JSON-Array zu analysieren und in eine Zeichenfolge umzuwandeln. So verhinderst du, die Nachricht neu ordnen oder Abstände ändern zu müssen.\n\n**HTTP POST-Beispiel zur Verifizierung des Endpunkts gesendet**\n\n```http\nPOST / HTTP/2\nHost: HOST\nAccept: */*\nContent-Length: 104\nContent-Type: application/json\nGithub-Public-Key-Identifier: bcb53661c06b4728e59d897fb6165d5c9cda0fd9cdf9d09ead458168deb7518c\nGithub-Public-Key-Signature: MEQCIQDaMKqrGnE27S0kgMrEK0eYBmyG0LeZismAEz/BgZyt7AIfXt9fErtRS4XaeSt/AO1RtBY66YcAdjxji410VQV4xg==\n\n[{\"source\":\"commit\",\"token\":\"some_token\",\"type\":\"some_type\",\"url\":\"https://example.com/base-repo-url/\"}]\n```\n\nMit den folgenden Codeausschnitten wird gezeigt, wie du eine Signaturüberprüfung durchführen kannst.\nDie Codebeispiele setzen voraus, dass Sie eine Umgebungsvariable namens `GITHUB_PRODUCTION_TOKEN` mit einem generierten [personal access token](https://github.com/settings/tokens) gesetzt haben, um Ratenbegrenzungen zu vermeiden. Das personal access token benötigt keine Bereiche/Berechtigungen.\n\n**Beispiel für eine Überprüfung in Go**\n\n```golang\npackage main\n\nimport (\n  \"crypto/ecdsa\"\n  \"crypto/sha256\"\n  \"crypto/x509\"\n  \"encoding/asn1\"\n  \"encoding/base64\"\n  \"encoding/json\"\n  \"encoding/pem\"\n  \"errors\"\n  \"fmt\"\n  \"math/big\"\n  \"net/http\"\n  \"os\"\n)\n\nfunc main() {\n  payload := `[{\"source\":\"commit\",\"token\":\"some_token\",\"type\":\"some_type\",\"url\":\"https://example.com/base-repo-url/\"}]`\n\n  kID := \"bcb53661c06b4728e59d897fb6165d5c9cda0fd9cdf9d09ead458168deb7518c\"\n\n  kSig := \"MEQCIQDaMKqrGnE27S0kgMrEK0eYBmyG0LeZismAEz/BgZyt7AIfXt9fErtRS4XaeSt/AO1RtBY66YcAdjxji410VQV4xg==\"\n\n  // Fetch the list of GitHub Public Keys\n  req, err := http.NewRequest(\"GET\", \"https://api.github.com/meta/public_keys/secret_scanning\", nil)\n  if err != nil {\n    fmt.Printf(\"Error preparing request: %s\\n\", err)\n    os.Exit(1)\n  }\n\n  if len(os.Getenv(\"GITHUB_PRODUCTION_TOKEN\")) == 0 {\n    fmt.Println(\"Need to define environment variable GITHUB_PRODUCTION_TOKEN\")\n    os.Exit(1)\n  }\n\n  req.Header.Add(\"Authorization\", \"Bearer \"+os.Getenv(\"GITHUB_PRODUCTION_TOKEN\"))\n\n  resp, err := http.DefaultClient.Do(req)\n  if err != nil {\n    fmt.Printf(\"Error requesting GitHub signing keys: %s\\n\", err)\n    os.Exit(2)\n  }\n\n  decoder := json.NewDecoder(resp.Body)\n  var keys GitHubSigningKeys\n  if err := decoder.Decode(&keys); err != nil {\n    fmt.Printf(\"Error decoding GitHub signing key request: %s\\n\", err)\n    os.Exit(3)\n  }\n\n  // Find the Key used to sign our webhook\n  pubKey, err := func() (string, error) {\n    for _, v := range keys.PublicKeys {\n      if v.KeyIdentifier == kID {\n        return v.Key, nil\n\n      }\n    }\n    return \"\", errors.New(\"specified key was not found in GitHub key list\")\n  }()\n\n  if err != nil {\n    fmt.Printf(\"Error finding GitHub signing key: %s\\n\", err)\n    os.Exit(4)\n  }\n\n  // Decode the Public Key\n  block, _ := pem.Decode([]byte(pubKey))\n  if block == nil {\n    fmt.Println(\"Error parsing PEM block with GitHub public key\")\n    os.Exit(5)\n  }\n\n  // Create our ECDSA Public Key\n  key, err := x509.ParsePKIXPublicKey(block.Bytes)\n  if err != nil {\n    fmt.Printf(\"Error parsing DER encoded public key: %s\\n\", err)\n    os.Exit(6)\n  }\n\n  // Because of documentation, we know it's a *ecdsa.PublicKey\n  ecdsaKey, ok := key.(*ecdsa.PublicKey)\n  if !ok {\n    fmt.Println(\"GitHub key was not ECDSA, what are they doing?!\")\n    os.Exit(7)\n  }\n\n  // Parse the Webhook Signature\n  parsedSig := asn1Signature{}\n  asnSig, err := base64.StdEncoding.DecodeString(kSig)\n  if err != nil {\n    fmt.Printf(\"unable to base64 decode signature: %s\\n\", err)\n    os.Exit(8)\n  }\n  rest, err := asn1.Unmarshal(asnSig, &parsedSig)\n  if err != nil || len(rest) != 0 {\n    fmt.Printf(\"Error unmarshalling asn.1 signature: %s\\n\", err)\n    os.Exit(9)\n  }\n\n  // Verify the SHA256 encoded payload against the signature with GitHub's Key\n  digest := sha256.Sum256([]byte(payload))\n  keyOk := ecdsa.Verify(ecdsaKey, digest[:], parsedSig.R, parsedSig.S)\n\n  if keyOk {\n    fmt.Println(\"THE PAYLOAD IS GOOD!!\")\n  } else {\n    fmt.Println(\"the payload is invalid :(\")\n    os.Exit(10)\n  }\n}\n\ntype GitHubSigningKeys struct {\n  PublicKeys []struct {\n    KeyIdentifier string `json:\"key_identifier\"`\n    Key           string `json:\"key\"`\n    IsCurrent     bool   `json:\"is_current\"`\n  } `json:\"public_keys\"`\n}\n\n// asn1Signature is a struct for ASN.1 serializing/parsing signatures.\ntype asn1Signature struct {\n  R *big.Int\n  S *big.Int\n}\n```\n\n**Beispiel für eine Überprüfung in Ruby**\n\n```ruby\nrequire 'openssl'\nrequire 'net/http'\nrequire 'uri'\nrequire 'json'\nrequire 'base64'\n\npayload = <<-EOL\n[{\"source\":\"commit\",\"token\":\"some_token\",\"type\":\"some_type\",\"url\":\"https://example.com/base-repo-url/\"}]\nEOL\n\npayload = payload\n\nsignature = \"MEQCIQDaMKqrGnE27S0kgMrEK0eYBmyG0LeZismAEz/BgZyt7AIfXt9fErtRS4XaeSt/AO1RtBY66YcAdjxji410VQV4xg==\"\n\nkey_id = \"bcb53661c06b4728e59d897fb6165d5c9cda0fd9cdf9d09ead458168deb7518c\"\n\nurl = URI.parse('https://api.github.com/meta/public_keys/secret_scanning')\n\nraise \"Need to define GITHUB_PRODUCTION_TOKEN environment variable\" unless ENV['GITHUB_PRODUCTION_TOKEN']\nrequest = Net::HTTP::Get.new(url.path)\nrequest['Authorization'] = \"Bearer #{ENV['GITHUB_PRODUCTION_TOKEN']}\"\n\nhttp = Net::HTTP.new(url.host, url.port)\nhttp.use_ssl = (url.scheme == \"https\")\n\nresponse = http.request(request)\n\nparsed_response = JSON.parse(response.body)\n\ncurrent_key_object = parsed_response[\"public_keys\"].find { |key| key[\"key_identifier\"] == key_id }\n\ncurrent_key = current_key_object[\"key\"]\n\nopenssl_key = OpenSSL::PKey::EC.new(current_key)\n\nputs openssl_key.verify(OpenSSL::Digest::SHA256.new, Base64.decode64(signature), payload.chomp)\n```\n\n**Beispiel für eine Überprüfung in JavaScript**\n\n```javascript\nconst crypto = require(\"crypto\");\nconst axios = require(\"axios\");\n\nconst GITHUB_KEYS_URI = \"https://api.github.com/meta/public_keys/secret_scanning\";\n\n/**\n * Verify a payload and signature against a public key\n * @param {String} payload the value to verify\n * @param {String} signature the expected value\n * @param {String} keyID the id of the key used to generated the signature\n * @return {void} throws if the signature is invalid\n */\nconst verify_signature = async (payload, signature, keyID) => {\n  if (typeof payload !== \"string\" || payload.length === 0) {\n    throw new Error(\"Invalid payload\");\n  }\n  if (typeof signature !== \"string\" || signature.length === 0) {\n    throw new Error(\"Invalid signature\");\n  }\n  if (typeof keyID !== \"string\" || keyID.length === 0) {\n    throw new Error(\"Invalid keyID\");\n  }\n\n  const keys = (await axios.get(GITHUB_KEYS_URI)).data;\n  if (!(keys?.public_keys instanceof Array) || keys.length === 0) {\n    throw new Error(\"No public keys found\");\n  }\n\n  const publicKey = keys.public_keys.find((k) => k.key_identifier === keyID) ?? null;\n  if (publicKey === null) {\n    throw new Error(\"No public key found matching key identifier\");\n  }\n\n  const verify = crypto.createVerify(\"SHA256\").update(payload);\n  if (!verify.verify(publicKey.key, Buffer.from(signature, \"base64\"), \"base64\")) {\n    throw new Error(\"Signature does not match payload\");\n  }\n};\n```\n\n### Implementieren der Sperrung von Geheimnissen und von Benutzerbenachrichtigungen im Benachrichtigungsdienst\n\nFür öffentlich gefundene secret scanning können Sie Ihren geheimen Benachrichtigungsdienst verbessern, um die offengelegten Geheimnisse zu widerrufen und die betroffenen Benutzer zu benachrichtigen. Die konkrete Implementierung im Benachrichtigungsdienst bleibt Ihnen überlassen. Doch es wird empfohlen, alle Geheimnisse als öffentlich und kompromittiert zu betrachten, zu denen Sie eine Nachricht von GitHub erhalten haben.\n\n### Bereitstellen von Feedback für falsch positive Ergebnisse\n\nWir sammeln Feedback zur Gültigkeit aller identifizierten Geheimnisse in Partnerantworten. Wenn Sie teilnehmen möchten, senden Sie eine E-Mail an <a href=\"mailto:secret-scanning@github.com\"><secret-scanning@github.com></a>.\n\nDie Nachricht, die du von uns zu einem Geheimnis erhältst, besteht aus einem JSON-Array mit dem Token, dem Typbezeichner und der Commit-URL. Informiere uns in deinem Feedback darüber, ob es sich bei dem erkannten Token um echte oder falsche Anmeldeinformationen handelte. Nutze für das Feedback eines der folgenden Formate.\n\nDu kannst das unformatierte Token senden:\n\n```json\n[\n  {\n    \"token_raw\": \"The raw token\",\n    \"token_type\": \"ACompany_API_token\",\n    \"label\": \"true_positive\"\n  }\n]\n```\n\nDu kannst das Token auch in Form eines kryptografischen Hashs des unformatierten Tokens mit SHA-256 bereitstellen:\n\n```json\n[\n  {\n    \"token_hash\": \"The SHA-256 hashed form of the raw token\",\n    \"token_type\": \"ACompany_API_token\",\n    \"label\": \"false_positive\"\n  }\n]\n```\n\nEinige wichtige Punkte:\n\n* Sende uns das Token entweder unformatiert („token\\_raw“) oder als Hash („token\\_hash“), nicht beides.\n* Verwende zum Erstellen der Hashform des unformatierten Tokens nur SHA-256, keinen anderen Hashalgorithmus.\n* Die Bezeichnung gibt an, ob es sich bei dem Token um ein echtes („true\\_positive“) oder ein falsch positives („false\\_positive“) Ergebnis handelt. Nur diese beiden Literalzeichenfolgen in Kleinbuchstaben sind zulässig.\n\n> \\[!NOTE]\n> Das Anforderungstimeout für Partner, die Daten zu falsch positiven Ergebnissen bereitstellen, ist höher (30 Sekunden). Wenn Sie ein Timeout von mehr als 30 Sekunden benötigen, senden Sie eine E-Mail an <a href=\"mailto:secret-scanning@github.com\"><secret-scanning@github.com></a>."}