Passer au contenu
Français
  • Il n'y a aucune suggestion car le champ de recherche est vide.

Comment sécuriser vos webhooks smsmode ?

Protégez votre URL de callback contre les fausses notifications : signature HMAC SHA-256, user-agent, headers personnalisés et exemples Node.js, PHP, Python.

 

1. Introduction


Un **webhook** est une notification envoyée automatiquement par smsmode vers une URL que vous nous avez indiquée, dès qu'un événement se produit sur votre compte (par exemple : un accusé de réception de SMS, un changement de statut de campagne, etc.).

Sans protection, n'importe qui connaissant l'adresse de votre URL de callback pourrait potentiellement vous envoyer de fausses notifications et se faire passer pour smsmode.

Cette page présente les deux méthodes de sécurisation disponibles, ainsi qu'une nouveauté récente : un **User Agent fixe** identifiant nos appels.


2. Vue d'ensemble


| Méthode | Niveau de sécurité | Complexité de mise en œuvre |
|---|---|---|
| Headers HTTP personnalisés | Basique | Faible |
| Signature cryptographique (HMAC SHA-256) | Élevé | Modérée |

Ces deux méthodes ne sont pas mutuellement exclusives : elles peuvent être combinées pour renforcer la sécurité de vos intégrations.

3. Méthode 1 — Les headers HTTP personnalisés


Le principe

Vous définissez jusqu'à **2 headers HTTP personnalisés** (un nom et une valeur de votre choix). Ces headers sont automatiquement ajoutés à chaque appel de callback envoyé vers votre URL.

Vérification côté client

Votre serveur doit simplement contrôler, à la réception de chaque webhook, que ces headers sont présents et que leur valeur correspond exactement à celle que vous avez configurée. Si ce n'est pas le cas, la requête doit être rejetée.

Limites à connaître

Cette méthode repose sur une valeur statique. Si cette valeur venait à être interceptée ou devinée, elle pourrait être réutilisée par un tiers malveillant. Elle convient donc à un besoin de sécurité basique, mais n'est **pas recommandée seule** pour des flux sensibles.

4. Méthode 2 — La signature cryptographique (recommandée)


Le principe, en langage simple :

À chaque callback, smsmode calcule une "empreinte" unique du contenu envoyé. Cette empreinte permet à votre serveur de vérifier deux choses :
- que le message provient bien de smsmode,
- qu'il n'a pas été modifié en chemin.


Comment ça fonctionne chez smsmode ?

1. **En amont**, vous définissez une **clé secrète**, connue uniquement de vous et de smsmode.
2. **À chaque appel**, smsmode calcule un hash **HMAC-SHA256** du corps (body) de la requête, en utilisant cette clé secrète.
3. Le résultat est transmis dans un **header HTTP fixe et dédié** : `X-Smsmode-256`.


Vérification côté client

Pour valider un webhook :

1. Récupérez le corps brut (raw body) de la requête reçue, **avant tout parsing JSON**.
2. Recalculez le HMAC-SHA256 de ce body avec votre clé secrète.
3. Comparez le résultat obtenu à la valeur du header `X-Smsmode-256`.
4. Si les deux valeurs sont identiques, l'appel est authentique et intègre. Sinon, il doit être rejeté.


Pourquoi c'est plus robuste :

Même si un tiers connaît votre URL de callback, il lui est impossible de forger une signature valide sans connaître votre clé secrète.

⚠️ **Important** :
la comparaison des deux signatures doit idéalement se faire via une fonction de comparaison à temps constant (*constant-time comparison*) plutôt qu'un simple `==`, afin d'éviter les attaques par mesure de temps (*timing attacks*).


5. Nouveauté — User Agent fixe


Qu'est-ce qu'un User Agent ?

C'est un identifiant transmis par tout appel HTTP, indiquant "qui" ou "quoi" est à l'origine de la requête.

Valeur smsmode (User Agent)

Tous les appels de webhook émis par smsmode portent désormais le User Agent suivant :

```

smsmode-Webhooks/1.0 (+https://dev.smsmode.com)

```


À quoi ça sert concrètement

- Faciliter le filtrage ou l'allow-listing sur vos pare-feux, WAF ou reverse-proxy.
- Identifier plus facilement le trafic smsmode dans vos journaux (logs).

⚠️ Point d'attention important
Le User Agent est une information **déclarative et facilement falsifiable**. Il ne doit **jamais être utilisé seul** comme mécanisme de sécurité, mais uniquement en complément des méthodes 1 ou 2 décrites plus haut.


6. Bonnes pratiques recommandées

- Privilégiez la **signature cryptographique** pour tout flux métier sensible.
- Vérifiez systématiquement que les appels arrivent en **HTTPS**.
- Combinez plusieurs méthodes pour une défense en profondeur (signature + header personnalisé + filtrage User Agent).
- Ne considérez jamais l'URL de votre endpoint comme un secret suffisant en soi.

ℹ️ **À noter** :
à ce jour, smsmode ne définit pas de politique de durée de vie (rotation) pour les clés secrètes utilisées dans le calcul de signature. Cette information sera complétée dès qu'une recommandation officielle sera disponible.

7. Encart développeur — Exemple de vérification de signature


Voici un exemple de vérification du header `X-Smsmode-256` dans trois langages courants. Le principe est identique partout : recalculer le HMAC-SHA256 du **body brut** avec votre clé secrète, puis comparer au header reçu.

Node.js


const crypto = require('crypto');

function verifySmsmodeSignature(rawBody, receivedSignature, secretKey) {
  const expectedSignature = crypto
    .createHmac('sha256', secretKey)
    .update(rawBody, 'utf8')
    .digest('hex');

  // Comparaison à temps constant pour éviter les timing attacks
  const expectedBuffer = Buffer.from(expectedSignature, 'hex');
  const receivedBuffer = Buffer.from(receivedSignature, 'hex');

  if (expectedBuffer.length !== receivedBuffer.length) {
    return false;
  }

  return crypto.timingSafeEqual(expectedBuffer, receivedBuffer);
}

// Exemple d'utilisation dans un handler Express
app.post('/webhooks/smsmode', express.raw({ type: '*/*' }), (req, res) => {
  const signature = req.headers['x-smsmode-256'];
  const isValid = verifySmsmodeSignature(req.body, signature, process.env.SMSMODE_SECRET_KEY);

  if (!isValid) {
    return res.status(401).send('Signature invalide');
  }

  // Traitement du webhook...
  res.status(200).send('OK');
});

PHP :

<?php

function verifySmsmodeSignature(string $rawBody, string $receivedSignature, string $secretKey): bool
{
    $expectedSignature = hash_hmac('sha256', $rawBody, $secretKey);

    // hash_equals() effectue une comparaison à temps constant
    return hash_equals($expectedSignature, $receivedSignature);
}

// Exemple d'utilisation
$rawBody = file_get_contents('php://input');
$receivedSignature = $_SERVER['HTTP_X_SMSMODE_256'] ?? '';
$secretKey = getenv('SMSMODE_SECRET_KEY');

if (!verifySmsmodeSignature($rawBody, $receivedSignature, $secretKey)) {
    http_response_code(401);
    exit('Signature invalide');
}

// Traitement du webhook...
http_response_code(200);

Python :

import hashlib
import hmac
import os
from flask import Flask, request

app = Flask(__name__)

def verify_smsmode_signature(raw_body: bytes, received_signature: str, secret_key: str) -> bool:
    expected_signature = hmac.new(
        secret_key.encode('utf-8'),
        raw_body,
        hashlib.sha256
    ).hexdigest()

    # Comparaison à temps constant
    return hmac.compare_digest(expected_signature, received_signature)

@app.route('/webhooks/smsmode', methods=['POST'])
def handle_webhook():
    raw_body = request.get_data()
    signature = request.headers.get('X-Smsmode-256', '')
    secret_key = os.environ.get('SMSMODE_SECRET_KEY')

    if not verify_smsmode_signature(raw_body, signature, secret_key):
        return 'Signature invalide', 401

    # Traitement du webhook...
    return 'OK', 200

Points d'attention communs aux 3 exemples

- Toujours utiliser le **body brut** (raw), avant toute désérialisation JSON — un re-sérialisation peut modifier l'ordre des clés ou les espaces, et donc invalider le hash.

- Toujours utiliser une fonction de **comparaison à temps constant** (`crypto.timingSafeEqual`, `hash_equals`, `hmac.compare_digest`).

- Stocker la clé secrète dans une variable d'environnement ou un coffre-fort de secrets, jamais en dur dans le code.

8. FAQ

Que se passe-t-il si je ne vérifie pas la signature ?

Le webhook sera tout de même envoyé, mais votre système restera vulnérable à des appels frauduleux se faisant passer pour smsmode.

Où configurer ma clé secrète et mes headers personnalisés ?

Depuis votre espace client dans la section [Paramètres / Webhooks](https://ui.smsmode.com/settings/dev)

 

Existe-t-il une durée de vie recommandée pour ma clé secrète ?

 

Non, aucune politique de rotation n'est définie à ce jour côté smsmode. Cette section sera mise à jour dès qu'une recommandation sera formalisée.