vendredi 25 septembre 2026

À propos

Contact

Sécurité

Sécuriser une clé API en base avec un hachage indépendant du sel WordPress

Générer un chiffrement dérivé qui ne dépend pas uniquement des salts WordPress, pour survivre à leur renouvellement sans casser les clés API déjà stockées.

Par Clément Hadrot • 25 septembre 2021 • 6 min de lecture • Aucun commentaire
Sécuriser une clé API en base avec un hachage indépendant du sel WordPress

Une extension maison développée pour un client synchronise un catalogue produit avec un service tiers via une clé API, que l’extension doit stocker de façon réversible (contrairement à un mot de passe, elle doit pouvoir être relue pour être envoyée à chaque appel). Le développeur précédent avait choisi une solution rapide : chiffrer la clé avec la fonction openssl_encrypt() en utilisant directement la constante AUTH_KEY définie dans wp-config.php comme clé de chiffrement.

Six mois plus tard, à l’occasion d’une rotation de sécurité recommandée par notre check-list (le remplacement périodique des salts d’authentification, une bonne pratique par ailleurs), la synchronisation cesse brutalement de fonctionner. La clé API stockée en base devient illisible : elle a été chiffrée avec l’ancienne valeur de AUTH_KEY, et le déchiffrement avec la nouvelle valeur ne renvoie que des octets incohérents. Le client doit ressaisir sa clé API manuellement, un incident mineur mais révélateur d’un défaut de conception plus profond.

Pourquoi s’appuyer directement sur les salts est fragile

Les constantes AUTH_KEY, SECURE_AUTH_KEY, LOGGED_IN_KEY, NONCE_KEY (et leurs équivalents _SALT) définies dans wp-config.php ont un rôle précis dans WordPress : elles servent à signer les cookies d’authentification et à générer les nonces. Leur rotation régulière est justement une recommandation de sécurité, documentée par WordPress lui-même via le générateur officiel de salts, précisément parce qu’un changement périodique limite la fenêtre d’exploitation en cas de fuite. Ces constantes sont donc, par conception, faites pour changer.

Utiliser directement l’une d’elles comme clé de chiffrement pour des données applicatives crée une dépendance cachée et dangereuse : la moindre rotation de salt, recommandée par ailleurs, casse silencieusement tout ce qui a été chiffré avec l’ancienne valeur. Le développeur qui effectue la rotation n’a généralement aucune raison de soupçonner un lien avec une extension tierce sans rapport apparent avec l’authentification.

Construire une clé de chiffrement dérivée et stable

L'essentiel à retenir : Les salts WordPress peuvent changer à tout moment ; Une clé de chiffrement dérivée doit vivre indépendamment ; Toujours prévoir la rotation sans perte de données

La solution ne consiste pas à abandonner les salts WordPress, qui restent une source d’entropie légitime et déjà présente sur toute installation, mais à en dériver une clé propre à l’extension, stockée séparément et non affectée par une rotation ultérieure des salts eux-mêmes :

function moncpt_obtenir_cle_chiffrement() {
    $cle = get_option( 'moncpt_cle_chiffrement_interne' );

    if ( false === $cle ) {
        // Génération unique, au premier besoin, à partir d'une source
        // aléatoire cryptographiquement sûre — pas des salts WordPress.
        $cle = base64_encode( random_bytes( 32 ) );
        add_option( 'moncpt_cle_chiffrement_interne', $cle, '', false );
    }

    return base64_decode( $cle );
}

function moncpt_chiffrer_cle_api( $valeur_en_clair ) {
    $cle = moncpt_obtenir_cle_chiffrement();
    $iv  = random_bytes( openssl_cipher_iv_length( 'aes-256-cbc' ) );

    $chiffre = openssl_encrypt( $valeur_en_clair, 'aes-256-cbc', $cle, OPENSSL_RAW_DATA, $iv );

    // IV stocké avec le texte chiffré : nécessaire au déchiffrement,
    // il n'a pas besoin d'être secret, seulement unique par opération.
    return base64_encode( $iv . $chiffre );
}

function moncpt_dechiffrer_cle_api( $valeur_stockee ) {
    $cle       = moncpt_obtenir_cle_chiffrement();
    $donnees   = base64_decode( $valeur_stockee );
    $longueur_iv = openssl_cipher_iv_length( 'aes-256-cbc' );
    $iv        = substr( $donnees, 0, $longueur_iv );
    $chiffre   = substr( $donnees, $longueur_iv );

    return openssl_decrypt( $chiffre, 'aes-256-cbc', $cle, OPENSSL_RAW_DATA, $iv );
}

La clé de chiffrement interne, générée une seule fois via random_bytes() et stockée dans une option dédiée, ne dépend plus jamais des constantes de salt. Une rotation de AUTH_KEY ne casse plus rien, puisque la fonction n’y fait plus référence.

Où stocker cette clé de chiffrement elle-même

Un contre-argument légitime se pose immédiatement : si la clé de chiffrement est elle-même stockée dans wp_options, aux côtés des données qu’elle protège, un accès en lecture à la base de données suffit à tout déchiffrer, salts ou pas. C’est exact, et c’est une limite assumée de ce niveau de protection : il ne protège pas contre un accès complet à la base de données, mais contre des scénarios plus fréquents en pratique — une fuite partielle limitée à une table, une sauvegarde de base exportée sans les fichiers, ou un accès en lecture seule obtenu via une injection SQL qui ne permettrait pas d’atteindre le système de fichiers.

Pour un niveau de protection supérieur, la clé peut être définie comme constante dans wp-config.php plutôt que dans une option, ce qui la sépare physiquement de la base de données :

// Dans wp-config.php, générée une seule fois et jamais renouvelée
// sans procédure de migration explicite des données chiffrées existantes.
define( 'MONCPT_CLE_CHIFFREMENT', 'valeur-generee-aleatoirement-une-seule-fois' );

Ce choix déplace le problème initial plutôt que de le supprimer complètement : cette nouvelle constante ne doit alors, elle, jamais tourner sans un plan de migration explicite des données déjà chiffrées — exactement la logique qu’on cherchait à éviter avec les salts d’authentification.

Prévoir la rotation malgré tout

Que la clé vive en option ou en constante, une procédure de rotation doit exister dès la conception plutôt que d’être improvisée après incident : déchiffrer toutes les valeurs concernées avec l’ancienne clé, chiffrer à nouveau avec la nouvelle, dans une seule transaction contrôlée, jamais par un simple remplacement de constante suivi d’un espoir que « ça continue de marcher ».

La leçon retenue sur ce projet : toute donnée dont la persistance dépasse la durée de vie d’un salt d’authentification mérite sa propre clé, indépendante, même si cela demande quelques lignes de plus au départ.

Ce que cet article ne couvre pas

Ce sujet ne traite pas du chiffrement via la bibliothèque Sodium, une alternative plus moderne à openssl_encrypt() disponible nativement depuis PHP 7.2, abordée dans un autre article dédié aux extensions cryptographiques. Le principe de séparation entre clé applicative et salts d’authentification reste néanmoins identique quel que soit l’outil de chiffrement choisi.

Partager :

À propos de l'auteur

Clément Hadrot

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

Voir tous ses articles

Dans la même veine

À lire aussi