web-dev-qa-db-fra.com

Comment puis-je vérifier si AJAX les nonces sont implémentés correctement?

J'ai un simple bouton "post favori" qui fonctionne avec AJAX. Je comprends que l’utilisation d’un nonce WordPress améliore la sécurité, mais je ne sais pas trop pourquoi ni comment. Cela me rend également incapable de vérifier si j'ai implémenté le nonce correctement et en toute sécurité.

jQuery Script

function favorites_javascript() {       
    $ajax_nonce = wp_create_nonce( "ajax-nonce-favorites" );

    ?>

    <script>
        ( function( $ ) {               
            var ajaxurl = "<?php echo admin_url('admin-ajax.php'); ?>";

            // ...

            // Data to be sent to function
            var data = {
                'action': 'favorites_callback',
                'security': '<?php echo $ajax_nonce; ?>',

                'post_id': post_id,
                'button_action' : button_action
            };

            // Send Data
            jQuery.post(ajaxurl, data, function(response) {     

                // ...

            });

            // ...

        } )( jQuery );
    </script> 

    <?php
} add_action( 'wp_footer', 'favorites_javascript' );

Rappel PHP

function favorites_callback() {
    check_ajax_referer( 'ajax-nonce-favorites', 'security' );

    if ( !is_user_logged_in() ) {
        wp_send_json_error( 'Error!' );
    }

    // Process Data

    wp_die();
} add_action( 'wp_ajax_favorites_callback', 'favorites_callback' );

Est-ce la bonne implémentation de WordPress nonce pour AJAX? Et comment puis-je "tester" ce code pour voir si le nonce fonctionne et est sécurisé?

1
Swen

Votre code est incorrect de manière subtile, mais pour comprendre pourquoi nous devons d’abord revenir à ce qui est un nonce dans wordpress et contre quoi il protège.

Un nonce selon la définition commune est un nombre utilisé une seule fois et est destiné à combattre les attaques par rejeu. Dans une attaque par rejeu, vous ne faites que rejouer une transaction (demande http) sans comprendre son composant pour refaire une action de l'utilisateur. Un exemple simple où cela peut conduire à une mauvaise situation est si quelqu'un pouvait rejouer vos commandes d'achat et vous faire commander plus de la même chose sans que vous soyez impliqué. Situation typique, vous utilisez le réseau de quelqu'un d'autre (ne savez pas si SSL aide ou pas ici).

Il a également été découvert que les nonce sont un bon moyen d’éviter les attaques CSRF car il est difficile de prédire l’URL/les paramètres que l’attaquant doit utiliser.

Dans wordpress, l'ordre d'importance est inversé, la première priorité étant de lutter contre les attaques CSRF et de combattre les attaques en répétition n'a qu'une importance secondaire. Cela conduit les mots presse à ne pas être un nombre "unique par jour" au lieu du nombre classique "une fois".

alors, comment Wordpress utilise-t-il des nonces pour se protéger de CSRF? il génère un nonce basé sur le contexte. Vous pouvez voir dans le code wp_create_nonce

function wp_create_nonce($action = -1) {
    $user = wp_get_current_user();
    $uid = (int) $user->ID;
    if ( ! $uid ) {
        /** This filter is documented in wp-includes/pluggable.php */
        $uid = apply_filters( 'nonce_user_logged_out', $uid, $action );
    }

    $token = wp_get_session_token();
    $i = wp_nonce_tick();

    return substr( wp_hash( $i . '|' . $action . '|' . $uid . '|' . $token, 'nonce' ), -12, 10 );
}

Que le contexte soit le nom de l'action, l'identifiant de l'utilisateur et la session de connexion en cours, ce qui garantit qu'un nonce différent sera généré pour différentes actions, différents utilisateurs et même différentes sessions du même utilisateur, et ce même si quelqu'un connaît le nonce utilisé pour faire une action (disons, supprimer un post) lorsqu'il le fait avec son propre utilisateur, il ne pourra pas vous inciter à supprimer un post en construisant une URL spéciale avec le même nonce.

Et voici votre première erreur (ce que beaucoup font), qui consiste à appliquer des nonces à des utilisateurs non connectés. Sans un contexte utilisateur, la totalité de la nonce est uniquement dérivée de l'action et un "attaquant" peut simplement partager la même adresse URL que les utilisateurs non connectés (ou un bot) peuvent utiliser.

Comment vérifier que votre code fonctionne correctement pour empêcher CSRF? s'il s'agit d'une simple URL, essayez de le renvoyer lorsque vous êtes connecté en tant qu'utilisateur différent. Il est plus facile de faire avec des requêtes dans lesquelles l'URL elle-même contient le nonce, mais peut probablement être fait avec des outils de développement de navigateur (changer les cookies d'authentification et renvoyer) ou curl/wget.

L'autre élément dans lequel votre code manque est une protection contre une sorte d'attaque par rejeu. En supposant que je sache que vous avez aimé la publication X, puis-je transmettre la demande et la faire voir comme vous avez aimé également la publication Y? Pour le moment, tout ce que j'ai à faire est simplement de changer le paramètre post_id de la demande.

Le moyen de se protéger contre ce type d'attaques consiste à faire en sorte que la partie action de la nonce soit dynamique et inclue d'une certaine manière les paramètres importants, dans votre cas l'identifiant de poste. Core utilise généralement des actions du type delete-post-{post_id}, ce qui garantit qu'un nonce différent sera généré pour différentes publications.

Comment tester? A l'aide des outils de développement du navigateur, modifiez le paramètre post id pour vous assurer que le même nonce ne peut pas être utilisé pour mettre en favori une publication différente.

Pour le type de test phpunit , vous voudrez probablement écrire votre propre générateur de nonce qui enveloppe les fonctions de base de nonce wordpress et vérifier qu'elles ne donnent pas le même nonce pour différents utilisateurs, différentes sessions, différentes actions et différents paramètres de demande de clé.

1
Mark Kaplun

Une lecture à ce sujet dans le WP Codex semble indiquer que la mise en œuvre est correcte.

Un simple test consisterait à créer une demande ajax "falsifiée" sans paramètre security dans $.ajax() ou à effectuer la même demande avec un nonce pris à partir d'une heure et d'une page différentes.

(qu'est-ce qu'un nonce, pour référence: wiki )

2
Fabrizio Mele