# Validação de entregas de webhooks

Você pode usar um segredo de webhook para verificar se uma entrega de webhook é de GitHub.

## Sobre a validação de entregas de webhooks

Quando o servidor estiver configurado para receber cargas úteis, ele escutará qualquer entrega enviada ao endpoint que você configurou. Para garantir que o servidor processe apenas as entregas de webhook que foram enviadas por GitHub e que a entrega não tenha sido adulterada, você deve validar a assinatura do webhook antes de continuar processando a entrega. Isso ajudará você a evitar gastar tempo do servidor para processar entregas que não vêm de GitHub e ajudará a evitar ataques do tipo man-in-the-middle.

Para fazer isso, você precisa:

1. Crie um token secreto para um webhook.
2. Armazene o token de forma segura no seu servidor.
3. Valide conteúdo do webhook recebido no token para verificar se ele foi obtido de GitHub e não foi violado.

## Criando um token secreto

Você pode criar um novo webhook com um token secreto ou pode adicionar um token secreto a um webhook existente. Ao criar um token secreto, você deve escolher uma sequência aleatória de texto com alta entropia.

* *Para criar um novo webhook com um token secreto*, confira [Criação de webhooks](/pt/enterprise-server@3.22/webhooks/using-webhooks/creating-webhooks).
* *Para adicionar um token secreto a um webhook existente*, edite as configurações do webhook. Em "Segredo", digite uma cadeia de caracteres para usar como uma chave `secret`. Para saber mais, confira [Editando webhooks](/pt/enterprise-server@3.22/webhooks/using-webhooks/editing-webhooks).

## Armazenamento seguro de tokens secretos

Depois de criar um token secreto, você deve armazená-lo em um local seguro que seu servidor possa acessar. Nunca codifique um token em um aplicativo ou envie um token para qualquer repositório. Para obter mais informações sobre como usar credenciais de autenticação de maneira segura em seu código, confira [Manter suas credenciais de API seguras](/pt/enterprise-server@3.22/rest/authentication/keeping-your-api-credentials-secure#use-authentication-credentials-securely-in-your-code).

## Validação de entregas de webhooks

GitHub usará o seu token secreto para criar uma assinatura de hash que será enviada a você com cada conteúdo. A assinatura do hash aparecerá em cada entrega como o valor do cabeçalho `X-Hub-Signature-256`. Para saber mais, confira [Eventos e cargas de webhook](/pt/enterprise-server@3.22/webhooks/webhook-events-and-payloads#delivery-headers).

Em seu código que lida com entregas de webhooks, você deve calcular um hash usando seu token secreto. Em seguida, compare o hash enviado GitHub com o hash esperado que você calculou e verifique se eles correspondem. Para ver exemplos que mostram como validar os hashes em várias linguagens de programação, confira [Exemplos](#examples).

Há alguns aspectos importantes a serem considerados ao validar cargas de webhooks:

* GitHub utiliza um resumo hexadecimal HMAC para calcular o hash.
* A assinatura do hash sempre começa com `sha256=`.
* A assinatura de hash é gerada usando o token secreto do seu webhook e o conteúdo do payload.
* Se o seu idioma e a implementação de servidor especificarem uma codificação de caracteres, certifique-se de que você manipula a carga como UTF-8. As cargas do webhook podem conter caracteres unicode.
* Nunca use um operador simples `==`. Em vez disso, considere usar um método como [`secure_compare`](https://www.rubydoc.info/gems/rack/Rack%2FUtils:secure_compare) ou [`crypto.timingSafeEqual`](https://nodejs.org/api/crypto.html#cryptotimingsafeequala-b) que executa uma comparação de cadeia de caracteres em "tempo constante" para ajudar a atenuar determinados ataques de tempo contra operadores de igualdade regulares ou loops regulares em linguagens otimizadas por JIT.

### Testando a validação da carga útil do webhook

Você pode usar os seguintes valores `secret` e `payload` para verificar se sua implementação está correta:

* `secret`: `It's a Secret to Everybody`
* `payload`: `Hello, World!`

Se sua implementação estiver correta, as assinaturas que você gerar deverão corresponder aos seguintes valores de assinatura:

* assinatura: `757107ea0eb2509fc211221cce984b8a37570b6d7586c22c46f4379c8b043e17` <!-- markdownlint-disable-line GHD034 -->
* X-Hub-Signature-256: `sha256=757107ea0eb2509fc211221cce984b8a37570b6d7586c22c46f4379c8b043e17`

### Exemplos

Você pode usar a linguagem de programação de sua preferência para implementar a verificação HMAC em seu código. A seguir, alguns exemplos que mostram como uma implementação pode ser feita em várias linguagens de programação.

#### Exemplo de Ruby

Por exemplo, você pode definir a seguinte função `verify_signature`:

```ruby
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
```

Em seguida, você pode chamá-lo quando receber um conteúdo de webhook:

```ruby
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
```

#### Exemplo de Python

Por exemplo, você pode definir a seguinte função `verify_signature` e chamá-la quando receber um conteúdo de webhook:

```python
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!")
```

#### Exemplo de JavaScript

Por exemplo, você pode definir a seguinte função `verifySignature` e chamá-la em qualquer ambiente JavaScript quando receber um payload de webhook.

```javascript
let encoder = new TextEncoder();

async function verifySignature(secret, header, payload) {
    let parts = header.split("=");
    let sigHex = parts[1];

    let algorithm = { name: "HMAC", hash: { name: 'SHA-256' } };

    let keyBytes = encoder.encode(secret);
    let extractable = false;
    let key = await crypto.subtle.importKey(
        "raw",
        keyBytes,
        algorithm,
        extractable,
        [ "sign", "verify" ],
    );

    let sigBytes = hexToBytes(sigHex);
    let dataBytes = encoder.encode(payload);
    let equal = await crypto.subtle.verify(
        algorithm.name,
        key,
        sigBytes,
        dataBytes,
    );

    return equal;
}

function hexToBytes(hex) {
    let len = hex.length / 2;
    let bytes = new Uint8Array(len);

    let index = 0;
    for (let i = 0; i < hex.length; i += 2) {
        let c = hex.slice(i, i + 2);
        let b = parseInt(c, 16);
        bytes[index] = b;
        index += 1;
    }

    return bytes;
}
```

#### Exemplo de TypeScript

Por exemplo, você pode definir a seguinte função `verify_signature` e chamá-la quando receber um conteúdo de webhook:

```javascript copy
import { Webhooks } from "@octokit/webhooks";

const webhooks = new Webhooks({
  secret: process.env.WEBHOOK_SECRET,
});

const handleWebhook = async (req, res) => {
  const signature = req.headers["x-hub-signature-256"];
  const body = await req.text();

  if (!(await webhooks.verify(body, signature))) {
    res.status(401).send("Unauthorized");
    return;
  }

  // The rest of your logic here
};
```

## Solução de problemas

Se você tiver certeza de que a carga é da GitHub, mas a verificação da assinatura falhar:

* Certifique-se de ter configurado um segredo para seu webhook. O cabeçalho `X-Hub-Signature-256` não estará presente se você não tiver configurado um segredo para seu webhook. Para obter mais informações sobre como configurar um segredo para seu webhook, confira [Editando webhooks](/pt/enterprise-server@3.22/webhooks/using-webhooks/editing-webhooks).
* Certifique-se de que esteja usando o cabeçalho correto. A GitHub recomenda que você use o cabeçalho `X-Hub-Signature-256`, que usa o algoritmo HMAC-SHA256. O cabeçalho `X-Hub-Signature` usa o algoritmo HMAC-SHA1 e é incluído apenas para fins herdados.
* Certifique-se de que esteja usando o algoritmo correto. Se estiver usando o cabeçalho `X-Hub-Signature-256`, deverá usar o algoritmo HMAC-SHA256.
* Verifique se você está usando o segredo correto do webhook. Se você não souber o valor do segredo do webhook, poderá atualizar o segredo do webhook. Para saber mais, confira [Editando webhooks](/pt/enterprise-server@3.22/webhooks/using-webhooks/editing-webhooks).
* Certifique-se de que a carga útil e os cabeçalhos não sejam modificados antes da verificação. Por exemplo, se você usar um proxy ou um balanceador de carga, certifique-se de que o proxy ou o balanceador de carga não modifique a carga útil ou os cabeçalhos.
* Se o seu idioma e a implementação de servidor especificarem uma codificação de caracteres, certifique-se de que você manipula a carga como UTF-8. As cargas do webhook podem conter caracteres unicode.

## Leitura adicional

* [Lidar com entregas de webhook](/pt/enterprise-server@3.22/webhooks/using-webhooks/handling-webhook-deliveries)
* [Melhores práticas para usar webhooks](/pt/enterprise-server@3.22/webhooks/using-webhooks/best-practices-for-using-webhooks)