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

Sécurité

« Nonce verification failed » : la vraie durée de vie d’un nonce AJAX

Des soumissions légitimes se font rejeter avec un message de nonce invalide, alors que rien ne semble avoir changé côté formulaire. La cause tient à une hypothèse fausse sur sa durée de vie.

Par Clément Hadrot • 14 décembre 2025 • 4 min de lecture • Aucun commentaire
« Nonce verification failed » : la vraie durée de vie d'un nonce AJAX

« Nonce verification failed. » Ce message apparaît dans la console du navigateur après qu’un visiteur a laissé un onglet ouvert plusieurs heures avant de soumettre un formulaire, et le réflexe naturel est de suspecter une expiration trop rapide du nonce. Ce diagnostic, pourtant, part souvent d’une hypothèse fausse : un nonce WordPress ne dure pas quelques minutes, mais bien plus longtemps qu’on ne le pense en général.

Symptôme

Un formulaire de contact intégré en AJAX fonctionne parfaitement lors des tests, mais des utilisateurs signalent un rejet aléatoire de leur soumission avec le message 0 ou une réponse JSON contenant -1, accompagné dans les journaux serveur d’un échec de check_ajax_referer(). Le problème survient plus fréquemment pour les visiteurs qui laissent la page ouverte longtemps avant d’agir, ou qui reviennent sur un onglet resté inactif depuis la veille.

Diagnostic

L'essentiel à retenir : Un nonce reste valide 24 à 48 heures, pas quelques minutes ; Le cache de page peut servir un nonce périmé à un nouveau visiteur ; La solution combine exclusion du cache et régénération côté client

La documentation officielle de WordPress précise qu’un nonce reste valable pendant une « tick » de douze heures, et qu’une vérification reste acceptée sur deux ticks consécutifs — soit une fenêtre effective proche de vingt-quatre heures, parfois un peu plus selon le moment exact de génération. Un rejet après seulement quelques minutes d’inactivité ne peut donc pas s’expliquer par une expiration naturelle du nonce lui-même.

La cause réelle, dans ce cas précis, se trouvait ailleurs : un système de cache de page servait une version statique du formulaire à plusieurs visiteurs successifs, tous recevant le même nonce généré au moment de la mise en cache de la page. Dès que ce cache dépassait sa propre durée de vie sans être régénéré à temps, ou dès qu’un visiteur soumettait le formulaire longtemps après le premier chargement de la page en cache, le nonce reçu ne correspondait plus à celui attendu par la session active de vérification.

function domaine_contact_ajax() {
  check_ajax_referer('domaine_contact_nonce', 'nonce');
  // Le rejet se produit ici pour les pages servies depuis le cache.
}

Correctif

Deux changements complémentaires ont résolu le problème. D’abord, la page contenant le formulaire a été exclue du cache de page complet, en conservant uniquement la mise en cache des ressources statiques (images, styles), pour garantir qu’un nonce frais soit généré à chaque chargement réel :

add_action('init', function () {
  if (is_page('contact')) {
    define('DONOTCACHEPAGE', true);
  }
});

Ensuite, pour les cas où l’exclusion complète du cache n’était pas souhaitable sur d’autres pages utilisant le même formulaire, une régénération du nonce côté client a été ajoutée, déclenchée après un délai d’inactivité ou lors de la reprise de focus sur l’onglet :

add_action('rest_api_init', function () {
  register_rest_route('domaine/v1', '/nonce-frais', array(
    'methods'  => 'GET',
    'callback' => function () {
      return array('nonce' => wp_create_nonce('domaine_contact_nonce'));
    },
    'permission_callback' => '__return_true',
  ));
});

Le script du formulaire récupère un nonce actualisé juste avant la soumission si la page est ouverte depuis plus d’une heure, plutôt que de se fier uniquement au nonce injecté au chargement initial.

Prévention

Deux vérifications systématiques évitent de reproduire ce type d’incident sur un autre formulaire :

  • Vérifier qu’aucune page contenant un formulaire sensible à l’action n’est servie par un cache de page complet sans exclusion explicite.
  • Pour les formulaires susceptibles de rester ouverts longtemps avant soumission (devis, réservation, candidature), prévoir une régénération de nonce côté client plutôt que de se reposer uniquement sur sa durée de vie native.

Ce qu’il ne faut pas faire

Allonger artificiellement la durée de vie d’un nonce au-delà de ce que propose WordPress par défaut, en modifiant le filtre nonce_life vers une valeur très élevée, réduit la protection contre le rejeu sans résoudre la cause réelle du problème dans la plupart des cas de mise en cache mal configurée.

En résumé

Un rejet de nonce rapide n’est presque jamais dû à une expiration naturelle : la piste à privilégier en premier reste la mise en cache de page, qui fige un nonce généré à un instant donné et le sert ensuite à des contextes où il n’est plus valide. Exclure les pages sensibles du cache complet règle la grande majorité de ces cas.

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