Guia prático para receber webhooks do GitHub sem confiar cegamente no payload recebido.
Os exemplos mostram como validar X-Hub-Signature-256 em PHP e Node.js usando comparação em tempo constante. O material é independente de framework e não contém código de nenhum produto comercial.
- Leia o corpo bruto da requisição antes de interpretar o JSON.
- Valide
X-Hub-Signature-256com HMAC SHA-256. - Use comparação em tempo constante.
- Rejeite assinaturas ausentes, malformadas ou inválidas.
- Guarde
X-GitHub-Deliverypara detectar entregas duplicadas; veja o padrão de idempotênciaclaim → process → complete/fail. - Filtre os eventos permitidos pelo header
X-GitHub-Event. - Responda rapidamente e envie processamento pesado para uma fila.
- Nunca registre secrets ou payloads sensíveis sem política de retenção.
Para a visão completa das fronteiras de confiança — incluindo replay, autorização de negócio, DoS, logs, secrets e privilégios downstream — consulte o threat model do receiver.
flowchart LR
A[GitHub] -->|POST + assinatura| B[Endpoint HTTPS]
B --> C{Assinatura válida?}
C -->|Não| D[401 e auditoria mínima]
C -->|Sim| E{Delivery já processada?}
E -->|Sim| F[200 idempotente]
E -->|Não| G[Persistir envelope]
G --> H[Fila]
H --> I[Processador do evento]
Assinatura válida não significa execução única. Uma redelivery do GitHub mantém o mesmo X-GitHub-Delivery, então o consumidor deve fazer um claim atômico antes de produzir efeitos e precisa tratar concorrência, worker interrompido, TTL e retries de forma explícita.
O guia Idempotência de entregas com X-GitHub-Delivery mostra um padrão independente de framework com SQL/Redis, leases, fencing token, retry/backoff e a janela crítica entre executar o efeito e marcar a delivery como concluída.
A assinatura HMAC autentica os bytes recebidos quando o secret permanece confidencial, mas não substitui outras camadas de segurança.
O threat model cobre:
- o que a assinatura garante — e o que não garante;
- replay/redelivery e exatamente-uma-vez vs. idempotência;
- autorização de repositório/projeto após autenticação;
- limites de payload, rate limiting e disponibilidade;
- redução de privilégio entre receiver, fila e workers;
- logs, retenção e resposta a vazamento de secrets;
- checklist para revisão de um endpoint antes de produção.
| Plataforma | Implementação | Teste |
|---|---|---|
| PHP 8+ | examples/php/verify.php |
php tests/php-test.php |
| Node.js 20+ | examples/node/verify.mjs |
node tests/node-test.mjs |
Os exemplos recebem três valores: corpo bruto, header de assinatura e secret compartilhado.
A suíte pode ser executada sem GitHub Actions:
php tests/php-test.php
node tests/node-test.mjsO workflow de teste permanece disponível em modo manual. A manutenção normal prioriza execução local para evitar consumo desnecessário de CI.
- Abra Settings → Webhooks → Add webhook no repositório.
- Use HTTPS no Payload URL.
- Selecione
application/json. - Gere um secret longo e aleatório.
- Assine apenas os eventos necessários.
- Faça uma entrega de teste e confira o resultado sem copiar o secret para logs.
A assinatura comprova que o payload foi assinado com o secret compartilhado; ela não substitui autorização de negócio, idempotência, limites de tamanho, rate limiting, TLS ou controle de acesso ao painel de logs.
Consulte a documentação oficial sobre validação de webhooks.
- Envie relatos sensíveis conforme a política de segurança; nunca abra secrets ou payloads reais em uma issue.
- Para propor testes, exemplos ou melhorias, leia o guia de contribuição e o código de conduta.
- Escolha uma tarefa para primeira contribuição ou veja tudo que precisa de ajuda.
- Consulte também o changelog.
MIT.