it-swarm.com.de

Wie überprüfe ich, ob AJAX nonces sind korrekt implementiert?

Ich habe einen einfachen "Lieblingspost" -Button, der mit AJAX funktioniert. Ich verstehe, dass die Verwendung eines WordPress-Nonce die Sicherheit verbessert, bin mir aber nicht ganz sicher, warum oder wie dies geschieht. Dadurch kann ich auch nicht überprüfen, ob ich die Nonce korrekt und sicher implementiert habe.

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' );

PHP Callback

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' );

Ist dies die korrekte Implementierung von WordPress nonce für AJAX? Und wie "teste" ich diesen Code, um festzustellen, ob das Nonce funktioniert und sicher ist?

1
Swen

Ihr Code ist auf subtile Weise falsch, aber um herauszufinden, warum wir zuerst auf das zurückkommen müssen, was eine Nonce in WordPress ist und wovor es schützt.

Ein Nonce gemäß der allgemeinen Definition ist eine Zahl, die nur einmal verwendet wird und dazu gedacht ist, Wiederholungsangriffe abzuwehren. Bei einem Wiederholungsangriff wird lediglich eine Transaktion (http-Anforderung) wiederholt, ohne dass die Komponente zum Wiederholen einer Benutzeraktion bekannt ist. Ein einfaches Beispiel, bei dem es zu einer schlechten Situation kommen kann, besteht darin, dass jemand Ihre Einkaufsaufträge wiederholen und Sie dazu veranlassen könnte, mehr von dem Gleichen zu bestellen, ohne dass Sie involviert sind. Typische Situation, in der Sie das Netzwerk eines anderen Benutzers verwenden (nicht sicher, ob SSL hilft oder nicht).

Es wurde auch festgestellt, dass nonce eine gute Möglichkeit ist, CSRF Angriffe zu vermeiden, da es schwierig ist, die URL/Parameter vorherzusagen, die der Angreifer verwenden sollte.

In WordPress ist die Reihenfolge der Wichtigkeit umgekehrt, die erste Priorität ist die Bekämpfung von CSRF-Angriffen und die Bekämpfung von Replay-Angriffen hat nur eine untergeordnete Bedeutung. Dies führt dazu, dass WordPress-Nonces eine "einmalige" Nummer anstelle der klassischen "einmaligen" Nummer sind.

wie verwendet WordPress Nonces zum Schutz von CSRF? es erzeugt eine Nonce basierend auf dem Kontext. Sie können im wp_create_nonce Code sehen

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 );
}

Dass der Kontext der Aktionsname, die Benutzer-ID und die aktuelle Anmeldesitzung ist und dies sicherstellt, dass für verschiedene Aktionen, verschiedene Benutzer und sogar verschiedene Sitzungen desselben Benutzers eine andere Nonce generiert wird, selbst wenn jemand die verwendete Nonce kennt Wenn Sie eine Aktion ausführen (z. B. einen Beitrag löschen) und dies mit seinem eigenen Benutzer tun, kann er Sie nicht zum Löschen eines Beitrags verleiten, indem er eine spezielle URL mit derselben Nonce erstellt.

Und hier ist Ihr erster Fehler (den viele machen), der darauf abzielt, nicht angemeldete Benutzer mit Nonces zu belegen. Ohne Benutzerkontext wird der gesamte Nonce nur von der Aktion abgeleitet, und ein "Angreifer" kann nur dieselbe URL verwenden, die von nicht angemeldeten Benutzern (oder von einem Bot) verwendet wird.

Wie können Sie testen, ob Ihr Code beim Verhindern von CSRF ordnungsgemäß funktioniert? Wenn es sich um eine einfache URL handelt, versuchen Sie, sie erneut zu senden, wenn Sie als ein anderer Benutzer angemeldet sind. Es ist einfacher, Anforderungen zu bearbeiten, bei denen die URL selbst das Nonce enthält, dies kann jedoch wahrscheinlich mit den Browser-Entwicklertools (Ändern der Authentifizierungscookies und erneutes Senden) oder curl/wget erfolgen.

Der andere Teil, in dem Ihr Code fehlt, ist ein Schutz vor einer Art Wiederholungsangriff. Angenommen, ich weiß, dass Ihnen Post X gefallen hat, kann ich die Anfrage erneut senden und veranlassen, dass sie so angezeigt wird, wie es Ihnen auch bei Post Y gefallen hat? Im Moment muss ich nur den Parameter post_id der Anfrage ändern.

Zum Schutz vor solchen Angriffen muss der Teil action des Nonce dynamisch sein und in gewisser Weise die wichtigen Parameter enthalten, in Ihrem Fall die Post-ID. Core verwendet normalerweise Aktionen der Art delete-post-{post_id}, die sicherstellen, dass für verschiedene Posts eine andere Nonce generiert wird.

Vorgehensweise zum Testen Ändern Sie mithilfe der Browser-Entwicklertools den Parameter für die Post-ID, um sicherzustellen, dass dieselbe Nonce nicht zum Hinzufügen von Favoriten für andere Posts verwendet werden kann.

Für den Testtyp "phpunit" möchten Sie wahrscheinlich einen eigenen Nonce-Generator schreiben, der die wichtigsten Nonce-Funktionen von WordPress umschließt, und prüfen, ob sie nicht für verschiedene Benutzer und verschiedene Sitzungen dasselbe Nonce bereitstellen. verschiedene Aktionen und verschiedene Schlüsselanforderungsparameter.

1
Mark Kaplun

Das Lesen darüber im WP-Codex scheint, dass die Implementierung richtig ist.

Ein einfacher Test wäre, eine "gefälschte" Ajax-Anfrage ohne security Parameter in $.ajax() zu stellen oder dieselbe Anfrage mit einer Nonce aus einer anderen Zeit und Seite zu stellen.

(Was ist eine Nonce, als Referenz: Wiki )

2
Fabrizio Mele