> For the complete documentation index, see [llms.txt](https://documentation.themembers.dev.br/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://documentation.themembers.dev.br/webhooks/webhooks-do-checkout/seguranca.md).

# Segurança

## **🔐 Validação de Assinatura de Webhooks**

Para garantir a **autenticidade** e a **integridade** das notificações enviadas pelo nosso sistema, todos os webhooks são assinados utilizando um segredo compartilhado (*webhook secret*), que realiza a assinatura do payload via HMAC SHA-256.

#### **📌 Como funciona**

Cada requisição enviada contém:

* O **payload** (corpo da requisição)
* Um header HTTP:

```
X-Signature: {assinatura}
```

Essa assinatura é gerada aplicando um **HMAC SHA-256** sobre o payload bruto utilizando o *token de segurança* configurado:

![image.png](/files/YhXiDhb3tPkAplKkDFX4)

***

#### **🎯 Objetivo da validação**

O sistema receptor deve validar a assinatura para garantir:

* ✔️ Que o payload **não foi alterado** (integridade)
* ✔️ Que a requisição foi **enviada por um remetente confiável** (autenticidade)
* ✔️ Que a comunicação é **segura contra ataques de replay ou spoofing**

***

### **⚙️ Passo a passo para validação**

Ao receber o webhook, seu sistema deve:

1. **Ler o payload bruto da requisição**
   * Importante: não utilize payload já parseado (ex: JSON decodificado)
2. **Obter o header `X-Signature`**
3. **Gerar uma nova assinatura localmente**
   * Utilizando:
     * O payload bruto
     * O *secret* compartilhado
4. **Comparar as assinaturas**
   * Utilize comparação segura (*timing-safe comparison*)
5. **Rejeitar a requisição caso a assinatura seja inválida**
   * Retorne HTTP `403 Forbidden`

***

### **💻 Exemplo em PHP (Laravel)**

```php
$payload = request()->getContent();
$secret = 'xuiq12' // aqui vai o token que é exibido na criação do webhook

$receivedSignature = request()->header('x-signature');

$expectedSignature = hash_hmac('sha256', $payload, $secret);

if (! hash_equals($expectedSignature, $receivedSignature)) {
    abort(403, 'Invalid signature');
}
```

### **💻 Exemplo em NodeJS**

```javascript
const crypto = require('crypto');
const express = require('express');

const app = express();

// ⚠️ Importante: precisamos do payload bruto
app.use(express.raw({ type: '*/*' }));

const SECRET = process.env.WEBHOOK_SECRET;

app.post('/webhook', (req, res) => {
    const payload = req.body; // Buffer (raw)
    const receivedSignature = req.header('x-signature');

    const expectedSignature = crypto
        .createHmac('sha256', SECRET)
        .update(payload)
        .digest('hex');

    const isValid = crypto.timingSafeEqual(
        Buffer.from(expectedSignature),
        Buffer.from(receivedSignature || '')
    );

    if (!isValid) {
        return res.status(403).send('Invalid signature');
    }

    // ✅ assinatura válida → processar webhook
    console.log('Webhook válido:', payload.toString());

    res.status(200).send('OK');
});

app.listen(3000, () => {
    console.log('Server running on port 3000');
});
```

***

### ⚠️ Boas práticas (importante)

#### 1. Use sempre o payload bruto

Qualquer transformação (ex: `json_decode` → `json_encode`) pode invalidar a assinatura.

***

#### 2. Nunca use comparação simples (`===`)

Utilize sempre:

```
hash_equals()
```

***

#### 3. Proteja seu webhook secret

* Nunca exponha no frontend
* Armazene em variáveis de ambiente seguras

***

#### 4. Valide antes de processar

A validação da assinatura deve ser o **primeiro passo** antes de qualquer lógica de negócio
