WordPress Front-End-Sicherheit: CSRF und Nonces

Avatar of Andy Adams
Andy Adams am

DigitalOcean bietet Cloud-Produkte für jede Phase Ihrer Reise. Starten Sie mit 200 $ kostenlosem Guthaben!

In unserem letzten Artikel haben wir Cross-Site Scripting (XSS) und die Funktionen behandelt, die WordPress zur Verhinderung von XSS-Angriffen bereitstellt. Heute befassen wir uns mit einem weiteren Sicherheitsproblem für Front-End-Entwickler: Cross-Site Request Forgery (CSRF).

Damit Sie nicht denken, dass diese Sicherheitsdinge unwichtig sind: Eine große Sicherheitslücke wurde kürzlich im WP SEO Plugin entdeckt, das auf über 1.000.000 WordPress-Websites installiert ist und Hackern ermöglichte, die WordPress-Datenbank mittels CSRF zu manipulieren. (Das Plugin wurde schnell behoben, aber Sie können sehen, wie beängstigend so etwas sein kann.)

Nonces und Cross-Site Request Forgery

Vereinfacht ausgedrückt ist CSRF, wenn böswillige Akteure versuchen, Benutzer (normalerweise jemanden mit Zugriff auf das WordPress-Dashboard) zu täuschen, damit sie etwas tun, was sie nicht beabsichtigen. Ein einfaches Beispiel kann helfen, dies zu veranschaulichen.

Angenommen, Sie entwickeln ein WordPress-Plugin, das angemeldeten Benutzern das Hochladen ihrer Bilder ermöglicht. Auf der Front-End der Website könnte Ihr Plugin ein Formular wie dieses generieren:

<?php if ( is_user_logged_in() ) : ?>
  <form action="/submit-picture/" method="get">
    <input type="text" name="picture_url">
    <input type="submit">
  </form>
<?php endif; ?>

Auf der Back-End verarbeiten Sie die Einreichungen des Bildformulars.

if ( is_user_logged_in() && isset( $_REQUEST['picture_url'] ) ) {
  // Save the picture here
}

Angenommen, ein Hacker möchte nun ein *gefälschtes* Bild einreichen. Der Hacker hat keinen Benutzernamen oder kein Passwort – er kann also nichts tun, richtig?

Nicht ganz. Um das Konto eines Ihrer Benutzer zu kapern und ein gefälschtes Bild einzureichen, könnte der Hacker versuchen, einen angemeldeten Benutzer dazu zu bringen, auf einen Link zu klicken, der so aussieht:

http://your-site.com/submit-picture/?picture_url=fake-picture.jpg

Wenn ein angemeldeter Benutzer auf diesen Link klickt, was hindert dann die Einreichung des Bildes? Sie haben es erraten: Nichts. Der Hacker gewinnt.

Das liegt daran, dass wir nichts getan haben, um die *Absicht* des Benutzers zu bestätigen, ein Bild einzureichen. Das "F" in CSRF steht für Fälschung (Forgery): Der Hacker hat eine Anfrage im Namen des Benutzers gefälscht (nachgemacht), ähnlich wie Sie in der Grundschule Ihre Unterschrift auf Krankmeldungen *gefälscht* haben.

Wie man CSRF verhindert

Wir können CSRF-Angriffe stoppen, indem wir einige praktische Funktionen von WordPress nutzen. Um zu verhindern, dass eine Anfrage erfolgreich "gefälscht" wird, verwendet WordPress Nonces (nummern, die einmal verwendet werden), um zu überprüfen, ob die Anfrage tatsächlich vom aktuellen Benutzer stammt.

Der grundlegende Prozess sieht so aus:

  1. Ein Nonce wird generiert.
  2. Dieser Nonce wird mit dem Formular übermittelt.
  3. Auf der Back-End wird der Nonce auf Gültigkeit geprüft. Wenn er gültig ist, wird die Aktion fortgesetzt. Wenn er ungültig ist, stoppt alles – die Anfrage wurde wahrscheinlich gefälscht!

Lassen Sie uns einen Nonce hinzufügen

Auf der Front-End wollen wir einen Nonce zu einer Formularübermittlung hinzufügen. Dies tun wir mit der praktischen Funktion wp_nonce_field.

<form action="/submit-picture/" method="get">
  <input type="text" name="picture_url">
  <input type="submit">
  <?php wp_nonce_field( 'submit_picture' ); ?>
</form>

Einfach, oder? Nun müssen wir bei der Verarbeitung dieses Formulars auf der Back-End nur noch einige integrierte WordPress-Funktionen verwenden, um zu überprüfen, ob der Nonce gültig war.

// By default, we can find the nonce in the "_wpnonce" request parameter.
$nonce = $_REQUEST['_wpnonce'];
if ( ! wp_verify_nonce( $nonce, 'submit_picture' ) ) {
  exit; // Get out of here, the nonce is rotten!
}

// Now we can process the submission
if ( is_user_logged_in() && isset( $_REQUEST['picture_url'] ) ) {
  // Save the picture here
}

Da der Nonce dem Hacker unbekannt ist, kann er keinen gefälschten Link erstellen, der Schaden anrichtet. Jeder böswillige Versuch wird bei der Überprüfung mit wp_verify_nonce abgebrochen. Wir haben den Hacker gestoppt, richtig?! In vielen Fällen ja. Wir haben es einem Hacker deutlich erschwert, eine Anfrage zu fälschen.

Nonces sind benutzerspezifisch

Aber was ist, wenn ein *böswilliger angemeldeter Benutzer* Ihrer Website ein gefälschtes Bild *für einen anderen Benutzer* einreichen möchte? Könnte der böswillige Benutzer nicht einfach die HTML-Quelle der Website ansehen, das Nonce-Feld finden und es zu seiner "bösen" URL hinzufügen, wie hier?

http://ihre-seite.com/bild-einreichen/?bild_url=gefälschtes-bild.jpg&_wpnonce=NONCEWERT

Glücklicherweise *wird es nicht funktionieren*. WordPress-Nonces sind eindeutig für die Sitzung eines Benutzers, sodass ein Hacker seinen eigenen Nonce nicht gegen den eines anderen Benutzers austauschen könnte.

Ein Hut-Tipp an Mark Allen in den Kommentaren für den Hinweis auf sitzungsbezogene Nonces.

Probieren Sie diese Nonce-Funktionen aus

WordPress ist voll von praktischen Funktionen, die das Generieren von Nonces (und die Verhinderung von CSRF) erleichtern. Hier sind einige, die Sie für verschiedene Situationen nützlich finden könnten:

Funktion: wp_verify_nonce

Was sie tut: Überprüft, ob der Nonce-Wert ordnungsgemäß von WordPress generiert wurde.

Unabhängig davon, wie Sie Ihren Nonce generieren, sollte er auf der Back-End mit wp_verify_nonce überprüft werden.

Genau wie in den obigen Beispielen verwenden Sie wp_verify_nonce, um die Absicht eines Benutzers zu überprüfen.

$submitted_value = $_REQUEST['_wpnonce'];

if ( wp_verify_nonce( $submitted_value, 'your_action_name' ) ) {
  // nonce was valid...
}

Codex-Eintrag für wp_verify_nonce

Funktion: wp_nonce_field

Was sie tut: Gibt ein verstecktes <input>-Tag aus, das einen Nonce-Wert enthält.

Wird verwendet, wenn Sie ein <form> erstellen, das vor CSRF geschützt werden muss (was *so ziemlich jedes* <form> ist).

Genau wie in den obigen Beispielen ist wp_nonce_field eine praktische Funktion, die uns das Leben beim Erstellen von HTML-Formularen erleichtert.

<form>
<!-- Other form fields go here -->
<?php wp_nonce_field( 'your_action_name' ); ?>
</form>

Codex-Eintrag für wp_nonce_field

Funktion: wp_nonce_url

Was sie tut: Gibt eine URL mit einem angehängten Nonce-Wert zurück.

Wird verwendet, wenn Sie eine URL erstellen, die ein Nonce-Feld als Query-String-Parameter benötigt. Am nützlichsten bei GET-Anfragen, die eine CSRF-Validierung erfordern.

Hier ist ein Beispiel für wp_nonce_url, bei dem wir überprüfen müssen, ob ein Benutzer beabsichtigt hat, auf einen Link zu klicken.

<?php
  $action_url = wp_nonce_url( '/change-color/?color=blue', 'change_color' );
  // $action_url is now "/change-color/?color=blue&_wpnonce=GENERATED_VALUE"
?>
<a href="<?php echo esc_url( $action_url ); ?>">Change to blue</a>

Codex-Eintrag für wp_nonce_url

Funktion: wp_create_nonce

Was sie tut: Generiert einen Nonce-Wert.

Wird verwendet, wenn Sie einen Nonce-Wert benötigen, der nicht zu einer der oben genannten praktischen Funktionen passt.

Hier wird wp_create_nonce verwendet, um einen Nonce-Wert für die Rückgabe im JSON-Format zu generieren (nützlich für die Rückgabe in AJAX-Anfragen).

<?php
  $nonce_value = wp_create_nonce( 'your_action_name' );

  return json_encode( array( 'nonce' => $nonce_value ) );
?>

Codex-Eintrag für wp_create_nonce

Funktion: check_ajax_referer

Was sie tut: Prüft einen übermittelten Nonce mit wp_verify_nonce und stoppt die Ausführung, wenn die Validierung fehlschlägt.

check_ajax_referer ist eine weitere praktische Funktion, die hauptsächlich für AJAX-Anfragen verwendet wird. Sie können sie verwenden, um die Überprüfung mit wp_verify_nonce selbst zu überspringen.

<?php
  // Forged requests won't get past this line:
  check_ajax_referer( 'your_action_name' );

  // Do your action here
?>

Codex-Eintrag für check_ajax_referer

Nonces für alles!

CSRF-Schwachstellen reichen von harmlos (z. B. Umfrage-Einreichungen) bis hin zu *extrem gefährlich* (z. B. Änderung von Passwörtern oder Berechtigungen).

Unabhängig von der Schwere sollten Sie Nonces verwenden, um CSRF zu verhindern, *jedes Mal, wenn ein Benutzer eine Aktion* in WordPress ausführt. Denn... warum auch nicht? Sie möchten nicht, dass Hacker Anfragen auf Ihrer Website fälschen, und WordPress bietet Ihnen die Werkzeuge, um sie zu stoppen.

Verwenden Sie Nonces, stoppen Sie Fälschungen und vereiteln Sie Hacker!