view-source: — c’est la seule commande nécessaire pour trouver la clé d’API d’un service météo agricole intégrée à un thème viticole personnalisé. Le widget affichait les prévisions de gel et de précipitations sur la page d’accueil du domaine, une fonctionnalité appréciée des visiteurs et utile pour planifier les visites de la propriété. Mais la clé qui interrogeait le service météo tiers était écrite directement dans un fichier JavaScript chargé publiquement.
Ce type de fuite ne vient presque jamais d’une intention négligente : un développeur teste rapidement une intégration, oublie de déplacer la clé côté serveur, et le code part en production tel quel. La suite de cet article ne traite pas de la migration générale des clés vers des variables d’environnement, déjà documentée ailleurs : il se concentre sur ce cas précis et sur le correctif immédiat.
Comment la fuite a été repérée
Le domaine a reçu une notification du fournisseur météo signalant un usage anormalement élevé de son quota d’appels, en pleine nuit, alors que le trafic du site restait faible à cette heure. En inspectant les journaux d’appels côté fournisseur, l’adresse IP d’origine ne correspondait à aucun serveur du domaine : un tiers avait extrait la clé du code source public et l’utilisait pour ses propres besoins, à l’insu du site viticole.
La faille dans le thème

Le fichier en cause ressemblait à ceci, chargé par wp_enqueue_script() sans aucune protection :
function domaine_meteo_widget() {
fetch('https://api.meteo-agri.example/v1/forecast?key=abcd1234EXPOSEE⪫=44.8&lon;=-0.5')
.then(r => r.json())
.then(data => afficherPrevisions(data));
}
Toute personne ouvrant les outils de développement du navigateur, ou même simplement le code source de la page, pouvait copier cette URL et l’utiliser depuis n’importe où. Aucune restriction par domaine référent n’avait été configurée côté fournisseur, ce qui a facilité l’exploitation.
Le correctif appliqué
La solution retenue déplace l’appel côté serveur, via un point de terminaison REST propre au site, qui interroge le service météo avec la clé stockée dans la configuration serveur et renvoie uniquement les données de prévision au navigateur :
add_action('rest_api_init', function () {
register_rest_route('domaine/v1', '/meteo', array(
'methods' => 'GET',
'callback' => 'domaine_meteo_proxy',
'permission_callback' => '__return_true',
));
});
function domaine_meteo_proxy() {
$cle = defined('METEO_AGRI_CLE') ? METEO_AGRI_CLE : '';
$reponse = wp_remote_get(
"https://api.meteo-agri.example/v1/forecast?key={$cle}⪫=44.8&lon;=-0.5"
);
if (is_wp_error($reponse)) {
return new WP_REST_Response(array('erreur' => 'indisponible'), 502);
}
return json_decode(wp_remote_retrieve_body($reponse));
}
Le navigateur n’a plus jamais accès à la clé : il interroge /wp-json/domaine/v1/meteo, et c’est le serveur WordPress qui porte l’appel externe avec ses propres identifiants, protégés hors de portée du public.
Ce qui a été fait auprès du fournisseur
Le fournisseur météo a révoqué l’ancienne clé et une nouvelle a été générée. Sur cette famille de services, il est courant de pouvoir restreindre une clé à une liste de domaines référents autorisés : cette option, ignorée lors de la première intégration, a été activée en complément du proxy côté serveur, en défense en profondeur.
Un réflexe à généraliser
Toute intégration qui affiche une donnée provenant d’un service tiers mérite la même question : la clé transite-t-elle par le navigateur, ou reste-t-elle sur le serveur ? Dès qu’un appel fetch ou XMLHttpRequest contient un paramètre nommé key, token ou api_key directement dans son URL visible côté client, il s’agit d’un signal d’alerte à traiter avant la mise en production, pas après un pic d’usage suspect.
En résumé
Une clé d’API exposée dans un thème n’est jamais un problème abstrait : elle se traduit par une facture inattendue, un quota épuisé ou, pire, un accès détourné à des fonctionnalités payantes. Le réflexe du proxy côté serveur, couplé à la restriction par domaine référent côté fournisseur, referme durablement ce type de faille pour un coût de développement modeste.