Sicherheit/Cross Site Request Forgery

Aus SELFHTML-Wiki
Wechseln zu: Navigation, Suche

Eine Cross-Site-Request-Forgery (CSRF oder XSRF abgekürzt) – auf Deutsch etwa Website-übergreifende Anfragenfälschung – ist eine Schwachstelle in einer Webapplikation, bei der es ermöglicht wird, einem Nutzer eine Anfrage an eine andere Website unterzuschieben. Dabei sendet der Browser auch die zu dieser Site gehörenden Cookies mit. Lautet beispielsweise ein Logout-Link https://example.org/logout, so könnte man einem Nutzer, von dem man relativ sicher sein kann, dass er auf dieser Seite angemeldet ist, eine E-Mail mit vermeintlichen Sonderangeboten schicken, die auf diesen Link verweisen. Der nichtsahnende Nutzer klickt auf den Link und loggt sich ungewollt aus. Dieses Beispiel ist noch relativ harmlos, wesentlich brisanter wäre da ein Online-Shop mit einer Art Sofort-Kaufen-Funktion, die mit Links wie diesem arbeitet https://example.com/purchase?item=Waschmaschine+Typ+4711 und nach Aufrufen dieser URL ohne weitere Interaktion des Nutzers auskommt. Hier hätte der Nutzer, sofern er bei example.com Kunde und eingeloggt ist, wenig später eine Waschmaschine vor der Tür stehen. Noch gravierender: Er muss gar nicht selbst auf den Link klicken. Ein Angreifer könnte diesen Link in einem img-Element auf einer vom Nutzer aufgerufenen Seite als Quelladresse hinterlegen. Dass es sich dabei um eine Website und kein Bild handelt, „merkt“ der Browser erst, wenn er die URL schon aufgerufen und dabei die dazugehörigen Cookies mitgeschickt hat:

Fast unbemerkbares CSRF
<img src="https://example.com/purchase?item=Waschmaschine+Typ+4711" alt="">

Gegenmaßnahmen

Wie oben gezeigt wurde, ist CSRF ein ernsthaftes Sicherheitsproblem und muss beim Entwickeln von Webapplikation unbedingt beachtet werden. Dabei gibt es folgende Maßnahmen, die in der Regel zusammen eingesetzt werden (Defense in Depth):

  • Für Anfragen, die den Zustand der Sitzung oder Daten auf dem Server ändern, sollte ausschließlich POST als Anfragemethode benutzt werden. GET dient lediglich zum Abrufen von Inhalten und ändert keine Daten auf dem Server – eventuell aktivierte Log-Dateien des Webservers mal ausgenommen.
  • Außerdem sollte in solchen Formularen ein CSRF-Token benutzt werden, das Formulardaten und die Session eines Nutzers miteinander verbindet, es muss gleich sein, sonst kann es sich um einen CSRF-Angriff handelt – vielleicht ist auch nur die Session des Nutzers und damit das CSRF-Token abgelaufen. Weiter unten ist die Benutzung umrissen.
  • Cookies lassen sich mit einem Parameter setzen, der Browser anweist, dieses Cookie nur bei Anfragen mitzusenden, die von der ursprünglichen Seite ausgehen. Dies lässt sich das Senden des betreffenden Cookies bei Anfragen von Drittseiten nur bei GET erlauben (SameSite=lax) oder komplett deaktivieren (SameSite=strict)[1].
Schutz vor CSRF mittels Token
if (!isset($_SESSION)) {
  session_start();
  if(!isset($_SESSION['csrf_token']) || empty($_SESSION['csrf_token'])) {
    $_SESSION['csrf_token'] = base64_encode(random_bytes(23));
  }
}

function validateCsrfToken() {
  if(($_POST['csrf_token']??'') != $_SESSION['csrf_token']) {
    // Fehlerbehandlung, ggf. auch HTTP-Weiterleitung
    return false;
  }
  return true;
}

if(isset($_POST['test'])) {
  if(validateCsrfToken()) {
    // Mach etwas mit den Daten und zeige eine Erfolgmeldung an.
  } else {
    echo 'Prüfung des CSRF-Token ist fehlgeschlagen, prüfen Sie den Inhalt des Formulars und senden Sie es erneut ab.';
  }
}
<form method="post">
  <input name="test" value="<?=htmlspecialchars($_POST['test'])?>">>
  <input name="csrf_token" type="hidden" value="<?=htmlspecialchars($_SESSION['csrf_token'])?>">
  <button>Absenden</button>
</form>
Zuerst wird eine Session gestartet, damit das superglobale $_SESSION-Array zur Verfügung steht. Vor der Validierung der Formulareingaben wird dann die Funktion validateCsrfToken() aufgerufen. Im Falle des obigen Affenformulars kann man dem Nutzer einfach das Formular erneut vorsetzen und ihm erklären, dass seine Sitzung zwischenzeitlich abgelaufen ist oder das CSRF gerade verhindert wurde.

Eine Bonusfunktion, die man beim Einsatz eines CSRF-Tokens erhält, ist eine Reloadsperre, sofern man den Token nach Absenden eines Formulars neu generiert. Sofern ein Nutzer das Formular erneut absenden möchte, schlägt die Verifizierung des CSRF-Token fehl, da im Formular noch der alte Wert, im Cookie aber bereits der neue enthalten ist.

Sofern ein Framework beim Entwickeln der Applikation eingesetzt wird, das bereits Schutzmechanismen gegen CSRF bietet, so sollten diese anstatt eines Eigenbaus verwendet werden.

Weblinks

  1. MDN: Set-Cookie, Abschnitt „SameSite“