Ich versuche, das ganze Problem mit CSRF und geeignete Möglichkeiten zu verstehen, um es zu verhindern. (Ressourcen, die ich gelesen habe, verstehe und mit denen ich einverstanden bin: OWASP CSRF Prevention Cheat Sheet , Fragen zu CSRF .)
Soweit ich weiß, wird die Sicherheitsanfälligkeit in Bezug auf CSRF durch die Annahme verursacht, dass (aus Sicht des Webservers) ein gültiges Sitzungscookie in einer eingehenden HTTP-Anforderung die Wünsche eines authentifizierten Benutzers widerspiegelt. Alle Cookies für die Ursprungsdomäne werden jedoch vom Browser auf magische Weise an die Anforderung angehängt, sodass der Server aus dem Vorhandensein eines gültigen Sitzungscookies in einer Anforderung tatsächlich schließen kann, dass die Anforderung von einem Browser stammt, der über eine authentifizierte Sitzung verfügt. es kann nichts weiter über den Code annehmenin diesem Browser ausgeführt werden oder ob es wirklich Benutzerwünsche widerspiegelt. Um dies zu verhindern, müssen Sie zusätzliche Authentifizierungsinformationen (das "CSRF-Token") in die Anforderung aufnehmen, die auf andere Weise als durch die automatische Cookie-Behandlung des Browsers übertragen werden. Das Sitzungscookie authentifiziert also den Benutzer / Browser und das CSRF-Token authentifiziert den im Browser ausgeführten Code.
Kurz gesagt, wenn Sie ein Sitzungscookie verwenden, um Benutzer Ihrer Webanwendung zu authentifizieren, sollten Sie jeder Antwort ein CSRF-Token hinzufügen und in jeder (mutierenden) Anforderung ein passendes CSRF-Token benötigen. Das CSRF-Token führt dann einen Roundtrip vom Server zum Browser zurück zum Server durch und beweist dem Server, dass die Seite, auf der die Anforderung gestellt wird, von diesem Server genehmigt (sogar generiert) wurde.
Weiter zu meiner Frage, die sich auf die spezifische Transportmethode bezieht, die für dieses CSRF-Token auf dieser Rundreise verwendet wird.
Es scheint üblich zu sein (zB in AngularJS , Django , Rails ), das CSRF-Token als Cookie (dh in einem Set-Cookie-Header) vom Server an den Client zu senden und dann Javascript im Client aus dem Cookie zu entfernen und anzuhängen als separater XSRF-TOKEN-Header zum Zurücksenden an den Server.
(Eine alternative Methode ist die von z Express , bei der das vom Server generierte CSRF-Token über eine serverseitige Vorlagenerweiterung in den Antworttext aufgenommen wird und direkt an den Code / das Markup angehängt wird, der es an den Server zurückgibt, z Dieses Beispiel ist eine Web 1.0-ähnliche Methode, würde sich aber gut auf einen JS-lastigeren Client verallgemeinern lassen.)
Warum ist es so üblich, Set-Cookie als Downstream-Transport für das CSRF-Token zu verwenden / warum ist dies eine gute Idee? Ich stelle mir vor, die Autoren all dieser Frameworks haben ihre Optionen sorgfältig geprüft und das nicht falsch verstanden. Auf den ersten Blick erscheint es jedoch dumm, Cookies zu verwenden, um das zu umgehen, was im Wesentlichen eine Designbeschränkung für Cookies darstellt. Wenn Sie Cookies als Hin- und Rücktransport verwenden (Set-Cookie: Header Downstream für den Server, um dem Browser das CSRF-Token mitzuteilen, und Cookie: Header Upstream für den Browser, um es an den Server zurückzugeben), würden Sie die Sicherheitsanfälligkeit wieder einführen versuchen zu beheben.
Mir ist klar, dass die oben genannten Frameworks keine Cookies für die gesamte Hin- und Rückfahrt für das CSRF-Token verwenden. Sie verwenden Set-Cookie Downstream, dann etwas anderes (z. B. einen X-CSRF-Token-Header) Upstream, und dies schließt die Sicherheitsanfälligkeit aus. Aber selbst die Verwendung von Set-Cookie als nachgeschalteter Transport ist möglicherweise irreführend und gefährlich. Der Browser hängt nun das CSRF-Token an jede Anforderung an, einschließlich echter böswilliger XSRF-Anforderungen. Im besten Fall ist die Anfrage dadurch größer als nötig, und im schlimmsten Fall könnte ein gut gemeinter, aber fehlgeleiteter Teil des Servercodes tatsächlich versuchen, sie zu verwenden, was wirklich schlecht wäre. Da der tatsächlich beabsichtigte Empfänger des CSRF-Tokens clientseitiges Javascript ist, bedeutet dies, dass dieses Cookie nicht nur mit http geschützt werden kann.
Antworten:
Ein guter Grund, den Sie angesprochen haben, ist, dass das CSRF-Cookie nach dem Empfang in der gesamten Anwendung im Client-Skript zur Verwendung sowohl in regulären Formularen als auch in AJAX-POSTs verfügbar ist. Dies ist in einer JavaScript-lastigen Anwendung wie der von AngularJS verwendeten sinnvoll (für die Verwendung von AngularJS ist es nicht erforderlich, dass die Anwendung eine Einzelseiten-App ist. Daher ist es hilfreich, wenn der Status zwischen verschiedenen Seitenanforderungen mit dem CSRF-Wert fließen muss kann normalerweise nicht im Browser bestehen bleiben).
Betrachten Sie die folgenden Szenarien und Prozesse in einer typischen Anwendung für einige Vor- und Nachteile jedes von Ihnen beschriebenen Ansatzes. Diese basieren auf dem Synchronizer-Token-Muster .
Body Approach anfordern
Vorteile:
Nachteile:
Benutzerdefinierter HTTP-Header (Downstream)
Vorteile:
Nachteile:
Benutzerdefinierter HTTP-Header (Upstream)
Vorteile:
Nachteile:
Benutzerdefinierter HTTP-Header (Upstream & Downstream)
Vorteile:
Nachteile:
Set-Cookie
Vorteile:
Nachteile:
Der Cookie-Ansatz ist also ziemlich dynamisch und bietet eine einfache Möglichkeit, den Cookie-Wert (jede HTTP-Anforderung) abzurufen und zu verwenden (JS kann den Wert automatisch zu jedem Formular hinzufügen und in AJAX-Anforderungen entweder als Header oder als Header verwenden Formularwert). Sobald das CSRF-Token für die Sitzung empfangen wurde, muss es nicht erneut generiert werden, da ein Angreifer, der einen CSRF-Exploit verwendet, keine Methode zum Abrufen dieses Tokens hat. Wenn ein böswilliger Benutzer versucht, das CSRF-Token des Benutzers mit einer der oben genannten Methoden zu lesen, wird dies durch die Richtlinie für denselben Ursprung verhindert . Wenn ein böswilliger Benutzer versucht, die CSRF-Tokenserverseite abzurufen (z. B. über
curl
) dann wird dieses Token nicht demselben Benutzerkonto zugeordnet, in dem das Authentifizierungssitzungs-Cookie des Opfers in der Anforderung fehlt (es wäre das des Angreifers - daher wird es der Sitzung des Opfers nicht serverseitig zugeordnet).Neben dem Synchronizer-Token-Muster gibt es auch das Double Submit-CookieCSRF-Präventionsmethode, bei der natürlich Cookies zum Speichern einer Art CSRF-Token verwendet werden. Dies ist einfacher zu implementieren, da für das CSRF-Token kein serverseitiger Status erforderlich ist. Das CSRF-Token könnte tatsächlich das Standardauthentifizierungs-Cookie sein, wenn diese Methode verwendet wird, und dieser Wert wird wie gewohnt mit der Anforderung über Cookies gesendet. Der Wert wird jedoch auch in einem ausgeblendeten Feld oder Header wiederholt, als das ein Angreifer nicht replizieren kann Sie können den Wert überhaupt nicht lesen. Es wird jedoch empfohlen, ein anderes Cookie als das Authentifizierungscookie zu wählen, damit das Authentifizierungscookie durch Markieren mit HttpOnly gesichert werden kann. Dies ist ein weiterer häufiger Grund, warum Sie CSRF-Prävention mithilfe einer Cookie-basierten Methode finden.
quelle
Die Verwendung eines Cookies zur Bereitstellung des CSRF-Tokens für den Client ermöglicht keinen erfolgreichen Angriff, da der Angreifer den Wert des Cookies nicht lesen und ihn daher nicht dort ablegen kann, wo es für die serverseitige CSRF-Validierung erforderlich ist.
Der Angreifer kann eine Anforderung an den Server mit dem Authentifizierungs-Token-Cookie und dem CSRF-Cookie in den Anforderungsheadern senden. Der Server sucht jedoch nicht nach dem CSRF-Token als Cookie in den Anforderungsheadern, sondern nach der Nutzlast der Anforderung. Und selbst wenn der Angreifer weiß, wo er das CSRF-Token in die Nutzlast einfügen muss, muss er seinen Wert lesen, um es dort abzulegen. Die Cross-Origin-Richtlinie des Browsers verhindert jedoch das Lesen von Cookies von der Zielwebsite.
Dieselbe Logik gilt nicht für das Authentifizierungs-Token-Cookie, da der Server dies in den Anforderungsheadern erwartet und der Angreifer nichts Besonderes tun muss, um es dort abzulegen.
quelle
src='bank.com/transfer?to=hacker&amount=1000
dem der Browser dies anfordert, einschließlich der zugehörigen Cookies für diese Site (bank.com
)?Meine beste Vermutung bezüglich der Antwort: Betrachten Sie diese 3 Optionen, um das CSRF-Token vom Server zum Browser zu übertragen.
Ich denke, der erste Anfragetext (der durch das Express-Tutorial demonstriert wird, das ich in der Frage verlinkt habe ) ist für eine Vielzahl von Situationen nicht so portabel. Nicht jeder generiert jede HTTP-Antwort dynamisch. Wo Sie am Ende das Token in die generierte Antwort einfügen müssen, kann sehr unterschiedlich sein (in einer Eingabe in versteckter Form, in einem Fragment von JS-Code oder einer Variablen, auf die andere JS-Codes zugreifen können; möglicherweise sogar in einer URL, obwohl dies im Allgemeinen ein schlechter Ort zu sein scheint CSRF-Token setzen). Obwohl es mit einigen Anpassungen möglich ist, ist # 1 ein schwieriger Ort, um einen einheitlichen Ansatz zu entwickeln.
Der zweite, benutzerdefinierte Header, ist attraktiv, funktioniert aber nicht, da JS zwar die Header für eine aufgerufene XHR abrufen kann, jedoch nicht die Header für die Seite, von der es geladen wurde .
Damit bleibt das dritte, ein Cookie, das von einem Set-Cookie-Header getragen wird, ein Ansatz, der in allen Situationen einfach zu verwenden ist (jeder Server kann Cookies-Header pro Anforderung festlegen, und es spielt keine Rolle, um welche Art von Cookie es sich handelt Daten befinden sich im Anforderungshauptteil). Trotz seiner Nachteile war es die einfachste Methode, Frameworks umfassend zu implementieren.
quelle
Neben dem Sitzungscookie (der eine Art Standard ist) möchte ich keine zusätzlichen Cookies verwenden.
Ich habe eine Lösung gefunden, die für mich beim Erstellen einer Single Page Web Application (SPA) mit vielen AJAX-Anforderungen funktioniert. Hinweis: Ich verwende serverseitiges Java und clientseitiges JQuery, aber keine magischen Dinge, daher denke ich, dass dieses Prinzip in allen gängigen Programmiersprachen implementiert werden kann.
Meine Lösung ohne zusätzliche Cookies ist einfach:
Client-Seite
Speichern Sie das CSRF-Token, das vom Server nach einer erfolgreichen Anmeldung zurückgegeben wird, in einer globalen Variablen (wenn Sie Webspeicher anstelle eines globalen verwenden möchten, ist das natürlich in Ordnung). Weisen Sie JQuery an, bei jedem AJAX-Aufruf einen X-CSRF-TOKEN-Header anzugeben.
Die Hauptseite "Index" enthält dieses JavaScript-Snippet:
Serverseite
Erstellen Sie bei erfolgreicher Anmeldung ein zufälliges (und lang genug) CSRF-Token, speichern Sie dieses in der serverseitigen Sitzung und geben Sie es an den Client zurück. Filtern Sie bestimmte (vertrauliche) eingehende Anforderungen, indem Sie den X-CSRF-TOKEN-Headerwert mit dem in der Sitzung gespeicherten Wert vergleichen: Diese sollten übereinstimmen.
Sensible AJAX-Aufrufe (POST-Formulardaten und GET JSON-Daten) und der serverseitige Filter, der sie abfängt, befinden sich unter dem Pfad / dataservice / *. Anmeldeanforderungen dürfen den Filter nicht treffen, daher befinden sich diese auf einem anderen Pfad. Anforderungen für HTML-, CSS-, JS- und Bildressourcen befinden sich ebenfalls nicht im Pfad / dataservice / * und werden daher nicht gefiltert. Diese enthalten nichts Geheimnisvolles und können keinen Schaden anrichten, also ist das in Ordnung.
quelle