{"meta":{"title":"Programa de verificação de segredo de parceiros","intro":"Como um provedor de serviço, você pode associar-se ao GitHub para proteger os seus formatos de token secretos por varredura de segredos, que pesquisa commits acidentais no seu formato secreto e que pode ser enviado para o ponto de extremidade de verificação de um provedor de serviços.","product":"Qualidade de segurança e código","breadcrumbs":[{"href":"/pt/code-security","title":"Qualidade de segurança e código"},{"href":"/pt/code-security/tutorials","title":"Tutorials"},{"href":"/pt/code-security/tutorials/secret-scanning-partner-program","title":"Programa de parceiros"}],"documentType":"article"},"body":"# Programa de verificação de segredo de parceiros\n\nComo um provedor de serviço, você pode associar-se ao GitHub para proteger os seus formatos de token secretos por varredura de segredos, que pesquisa commits acidentais no seu formato secreto e que pode ser enviado para o ponto de extremidade de verificação de um provedor de serviços.\n\nO GitHub faz a varredura de repositórios de formatos secretos conhecidos para evitar uso fraudulento de credenciais confirmadas acidentalmente. Secret scanning ocorre por padrão em repositórios públicos e pacotes npm públicos. Os administradores do repositório e os proprietários da organização também podem habilitar secret scanning em repositórios privados. Como provedor de serviço, você pode fazer parcerias com GitHub para que seus formatos de segredo estejam incluídos em nosso secret scanning.\n\nQuando uma correspondência do seu formato secreto é encontrada em uma fonte pública, uma carga é enviada para um ponto de extremidade HTTP de sua escolha.\n\nQuando uma correspondência do formato secreto é encontrada em um repositório privado configurado para secret scanning, os administradores do repositório e o committer são alertados e podem visualizar e gerenciar o resultado secret scanning em GitHub. Para saber mais, confira [Gerenciar alertas de verificação de segredo](/pt/code-security/secret-scanning/managing-alerts-from-secret-scanning).\n\nEste artigo descreve como você pode fazer parceria com GitHub como um provedor de serviço e juntar-se ao programa de parceiro de secret scanning.\n\n## O processo de secret scanning\n\nO diagrama a seguir resume o processo de secret scanning para repositórios públicos, com qualquer correspondência enviada para o ponto de extremidade de verificação de um provedor de serviços. Um processo semelhante envia tokens de provedores de serviços expostos em pacotes públicos no registro npm.\n\n![Diagrama que mostra o processo de verificação de um segredo e o envio das correspondências para o ponto de extremidade de verificação de um provedor de serviços.](/assets/images/help/security/secret-scanning-flow.png)\n\n## Juntando-se ao programa de secret scanning em GitHub\n\n1. Entre em contato com GitHub para dar início ao processo.\n2. Identifique os segredos relevantes cuja varredura você deseja realizar e crie expressões regulares para capturá-los. Para obter informações e recomendações mais detalhadas, confira [Identificar seus segredos e criar expressões regulares](#identify-your-secrets-and-create-regular-expressions) abaixo.\n3. Para correspondências de segredos encontradas publicamente, crie um serviço de alerta de segredo que aceite webhooks de GitHub que contenham a carga da mensagem de secret scanning.\n4. Implemente a verificação de assinatura em seu serviço de alerta secreto.\n5. Implemente revogação do segredo e notificação do usuário no seu serviço de alerta secreto.\n6. Fornece feedback sobre falsos positivos (opcional).\n\n### Entre em contato com GitHub para dar início ao processo\n\nPara iniciar o processo de registro, envie um email para <a href=\"mailto:secret-scanning@github.com\"><secret-scanning@github.com></a>.\n\nVocê receberá detalhes do programa de secret scanning e você precisará aceitar os termos de participação de GitHub antes de prosseguir.\n\n### Identifique seus segredos e crie expressões regulares\n\nPara fazer a varredura dos seus segredos, GitHub precisa das informações a seguir para cada segredo que você deseja que seja incluído no programa secret scanning:\n\n* Um nome único e legível para o tipo do segredo. Usaremos isso para gerar o valor `Type` no conteúdo da mensagem posteriormente.\n\n* Uma expressão regular que encontra o tipo do segredo. Recomendamos que haja a maior precisão possível, pois isso ajudará a reduzir o número de falsos positivos. Algumas melhores práticas para segredos identificáveis de alta qualidade são:\n\n  * Um prefixo definido exclusivamente\n  * Sequências aleatórias de alta entropia\n  * Uma soma de verificação de 32 bits\n\n  ![Captura de tela mostrando o detalhamento de um segredo em um prefixo e uma soma de verificação de 32 bits.](/assets/images/help/security/regular-expression-guidance.png)\n\n* Uma conta de teste para o seu serviço. Isso nos permitirá gerar e analisar exemplos dos segredos, reduzindo ainda mais os falsos positivos.\n\n* A URL do ponto de extremidade que recebe mensagens de GitHub. A URL não precisa ser única para cada tipo de segredo.\n\nEnvie essas informações para <a href=\"mailto:secret-scanning@github.com\"><secret-scanning@github.com></a>.\n\n### Crie um serviço de alerta secreto\n\nCrie um ponto de extremidade HTTP público e acessível à internet na URL que você nos forneceu. Quando uma correspondência da expressão regular for encontrada publicamente, o GitHub enviará uma mensagem HTTP `POST` ao seu ponto de extremidade.\n\n#### Exemplo do corpo de solicitação\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\nO corpo da mensagem é uma matriz JSON que contém um ou mais objetos, com cada objeto representando apenas uma correspondência de segredos. Seu ponto de extremidade deve ser capaz de lidar com solicitações com um grande número de correspondências sem exceder o tempo. As chaves para cada correspondência de segredos são:\n\n* **token:** o valor da correspondência de segredos.\n* **tipo:** o nome exclusivo que você forneceu para identificar a expressão regular.\n* **url:** a URL de commit pública em que a correspondência foi encontrada (pode estar vazio)\n* **source:** onde o token foi encontrado em GitHub.\n\nA lista de valores válidos para `source` são:\n\n* Content\n* Fazer 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\\_content\n* Wiki\\_commit\n* Npm\n* Envio\\_manual\n* Unknown\n\n### Implemente a verificação de assinatura em seu serviço de alerta secreto\n\nA solicitação HTTP para o seu serviço também conterá cabeçalhos cujo uso recomendamos fortemente para validar que as mensagens recebidas são genuinamente do GitHub e não são mal-intencionadas.\n\nOs dois cabeçalhos HTTP a procurar são:\n\n* `Github-Public-Key-Identifier`: qual `key_identifier` usar de nossa API\n* `Github-Public-Key-Signature`: a assinatura do conteúdo\n\nRecupere a chave pública da verificação de segredos do GitHub de <https://api.github.com/meta/public_keys/secret_scanning> e valide a mensagem usando o algoritmo `ECDSA-NIST-P256V1-SHA256`. O ponto de extremidade fornecerá várias chaves públicas e `key_identifier`. Você pode determinar qual chave pública usar com base no valor de `Github-Public-Key-Identifier`.\n\n> \\[!NOTE]\n> Quando você enviar uma solicitação ao ponto de extremidade da chave pública acima, poderá atingir limites de taxa. Para evitar atingir limites de taxa, você pode usar um personal access token (classic) (nenhum escopo necessário) ou um fine-grained personal access token (somente o acesso de leitura dos repositórios públicos automáticos é necessário) conforme sugerido nos exemplos abaixo ou usar uma solicitação condicional. Para saber mais, confira [Introdução à API REST](/pt/rest/guides/getting-started-with-the-rest-api#conditional-requests).\n\n> \\[!NOTE]\n> A assinatura foi gerada usando o corpo da mensagem bruta. Portanto, é importante que você também use o texto da mensagem não processada para validação da assinatura, em vez de analisar e criar strings do JSON a fim de evitar reorganizar a mensagem ou mudar de espaçamento.\n\n```\n          **HTTP POST de exemplo enviado para verificar o ponto de extremidade**\n```\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\nOs snippets de código a seguir demonstram como você pode realizar a validação da assinatura.\nOs exemplos de código presumem que você definiu uma variável de ambiente chamada `GITHUB_PRODUCTION_TOKEN` com um [personal access token](https://github.com/settings/tokens) gerado para evitar atingir os limites de taxa. O personal access token não precisa de escopos/permissões.\n\n```\n          **Exemplo de validação no Go**\n```\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```\n          **Exemplo de validação no Ruby**\n```\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```\n          **Exemplo de validação no JavaScript**\n```\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### Implemente revogação do segredo e notificação do usuário no seu serviço de alerta secreto\n\nPara secret scanning encontrado publicamente, você pode melhorar o seu serviço de alerta de segredo para revogar os segredos expostos e notificar os usuários afetados. Você define como implementa isso no seu serviço de alerta de segredo, mas recomendamos considerar qualquer segredo que GitHub envie mensagens de que é público e que está comprometido.\n\n### Fornece feedback sobre falsos positivos\n\nColetamos feedback sobre a validade dos segredos individuais detectados nas respostas do parceiro. Se quiser participar, envie um email para <a href=\"mailto:secret-scanning@github.com\"><secret-scanning@github.com></a>.\n\nQuando relatamos segredos para você, enviamos uma matriz JSON com cada elemento que contém o token, o identificador de tipo e a URL do commit. Quando você nos envia feedback, você nos envia informações sobre se o token detectado era uma credencial real ou falsa. Aceitamos comentários nos seguintes formatos.\n\nVocê pode nos enviar o token não processado:\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\nVocê também pode fornecer o token em forma de hash após executar uma única forma de hash criptográfico do token não processado usando SHA-256:\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\nAlguns pontos importantes:\n\n* Você deve enviar-nos apenas a forma não processada do token (\"token\\_raw\"), ou a forma em hash (\"token\\_hash\"), mas não ambos.\n* Para a forma de hash do token não processado, você só pode usar SHA-256 para armazenar o token, e não qualquer outro algoritmo de hashing.\n* A etiqueta indica se o token é verdadeiro (\"true\\_positive\") ou um falso positivo (\"false\\_positive\"). São permitidas apenas essas duas strings literais minúsculas.\n\n> \\[!NOTE]\n> Nosso tempo limite de solicitação está definido para ser maior (ou seja, 30 segundos) para os parceiros que fornecem dados sobre falsos positivos. Se você precisar de um tempo limite superior a 30 segundos, envie um email para <a href=\"mailto:secret-scanning@github.com\"><secret-scanning@github.com></a>."}