Sicurezza Webhook
Tutte le consegne webhook sono firmate usando HMAC-SHA256 così puoi verificare che le richieste provengano realmente da Replicer.
Meccanismo di firma
Ogni endpoint webhook ha un signing secret univoco (mostrato una sola volta alla creazione). Replicer firma ogni payload con questo secret e include la firma nell'header X-Replicer-Signature.
La firma viene calcolata come:
HMAC-SHA256(signing_secret, request_body)Verificare le firme
Node.js
javascript
import crypto from 'crypto'
function verifyWebhookSignature(payload, signature, secret) {
const expected = crypto
.createHmac('sha256', secret)
.update(payload)
.digest('hex')
return crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(expected)
)
}
// Middleware Express
app.post('/webhook', express.raw({ type: 'application/json' }), (req, res) => {
const signature = req.headers['x-replicer-signature']
const secret = process.env.WEBHOOK_SECRET
if (!verifyWebhookSignature(req.body, signature, secret)) {
return res.status(401).json({ error: 'Firma non valida' })
}
const event = JSON.parse(req.body)
// Processa l'evento...
res.status(200).json({ received: true })
})Python
python
import hmac
import hashlib
def verify_webhook(payload: bytes, signature: str, secret: str) -> bool:
expected = hmac.new(
secret.encode(),
payload,
hashlib.sha256
).hexdigest()
return hmac.compare_digest(signature, expected)
# Esempio Flask
@app.route('/webhook', methods=['POST'])
def webhook():
signature = request.headers.get('X-Replicer-Signature')
secret = os.environ['WEBHOOK_SECRET']
if not verify_webhook(request.data, signature, secret):
return jsonify({'error': 'Firma non valida'}), 401
event = request.get_json()
# Processa l'evento...
return jsonify({'received': True}), 200Go
go
func verifySignature(payload []byte, signature, secret string) bool {
mac := hmac.New(sha256.New, []byte(secret))
mac.Write(payload)
expected := hex.EncodeToString(mac.Sum(nil))
return hmac.Equal([]byte(signature), []byte(expected))
}Header aggiuntivi
Usa questi header per una verifica extra:
| Header | Descrizione |
|---|---|
X-Replicer-Timestamp | Timestamp Unix di quando l'evento è stato inviato |
X-Replicer-Delivery-Id | ID univoco per questo tentativo di consegna |
X-Replicer-Event | Tipo di evento (es. call.ended) |
Best practice
Raccomandazioni di sicurezza
- Verifica sempre le firme prima di processare gli eventi webhook
- Usa
timingSafeEqual(o equivalente) per prevenire timing attack - Conserva i secret in modo sicuro in variabili d'ambiente o secret manager
- Rispondi rapidamente — processa in modo asincrono e restituisci
200immediatamente - Sii idempotente — potresti ricevere lo stesso evento più volte a causa dei retry
- Controlla il timestamp — rifiuta eventi più vecchi di 5 minuti per prevenire replay attack
Verifica del timestamp
Per prevenire replay attack, verifica l'header X-Replicer-Timestamp:
javascript
const timestamp = parseInt(req.headers['x-replicer-timestamp'])
const now = Math.floor(Date.now() / 1000)
const fiveMinutes = 5 * 60
if (Math.abs(now - timestamp) > fiveMinutes) {
return res.status(401).json({ error: 'Timestamp troppo vecchio' })
}
