Le WordPress d'aujourd'hui, décodé pour les développeurs

Hébergement & serveurs

Twilio et WordPress : sécuriser les webhooks SMS derrière le pare-feu du serveur

Recevoir les accusés de réception SMS de Twilio suppose d'ouvrir une route sur le serveur : comment le faire sans exposer inutilement l'infrastructure derrière le pare-feu.

Par WordPress Développement • 8 juin 2021 • 4 min de lecture • Aucun commentaire
Twilio et WordPress : sécuriser les webhooks SMS derrière le pare-feu du serveur

« Comment recevoir un webhook externe sans percer un trou béant dans le pare-feu ? » C’est la question que pose systématiquement l’intégration de Twilio pour l’envoi de SMS de confirmation depuis un site WordPress : Twilio doit pouvoir notifier le serveur du statut de livraison de chaque SMS, ce qui suppose une route HTTP accessible depuis l’extérieur, or le pare-feu du serveur bloque par défaut tout ce qui n’est pas explicitement autorisé.

La tentation la plus rapide, ouvrir largement le port HTTP entrant sans restriction, fonctionne mais expose inutilement l’ensemble du serveur. La bonne approche combine plusieurs couches de protection plutôt qu’une ouverture large, sans que cela complique réellement la configuration du plugin SMS lui-même, qui n’est pas le sujet ici.

Comprendre ce que Twilio a besoin d’atteindre

Twilio contacte le serveur uniquement pour deux usages : recevoir un SMS entrant (si le numéro est configuré pour cela) et notifier le statut de livraison d’un SMS sortant via un callback configuré dans la console Twilio. Dans les deux cas, l’appel provient exclusivement des plages d’adresses IP publiées officiellement par Twilio, ce qui rend possible un filtrage strict côté pare-feu, contrairement à un webhook dont l’origine serait imprévisible.

Première couche : liste blanche d’IP au niveau du pare-feu

L'essentiel à retenir : Le webhook Twilio doit rester joignable sans exposer le reste du serveur ; Une liste blanche d'IP limite l'accès aux seules plages Twilio publiées ; La validation de signature X-Twilio-Signature complète le filtrage réseau

La première protection consiste à n’autoriser l’accès à la route du webhook qu’aux plages IP publiées par Twilio, en bloquant tout le reste par défaut. Avec un pare-feu applicatif type nginx en amont, cela se traduit par un bloc dédié qui restreint l’accès avant même que la requête n’atteigne WordPress :

location /wp-json/mon-plugin-sms/v1/statut {
    allow 54.172.60.0/23;
    allow 54.244.51.0/24;
    # ... autres plages Twilio à jour
    deny all;
    try_files $uri /index.php?$args;
}

Il faut vérifier régulièrement la liste à jour des plages IP Twilio publiée dans leur documentation, ces plages pouvant évoluer. Un renouvellement d’infrastructure côté Twilio sans mise à jour de la liste blanche peut bloquer silencieusement les callbacks de statut.

Deuxième couche : un point d’entrée dédié, pas générique

Plutôt que de faire transiter le webhook par une route WordPress générique (comme admin-ajax.php, ciblée en permanence par des robots), mieux vaut exposer une route REST dédiée et peu devinable, via register_rest_route(), avec un espace de nom spécifique au projet.

add_action( 'rest_api_init', function () {
    register_rest_route( 'mon-plugin-sms/v1', '/statut', array(
        'methods'             => 'POST',
        'callback'            => 'traiter_statut_twilio',
        'permission_callback' => '__return_true',
    ) );
} );

Le permission_callback reste ouvert ici volontairement, car Twilio n’envoie pas d’identifiants WordPress : c’est la validation de signature, décrite ci-dessous, qui authentifie réellement l’appelant, pas un système de permission WordPress classique.

Troisième couche : valider la signature Twilio

Chaque requête envoyée par Twilio inclut un en-tête X-Twilio-Signature, calculé à partir de l’URL complète, des paramètres envoyés et du jeton d’authentification secret du compte. Vérifier cette signature dans le callback confirme que la requête provient bien de Twilio, même si elle passe le filtrage IP.

function traiter_statut_twilio( WP_REST_Request $request ) {
    $signature = $request->get_header( 'x_twilio_signature' );
    $url       = home_url( '/wp-json/mon-plugin-sms/v1/statut' );
    $params    = $request->get_body_params();

    if ( ! twilio_signature_valide( $signature, $url, $params ) ) {
        return new WP_Error( 'signature_invalide', 'Refusé', array( 'status' => 403 ) );
    }
    // traitement du statut de livraison
}

Ce qu’il ne faut pas ouvrir

  • Ne jamais ouvrir tout le port 443 sans restriction sous prétexte de simplifier l’intégration
  • Ne jamais désactiver le pare-feu applicatif sur la route webhook pour « voir si ça marche »
  • Ne jamais journaliser le corps complet des requêtes Twilio en clair, il peut contenir des numéros de téléphone de clients

Le réflexe le plus sûr face à un webhook externe : traiter chaque couche de protection comme indépendante des autres. Si la liste blanche d’IP échoue un jour, la validation de signature doit à elle seule suffire à bloquer une requête frauduleuse.

En résumé

Sécuriser les webhooks Twilio derrière le pare-feu d’un serveur WordPress ne demande pas de renoncer à la sécurité pour la commodité : une liste blanche d’IP à jour, un point d’entrée REST dédié plutôt qu’une route générique, et une validation systématique de la signature Twilio suffisent à limiter drastiquement la surface d’exposition. Ces trois couches, combinées, protègent le serveur sans jamais bloquer les notifications de statut légitimes envoyées par Twilio.

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *

Partager :

À propos de l'auteur

WordPress Développement

Développeur WordPress, passionné par Elementor, le FSE et l’automatisation par IA.

Voir tous ses articles

Dans la même veine

À lire aussi