Skip to content

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}), 200

Go ​

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:

HeaderDescrizione
X-Replicer-TimestampTimestamp Unix di quando l'evento è stato inviato
X-Replicer-Delivery-IdID univoco per questo tentativo di consegna
X-Replicer-EventTipo 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 200 immediatamente
  • 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' })
}

Replicer API Documentation