<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Asllan Maciel</title>
    <description>The latest articles on DEV Community by Asllan Maciel (@asllanmaciel).</description>
    <link>https://dev.to/asllanmaciel</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F684817%2Fde7e5b27-bf97-458f-8c20-8dc285107515.png</url>
      <title>DEV Community: Asllan Maciel</title>
      <link>https://dev.to/asllanmaciel</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/asllanmaciel"/>
    <language>en</language>
    <item>
      <title>Como validar webhooks do GitHub com HMAC em PHP e Node.js</title>
      <dc:creator>Asllan Maciel</dc:creator>
      <pubDate>Mon, 10 Aug 2026 16:56:57 +0000</pubDate>
      <link>https://dev.to/asllanmaciel/como-validar-webhooks-do-github-com-hmac-em-php-e-nodejs-a5n</link>
      <guid>https://dev.to/asllanmaciel/como-validar-webhooks-do-github-com-hmac-em-php-e-nodejs-a5n</guid>
      <description>&lt;p&gt;Receber um webhook é simples: você expõe um endpoint, recebe um POST e interpreta o JSON.&lt;/p&gt;

&lt;p&gt;O problema começa quando esse endpoint confia em qualquer payload que chega.&lt;/p&gt;

&lt;p&gt;Se uma aplicação executa ações a partir de webhooks — atualiza dados, inicia deploys, envia notificações ou dispara automações — ela precisa confirmar duas coisas antes de processar o evento:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;o payload foi assinado com o secret compartilhado com o GitHub;&lt;/li&gt;
&lt;li&gt;o conteúdo recebido não foi modificado no caminho.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Neste artigo, vamos implementar essa verificação com HMAC SHA-256 em PHP e Node.js.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Os exemplos completos e testados estão no repositório &lt;a href="https://github.com/asllanmaciel/github-webhook-security-guide" rel="noopener noreferrer"&gt;github-webhook-security-guide&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Como a assinatura funciona
&lt;/h2&gt;

&lt;p&gt;Ao enviar uma entrega, o GitHub calcula um HMAC usando o corpo original da requisição, o secret configurado no webhook e o algoritmo SHA-256.&lt;/p&gt;

&lt;p&gt;O resultado é enviado no header:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;X-Hub-Signature-256: sha256=&amp;lt;assinatura hexadecimal&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Seu endpoint precisa calcular a assinatura esperada a partir do &lt;strong&gt;corpo bruto&lt;/strong&gt; recebido e compará-la com o valor do header.&lt;/p&gt;

&lt;p&gt;Esse detalhe é importante: não valide a assinatura depois de converter o JSON em objeto e serializá-lo novamente. Qualquer mudança nos bytes — espaços, quebras de linha, Unicode ou ordem de serialização — muda o HMAC.&lt;/p&gt;

&lt;h2&gt;
  
  
  Checklist mínimo
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Leia o corpo bruto antes de interpretar o JSON.&lt;/li&gt;
&lt;li&gt;Rejeite secret vazio.&lt;/li&gt;
&lt;li&gt;Valide o formato de &lt;code&gt;X-Hub-Signature-256&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Calcule o HMAC com SHA-256.&lt;/li&gt;
&lt;li&gt;Compare em tempo constante.&lt;/li&gt;
&lt;li&gt;Rejeite assinaturas ausentes ou inválidas.&lt;/li&gt;
&lt;li&gt;Só então interprete e processe o evento.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Implementação em PHP 8+
&lt;/h2&gt;

&lt;p&gt;Em PHP, podemos usar &lt;code&gt;hash_hmac()&lt;/code&gt; para gerar a assinatura e &lt;code&gt;hash_equals()&lt;/code&gt; para realizar a comparação segura:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt;

&lt;span class="k"&gt;declare&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;strict_types&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;verifyGitHubWebhook&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nv"&gt;$payload&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nv"&gt;$signatureHeader&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nv"&gt;$secret&lt;/span&gt;
&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nv"&gt;$secret&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="s1"&gt;''&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt;
        &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nb"&gt;preg_match&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'/^sha256=[a-f0-9]{64}$/'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$signatureHeader&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nv"&gt;$expected&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'sha256='&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="nb"&gt;hash_hmac&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="s1"&gt;'sha256'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nv"&gt;$payload&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nv"&gt;$secret&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;hash_equals&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$expected&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$signatureHeader&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;O formato é verificado antes do cálculo. Isso elimina headers ausentes ou malformados e garante que a comparação receba valores com a estrutura esperada.&lt;/p&gt;

&lt;p&gt;Um endpoint genérico poderia usar a função assim:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nv"&gt;$payload&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;file_get_contents&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'php://input'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nv"&gt;$signature&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$_SERVER&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'HTTP_X_HUB_SIGNATURE_256'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="s1"&gt;''&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nv"&gt;$secret&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;getenv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'GITHUB_WEBHOOK_SECRET'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;?:&lt;/span&gt; &lt;span class="s1"&gt;''&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nf"&gt;verifyGitHubWebhook&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$payload&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$signature&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$secret&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nb"&gt;http_response_code&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;401&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;exit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Invalid signature'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nv"&gt;$event&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;json_decode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$payload&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;flags&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="no"&gt;JSON_THROW_ON_ERROR&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;O secret vem do ambiente, nunca do repositório.&lt;/p&gt;

&lt;h2&gt;
  
  
  Implementação em Node.js 20+
&lt;/h2&gt;

&lt;p&gt;No Node.js, usamos &lt;code&gt;createHmac()&lt;/code&gt; e &lt;code&gt;timingSafeEqual()&lt;/code&gt; do módulo nativo &lt;code&gt;node:crypto&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;createHmac&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;timingSafeEqual&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;node:crypto&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;verifyGitHubWebhook&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;signatureHeader&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;secret&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;secret&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="sr"&gt;/^sha256=&lt;/span&gt;&lt;span class="se"&gt;[&lt;/span&gt;&lt;span class="sr"&gt;a-f0-9&lt;/span&gt;&lt;span class="se"&gt;]{64}&lt;/span&gt;&lt;span class="sr"&gt;$/&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;signatureHeader&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;expected&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`sha256=&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nf"&gt;createHmac&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;sha256&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;secret&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;digest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;hex&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;receivedBuffer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Buffer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;signatureHeader&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;utf8&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;expectedBuffer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Buffer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;expected&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;utf8&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nx"&gt;receivedBuffer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;expectedBuffer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;
    &lt;span class="nf"&gt;timingSafeEqual&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;receivedBuffer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;expectedBuffer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A verificação do tamanho antes de &lt;code&gt;timingSafeEqual()&lt;/code&gt; é obrigatória: a função lança uma exceção quando os buffers têm comprimentos diferentes.&lt;/p&gt;

&lt;p&gt;Em frameworks como Express, Fastify ou NestJS, preserve o corpo bruto. Se o middleware de JSON consumir ou transformar o body antes da validação, a assinatura calculada não será a mesma.&lt;/p&gt;

&lt;h2&gt;
  
  
  Por que não usar uma comparação comum?
&lt;/h2&gt;

&lt;p&gt;Pode parecer suficiente escrever &lt;code&gt;expected === signatureHeader&lt;/code&gt;. Mas comparações comuns podem encerrar o trabalho assim que encontram o primeiro caractere diferente. Em determinados cenários, a variação no tempo de resposta pode revelar informações sobre a assinatura esperada.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;hash_equals()&lt;/code&gt; e &lt;code&gt;timingSafeEqual()&lt;/code&gt; foram projetadas para reduzir esse risco por meio de comparação em tempo constante.&lt;/p&gt;

&lt;h2&gt;
  
  
  A assinatura é apenas a primeira camada
&lt;/h2&gt;

&lt;p&gt;Uma assinatura válida prova que o payload foi assinado com o secret compartilhado. Ela não transforma todo evento em uma ação autorizada para o seu negócio.&lt;/p&gt;

&lt;h3&gt;
  
  
  Idempotência
&lt;/h3&gt;

&lt;p&gt;Armazene o header &lt;code&gt;X-GitHub-Delivery&lt;/code&gt;. Se a mesma entrega chegar novamente, responda de maneira idempotente em vez de repetir efeitos colaterais.&lt;/p&gt;

&lt;h3&gt;
  
  
  Eventos permitidos
&lt;/h3&gt;

&lt;p&gt;Leia &lt;code&gt;X-GitHub-Event&lt;/code&gt; e aceite somente os eventos necessários. Um endpoint criado para &lt;code&gt;push&lt;/code&gt; não deve processar qualquer tipo de entrega.&lt;/p&gt;

&lt;h3&gt;
  
  
  Limites e filas
&lt;/h3&gt;

&lt;p&gt;Limite o tamanho do body, responda rapidamente e envie trabalho pesado para uma fila. O endpoint do webhook não deve executar todo o processamento de forma síncrona.&lt;/p&gt;

&lt;h3&gt;
  
  
  Logs e retenção
&lt;/h3&gt;

&lt;p&gt;Nunca registre o secret. Evite armazenar payloads completos sem necessidade e defina uma política de retenção para dados que possam conter informações sensíveis.&lt;/p&gt;

&lt;h3&gt;
  
  
  Autorização de negócio
&lt;/h3&gt;

&lt;p&gt;Mesmo depois de validar o GitHub, confirme se aquele repositório, organização, instalação ou evento pode executar a operação solicitada.&lt;/p&gt;

&lt;h2&gt;
  
  
  Testando a implementação
&lt;/h2&gt;

&lt;p&gt;O GitHub fornece um vetor público de teste:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;secret: It's a Secret to Everybody
payload: Hello, World!
assinatura esperada:
sha256=757107ea0eb2509fc211221cce984b8a37570b6d7586c22c46f4379c8b043e17
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Use esse valor em testes automatizados e acrescente casos para assinatura correta, assinatura ausente, prefixo inválido, tamanho incorreto, payload modificado e secret vazio.&lt;/p&gt;

&lt;p&gt;O &lt;a href="https://github.com/asllanmaciel/github-webhook-security-guide" rel="noopener noreferrer"&gt;repositório do guia&lt;/a&gt; inclui exemplos independentes de framework e testes executáveis para PHP e Node.js.&lt;/p&gt;

&lt;h2&gt;
  
  
  Fluxo recomendado em produção
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Receber o POST via HTTPS.&lt;/li&gt;
&lt;li&gt;Preservar o corpo bruto.&lt;/li&gt;
&lt;li&gt;Validar a assinatura.&lt;/li&gt;
&lt;li&gt;Verificar duplicidade por &lt;code&gt;X-GitHub-Delivery&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Filtrar o tipo em &lt;code&gt;X-GitHub-Event&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Persistir um envelope mínimo.&lt;/li&gt;
&lt;li&gt;Enviar o processamento para uma fila.&lt;/li&gt;
&lt;li&gt;Responder rapidamente ao GitHub.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;A validação HMAC é pequena em quantidade de código, mas define a fronteira de confiança de todo o sistema.&lt;/p&gt;

&lt;p&gt;Se seu produto recebe webhooks, não trate o endpoint como uma simples rota de entrada. Trate-o como uma interface pública exposta a dados não confiáveis.&lt;/p&gt;




&lt;p&gt;Como você trata idempotência e reprocessamento de webhooks nos seus projetos?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>github</category>
      <category>security</category>
      <category>php</category>
      <category>node</category>
    </item>
    <item>
      <title>Voltei ao DEV: o que mudou depois de 25 anos programando</title>
      <dc:creator>Asllan Maciel</dc:creator>
      <pubDate>Mon, 10 Aug 2026 16:46:18 +0000</pubDate>
      <link>https://dev.to/asllanmaciel/voltei-ao-dev-o-que-mudou-depois-de-25-anos-programando-1ikl</link>
      <guid>https://dev.to/asllanmaciel/voltei-ao-dev-o-que-mudou-depois-de-25-anos-programando-1ikl</guid>
      <description>&lt;p&gt;Programo desde o início dos anos 2000. Nesse tempo, linguagens mudaram, frameworks nasceram e desapareceram, a web amadureceu e a inteligência artificial deixou os laboratórios para entrar no trabalho diário.&lt;/p&gt;

&lt;p&gt;Eu também mudei.&lt;/p&gt;

&lt;p&gt;Quando publiquei meu primeiro texto aqui no DEV, em 2024, meu perfil ainda mostrava apenas uma parte da minha trajetória. Depois disso, continuei construindo sistemas, empresas, produtos digitais, plataformas SaaS e automações. Mas compartilhei muito pouco desse processo.&lt;/p&gt;

&lt;p&gt;Estou voltando para mudar isso.&lt;/p&gt;

&lt;h2&gt;
  
  
  Construir continua sendo meu jeito de aprender
&lt;/h2&gt;

&lt;p&gt;Ao longo de mais de 25 anos, aprendi que tecnologia só ganha valor quando resolve um problema concreto.&lt;/p&gt;

&lt;p&gt;Uma API não é interessante apenas por estar bem estruturada. Ela é interessante quando permite que outro produto exista.&lt;/p&gt;

&lt;p&gt;Uma automação não importa apenas porque economiza alguns cliques. Ela importa quando devolve tempo, reduz erros e torna uma operação mais previsível.&lt;/p&gt;

&lt;p&gt;Um SaaS não se sustenta apenas com uma boa stack. Ele precisa resolver uma dor real, funcionar em produção e encontrar pessoas dispostas a usá-lo.&lt;/p&gt;

&lt;p&gt;Essa ligação entre engenharia, produto e negócio é o que mais me interessa hoje.&lt;/p&gt;

&lt;h2&gt;
  
  
  O que estou construindo
&lt;/h2&gt;

&lt;p&gt;Atualmente, trabalho em produtos e experimentos que combinam desenvolvimento, inteligência artificial, automação e negócios digitais.&lt;/p&gt;

&lt;p&gt;Entre eles estão:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;GHDevLog&lt;/strong&gt; — uma central privada para receber, validar e investigar webhooks do GitHub em tempo real, com foco em segurança e rastreabilidade;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;BibliaAPI&lt;/strong&gt; — uma infraestrutura bíblica para aplicações, com API REST, WordPress, aplicativo mobile e recursos SaaS;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;ClariDados&lt;/strong&gt; — analytics simples para acompanhar visitas, origens, páginas e conversões sem a complexidade das plataformas tradicionais;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cresça na Fé&lt;/strong&gt; — uma plataforma de conteúdo, estudos e recursos voltados ao crescimento espiritual;&lt;/li&gt;
&lt;li&gt;ferramentas para desenvolvedores, plugins WordPress, APIs e novos SaaS ainda em validação.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Também venho estudando e aplicando agentes de IA, MCPs, workflows e automações em situações reais — não apenas como demonstrações, mas como partes de produtos e operações.&lt;/p&gt;

&lt;h2&gt;
  
  
  Por que voltar a escrever
&lt;/h2&gt;

&lt;p&gt;Durante muito tempo, grande parte do meu trabalho permaneceu nos bastidores. Muitos sistemas pertencem a clientes ou fazem parte de produtos privados. Isso, porém, não impede que as decisões, os padrões e os aprendizados sejam compartilhados.&lt;/p&gt;

&lt;p&gt;Quero usar este espaço para documentar:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;decisões de arquitetura e seus trade-offs;&lt;/li&gt;
&lt;li&gt;construção e validação de produtos SaaS;&lt;/li&gt;
&lt;li&gt;APIs, webhooks e integrações seguras;&lt;/li&gt;
&lt;li&gt;PHP, Laravel, WordPress e JavaScript em produção;&lt;/li&gt;
&lt;li&gt;agentes de IA, MCPs e automações aplicadas;&lt;/li&gt;
&lt;li&gt;Docker, CI/CD, observabilidade e operação;&lt;/li&gt;
&lt;li&gt;erros, mudanças de direção e aprendizados de produto;&lt;/li&gt;
&lt;li&gt;a relação entre código, monetização e crescimento.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A intenção não é publicar teoria distante da prática. Quero escrever sobre problemas que encontrei, soluções que testei e coisas que ainda estou tentando entender.&lt;/p&gt;

&lt;h2&gt;
  
  
  O que 25 anos de programação me ensinaram
&lt;/h2&gt;

&lt;p&gt;Alguns princípios sobreviveram a todas as mudanças de stack:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;O problema vem antes da ferramenta.&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Escolher tecnologia sem compreender a necessidade costuma produzir soluções sofisticadas para o problema errado.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Colocar no ar ensina mais do que planejar indefinidamente.&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Construir, observar, aprender e melhorar continua sendo um ciclo poderoso.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Código é apenas uma parte do produto.&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Segurança, documentação, experiência, operação, aquisição e sustentabilidade também fazem parte da engenharia de algo útil.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Simplicidade exige experiência.&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
É fácil adicionar camadas. Difícil é remover o que não precisa existir.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Compartilhar organiza o pensamento.&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Explicar uma decisão obriga a separar convicção, hábito e evidência.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  O que vem a seguir
&lt;/h2&gt;

&lt;p&gt;Nos próximos textos, pretendo abrir os bastidores dos projetos que estou construindo e transformar experiências práticas em conteúdo que outras pessoas possam testar e adaptar.&lt;/p&gt;

&lt;p&gt;Alguns temas que já estão na fila:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;como validar assinaturas de webhooks do GitHub com HMAC;&lt;/li&gt;
&lt;li&gt;decisões de arquitetura para SaaS multi-tenant;&lt;/li&gt;
&lt;li&gt;o que aprendi construindo uma API que serve diferentes produtos;&lt;/li&gt;
&lt;li&gt;onde agentes de IA realmente ajudam — e onde apenas adicionam complexidade;&lt;/li&gt;
&lt;li&gt;automações e ferramentas para o ecossistema WordPress;&lt;/li&gt;
&lt;li&gt;como conectar engenharia, produto e crescimento sem perder o foco técnico.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Se você trabalha com algum desses temas, está construindo um produto ou enfrentando um problema parecido, vamos conversar.&lt;/p&gt;

&lt;p&gt;Estou de volta ao DEV para compartilhar enquanto construo — não depois que tudo parecer perfeito.&lt;/p&gt;

&lt;p&gt;Porque, depois de 25 anos, uma coisa continua igual: &lt;strong&gt;construir ainda é meu jeito de aprender.&lt;/strong&gt;&lt;/p&gt;




&lt;p&gt;Você também voltou a escrever depois de algum tempo? O que fez você recomeçar?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>programming</category>
      <category>career</category>
      <category>buildinpublic</category>
      <category>discuss</category>
    </item>
    <item>
      <title>O que é PHP e por que aprender?</title>
      <dc:creator>Asllan Maciel</dc:creator>
      <pubDate>Wed, 14 Aug 2024 01:28:02 +0000</pubDate>
      <link>https://dev.to/asllanmaciel/o-que-e-php-e-por-que-aprender-3po9</link>
      <guid>https://dev.to/asllanmaciel/o-que-e-php-e-por-que-aprender-3po9</guid>
      <description>&lt;p&gt;Se você está começando no mundo do desenvolvimento web, é provável que já tenha ouvido falar de PHP. Mas o que exatamente é PHP e por que ele é tão amplamente utilizado? Neste post, vamos explorar o que torna o PHP uma escolha popular entre desenvolvedores, suas principais aplicações e por que você deve considerar aprender essa linguagem.&lt;/p&gt;

&lt;h2&gt;
  
  
  O que é PHP?
&lt;/h2&gt;

&lt;p&gt;PHP, que originalmente significava "Personal Home Page" e agora é conhecido como "Hypertext Preprocessor", é uma linguagem de programação de código aberto utilizada principalmente para o desenvolvimento de aplicações web. Ele foi criado por Rasmus Lerdorf em 1994 e, desde então, se tornou uma das linguagens mais populares para o desenvolvimento de sites dinâmicos.&lt;/p&gt;

&lt;p&gt;PHP é uma linguagem server-side, o que significa que seu código é executado no servidor antes de ser enviado ao navegador do usuário. Isso permite que os desenvolvedores criem páginas web dinâmicas, onde o conteúdo pode mudar com base em interações do usuário ou outros fatores, como consultas a bancos de dados.&lt;/p&gt;

&lt;h2&gt;
  
  
  Por que o PHP é tão popular?
&lt;/h2&gt;

&lt;p&gt;PHP conquistou seu espaço no mundo do desenvolvimento web por várias razões:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Facilidade de Aprendizado:&lt;/strong&gt; Comparado a outras linguagens de programação, PHP é relativamente fácil de aprender, especialmente para quem já tem experiência com HTML. Sua sintaxe é clara e intuitiva, permitindo que novos desenvolvedores comecem a construir projetos rapidamente.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Comunidade e Suporte:&lt;/strong&gt; PHP tem uma comunidade enorme e ativa, o que significa que há uma abundância de recursos, tutoriais, e fóruns onde você pode encontrar ajuda. Além disso, muitas bibliotecas e frameworks, como Laravel e Symfony, foram desenvolvidos para facilitar ainda mais o trabalho com PHP.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Integração com Bancos de Dados:&lt;/strong&gt; PHP se integra facilmente com uma variedade de bancos de dados, como MySQL, PostgreSQL, Oracle, e muitos outros. Isso torna simples a criação de sites e aplicações que dependem de grandes volumes de dados.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Custo-Benefício:&lt;/strong&gt; Sendo uma linguagem de código aberto, PHP não requer nenhum custo de licença. Isso, aliado à grande quantidade de ferramentas e hospedagens compatíveis, faz do PHP uma opção econômica para desenvolvimento de websites.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Flexibilidade:&lt;/strong&gt; PHP é uma linguagem extremamente flexível. Ele pode ser usado tanto para criar pequenos scripts quanto para desenvolver grandes aplicações corporativas. Além disso, PHP se integra facilmente com outras tecnologias, como JavaScript, tornando-o ideal para desenvolver aplicações web completas.&lt;/p&gt;

&lt;h2&gt;
  
  
  Principais Aplicações do PHP
&lt;/h2&gt;

&lt;p&gt;PHP é uma linguagem versátil e pode ser usada para uma ampla gama de projetos. Aqui estão algumas das principais aplicações do PHP:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Desenvolvimento de Sites Dinâmicos:&lt;/strong&gt; A aplicação mais comum do PHP é no desenvolvimento de sites dinâmicos. Usando PHP, você pode criar páginas que exibem conteúdo diferente dependendo da interação do usuário, como blogs, portais de notícias, e-commerce, etc.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Sistemas de Gerenciamento de Conteúdo (CMS):&lt;/strong&gt; Muitos dos CMS mais populares, como WordPress, Joomla e Drupal, são construídos com PHP. Esses sistemas permitem que os usuários gerenciem o conteúdo de seus sites sem necessidade de conhecimento técnico avançado.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Aplicações Web Complexas:&lt;/strong&gt; PHP também é amplamente utilizado para criar aplicações web mais complexas, como plataformas de e-learning, redes sociais, e sistemas de gerenciamento de projetos.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;APIs e Microserviços:&lt;/strong&gt; PHP pode ser usado para construir APIs RESTful, que são utilizadas para conectar diferentes partes de uma aplicação ou para integrar diferentes sistemas.&lt;/p&gt;

&lt;h2&gt;
  
  
  Por que aprender PHP?
&lt;/h2&gt;

&lt;p&gt;Agora que você sabe o que é PHP e onde ele é usado, vamos falar sobre por que você deve aprender essa linguagem.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Alta Demanda no Mercado:&lt;/strong&gt; PHP é uma das linguagens mais utilizadas no desenvolvimento web, e há uma alta demanda por desenvolvedores que dominem essa tecnologia. Empresas de todos os portes, desde startups até grandes corporações, buscam profissionais que possam desenvolver e manter suas aplicações PHP.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Grande Ecossistema de Ferramentas:&lt;/strong&gt; Ao aprender PHP, você terá acesso a um grande ecossistema de ferramentas, frameworks e bibliotecas que podem acelerar o desenvolvimento e ajudar você a criar soluções mais sofisticadas.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Oportunidades de Trabalho como Freelancer:&lt;/strong&gt; Se você deseja trabalhar como freelancer, PHP oferece uma ampla gama de oportunidades. Muitos pequenos negócios e empreendedores procuram desenvolvedores PHP para criar e manter seus sites, o que pode ser uma excelente fonte de renda extra.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Facilidade de Hospedagem:&lt;/strong&gt; A maioria das hospedagens web oferece suporte nativo ao PHP, o que significa que você pode facilmente colocar seus projetos no ar sem complicações.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Aprendizado Contínuo:&lt;/strong&gt; PHP tem evoluído continuamente, com novas versões introduzindo melhorias significativas. Aprender PHP significa também estar sempre atualizado com as últimas tendências e práticas do desenvolvimento web.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusão
&lt;/h2&gt;

&lt;p&gt;PHP é uma linguagem poderosa, flexível e amplamente utilizada que pode abrir muitas portas no mundo do desenvolvimento web. Se você está começando agora ou se já tem experiência com outras linguagens, aprender PHP pode ser um passo estratégico para avançar na sua carreira.&lt;/p&gt;

&lt;p&gt;Então, o que está esperando? Pegue seu editor de código, instale o PHP e comece a explorar o vasto universo de possibilidades que essa linguagem oferece. Nos próximos posts, vamos mergulhar mais fundo em como configurar seu ambiente PHP e começar a escrever seus primeiros scripts.&lt;/p&gt;

&lt;h2&gt;
  
  
  Recursos Adicionais
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://www.php.net/docs.php" rel="noopener noreferrer"&gt;Documentação Oficial do PHP&lt;/a&gt;&lt;br&gt;
&lt;a href="https://www.reddit.com/r/php/" rel="noopener noreferrer"&gt;Comunidade PHP no Reddit&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Se você quer acelerar seu aprendizado em PHP ou precisa de um especialista para impulsionar o seu projeto, estou aqui para ajudar. Vamos transformar suas ideias em realidade com soluções robustas e eficientes. Entre em contato comigo através do &lt;a href="https://asllanmaciel.com.br/" rel="noopener noreferrer"&gt;asllanmaciel.com.br&lt;/a&gt;, explore mais conteúdos sobre WordPress no &lt;a href="https://wp24horas.com.br/" rel="noopener noreferrer"&gt;WP24Horas&lt;/a&gt; ou conheça os serviços da minha agência em &lt;a href="https://m3marketingdigital.com.br/" rel="noopener noreferrer"&gt;M3 Marketing Digital&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;Vamos juntos criar algo extraordinário?&lt;/p&gt;

</description>
      <category>php</category>
      <category>webdev</category>
      <category>beginners</category>
      <category>programming</category>
    </item>
  </channel>
</rss>
