Ich schreibe eine Anwendung (Django, das passiert auch) und möchte nur eine Vorstellung davon haben, was ein "CSRF-Token" eigentlich ist und wie es die Daten schützt. Sind die Post-Daten nicht sicher, wenn Sie keine CSRF-Token verwenden?
Ich schreibe eine Anwendung (Django, das passiert auch) und möchte nur eine Vorstellung davon haben, was ein "CSRF-Token" eigentlich ist und wie es die Daten schützt. Sind die Post-Daten nicht sicher, wenn Sie keine CSRF-Token verwenden?
Antworten:
www.mybank.com
mybank.com
führt zu einer Anforderung (konzeptionell) des Formulars http://www.mybank.com/transfer?to=<SomeAccountnumber>;amount=<SomeAmount>
. (Ihre Kontonummer wird nicht benötigt, da dies durch Ihre Anmeldung impliziert wird.)www.cute-cat-pictures.org
, ohne zu wissen, dass es sich um eine bösartige Website handelt.mybank.com
(erfordert etwas Glück!), Könnte er auf seiner Seite eine Anfrage wie http://www.mybank.com/transfer?to=123456;amount=10000
(wo 123456
ist die Nummer seines Cayman Islands-Kontos) einfügen und 10000
ist ein Betrag, von dem Sie vorher dachten, dass Sie ihn gerne besitzen würden).www.cute-cat-pictures.org
Seite abgerufen , sodass Ihr Browser diese Anfrage stellt.www.mybank.com
Cookie und sie sieht absolut legitim aus. Da geht dein Geld!Dies ist die Welt ohne CSRF-Token .
Nun zum Besseren mit CSRF-Token :
http://www.mybank.com/transfer?to=123456;amount=10000;token=31415926535897932384626433832795028841971
.mybank.com
die auf ihrer eigenen Webseite angezeigt wird, wenn sie Ihnen bereitgestellt wird. Es ist jedes Mal anders, wenn sie jemandem eine Seite zur Verfügung stellen.www.mybank.com
.Ergebnis: Sie behalten Ihre 10000
Geldeinheiten. Ich schlage vor, Sie spenden etwas davon an Wikipedia.
(Ihr Kilometerstand kann variieren.)
BEARBEITEN von lesenswertem Kommentar:
Es ist zu beachten, dass das Skript von www.cute-cat-pictures.org
normalerweise www.mybank.com
aufgrund der HTTP-Zugriffskontrolle keinen Zugriff auf Ihr Anti-CSRF-Token hat . Dieser Hinweis ist wichtig für einige Personen, die unangemessen einen Header Access-Control-Allow-Origin: *
für jede Website-Antwort senden, ohne zu wissen, wofür er bestimmt ist, nur weil sie die API von einer anderen Website nicht verwenden können.
www.cute-cat-pictures.org
normalerweise www.mybank.com
aufgrund der HTTP-Zugriffskontrolle keinen Zugriff auf Ihr Anti-CSRF-Token hat . Dieser Hinweis ist wichtig für einige Personen, die unangemessen einen Header Access-Control-Allow-Origin: *
für jede Website-Antwort senden, ohne zu wissen, wofür er bestimmt ist, nur weil sie die API von einer anderen Website nicht verwenden können.
Ja, die Postdaten sind sicher. Der Ursprung dieser Daten ist jedoch nicht. Auf diese Weise kann jemand Benutzer mit JS dazu verleiten, sich bei Ihrer Website anzumelden, während er die Webseite des Angreifers durchsucht.
Um dies zu verhindern, sendet django einen zufälligen Schlüssel sowohl im Cookie als auch in Formulardaten. Wenn Benutzer POSTs senden, wird überprüft, ob zwei Schlüssel identisch sind. Wenn der Benutzer betrogen wird, kann die Website eines Drittanbieters die Cookies Ihrer Website nicht abrufen, was zu einem Authentifizierungsfehler führt.
Die Site generiert ein eindeutiges Token, wenn sie die Formularseite erstellt. Dieses Token ist erforderlich, um Daten an den Server zurückzusenden.
Da das Token von Ihrer Site generiert und nur bereitgestellt wird, wenn die Seite mit dem Formular generiert wird, kann eine andere Site Ihre Formulare nicht nachahmen - sie haben das Token nicht und können daher nicht auf Ihrer Site posten.
Der Cloud Under-Blog bietet eine gute Erklärung für CSRF-Token.
Stellen Sie sich vor, Sie hätten eine Website wie ein vereinfachtes Twitter, die auf a.com gehostet wird. Angemeldete Benutzer können Text (einen Tweet) in ein Formular eingeben, das als POST-Anfrage an den Server gesendet und veröffentlicht wird, wenn sie auf die Schaltfläche "Senden" klicken. Auf dem Server wird der Benutzer durch ein Cookie identifiziert, das seine eindeutige Sitzungs-ID enthält, sodass Ihr Server weiß, wer den Tweet gepostet hat.
Das Formular könnte so einfach sein:
<form action="http://a.com/tweet" method="POST"> <input type="text" name="tweet"> <input type="submit"> </form>
Stellen Sie sich nun vor, ein Bösewicht kopiert dieses Formular und fügt es in seine bösartige Website ein, sagen wir b.com. Das Formular würde immer noch funktionieren. Solange ein Benutzer bei Ihrem Twitter angemeldet ist (dh er hat ein gültiges Sitzungscookie für a.com), wird die POST-Anforderung
http://a.com/tweet
wie gewohnt an gesendet und verarbeitet, wenn der Benutzer auf die Schaltfläche " Senden" klickt.Bisher ist dies kein großes Problem, solange der Benutzer darüber informiert wird, was das Formular genau tut, aber was ist, wenn unser Bösewicht das Formular so ändert:
<form action="https://example.com/tweet" method="POST"> <input type="hidden" name="tweet" value="Buy great products at http://b.com/#iambad"> <input type="submit" value="Click to win!"> </form>
Wenn nun einer Ihrer Benutzer auf der Website des Bösen landet und auf "Klicken, um zu gewinnen!" Klicken Sie auf die Schaltfläche, das Formular wird an Ihre Website gesendet, der Benutzer wird anhand der Sitzungs-ID im Cookie korrekt identifiziert und der versteckte Tweet wird veröffentlicht.
Wenn unser Bösewicht noch schlimmer wäre, würde er den unschuldigen Benutzer dazu bringen, dieses Formular einzureichen, sobald er seine Webseite mit JavaScript öffnet, vielleicht sogar vollständig versteckt in einem unsichtbaren Iframe. Dies ist im Grunde eine standortübergreifende Fälschung von Anfragen.
Ein Formular kann einfach von überall nach überall eingereicht werden. Im Allgemeinen ist dies eine häufige Funktion, aber es gibt noch viele weitere Fälle, in denen es wichtig ist, nur das Senden eines Formulars von der Domäne zuzulassen, zu der es gehört.
Noch schlimmer ist es, wenn Ihre Webanwendung nicht zwischen POST- und GET-Anforderungen unterscheidet (z. B. in PHP, indem Sie $ _REQUEST anstelle von $ _POST verwenden). Tu das nicht! Anfragen zur Änderung von Daten können so einfach wie
<img src="http://a.com/tweet?tweet=This+is+really+bad">
eingebettet in eine schädliche Website oder sogar in eine E-Mail gesendet werden.Wie stelle ich sicher, dass ein Formular nur von meiner eigenen Website eingereicht werden kann? Hier kommt das CSRF-Token ins Spiel. Ein CSRF-Token ist eine zufällige, schwer zu erratende Zeichenfolge. Auf einer Seite mit einem Formular, das Sie schützen möchten, generiert der Server eine zufällige Zeichenfolge, das CSRF-Token, fügt es dem Formular als verstecktes Feld hinzu und merkt es sich auch irgendwie, indem er es in der Sitzung speichert oder ein Cookie setzt mit dem Wert. Jetzt würde das Formular folgendermaßen aussehen:
<form action="https://example.com/tweet" method="POST"> <input type="hidden" name="csrf-token" value="nc98P987bcpncYhoadjoiydc9ajDlcn"> <input type="text" name="tweet"> <input type="submit"> </form>
Wenn der Benutzer das Formular sendet, muss der Server lediglich den Wert des veröffentlichten Felds csrf-token (der Name spielt keine Rolle) mit dem CSRF-Token vergleichen, an das sich der Server erinnert. Wenn beide Zeichenfolgen gleich sind, kann der Server das Formular weiter verarbeiten. Andernfalls sollte der Server die Verarbeitung des Formulars sofort beenden und mit einem Fehler antworten.
Warum funktioniert das? Es gibt mehrere Gründe, warum der Bösewicht aus unserem obigen Beispiel den CSRF-Token nicht erhalten kann:
Das Kopieren des statischen Quellcodes von unserer Seite auf eine andere Website wäre nutzlos, da sich der Wert des ausgeblendeten Felds mit jedem Benutzer ändert. Ohne dass die Website des Bösewichts das CSRF-Token des aktuellen Benutzers kennt, würde Ihr Server die POST-Anforderung immer ablehnen.
Da die bösartige Seite des Bösewichts vom Browser Ihres Benutzers aus einer anderen Domain (b.com anstelle von a.com) geladen wird, hat der Bösewicht keine Chance, ein JavaScript zu codieren, das den Inhalt und damit das aktuelle CSRF-Token unseres Benutzers lädt deine Website. Dies liegt daran, dass Webbrowser standardmäßig keine domänenübergreifenden AJAX-Anforderungen zulassen.
Der Bösewicht kann auch nicht auf das von Ihrem Server gesetzte Cookie zugreifen, da die Domänen nicht übereinstimmen.
Wann sollte ich mich vor Fälschungen von standortübergreifenden Anfragen schützen? Wenn Sie sicherstellen können, dass Sie GET, POST und andere Anforderungsmethoden nicht wie oben beschrieben verwechseln, ist es ein guter Anfang, standardmäßig alle POST-Anforderungen zu schützen.
Sie müssen PUT- und DELETE-Anforderungen nicht schützen, da, wie oben erläutert, ein Standard-HTML-Formular von einem Browser mit diesen Methoden nicht gesendet werden kann.
JavaScript hingegen kann zwar andere Arten von Anforderungen stellen, z. B. mithilfe der Funktion $ .ajax () von jQuery. Beachten Sie jedoch, dass die Domänen übereinstimmen müssen, damit AJAX-Anforderungen funktionieren (sofern Sie Ihren Webserver nicht explizit anders konfigurieren). .
Dies bedeutet, dass Sie AJAX-Anforderungen häufig nicht einmal ein CSRF-Token hinzufügen müssen, selbst wenn es sich um POST-Anforderungen handelt. Sie müssen jedoch sicherstellen, dass Sie die CSRF-Prüfung in Ihrer Webanwendung nur umgehen, wenn es sich bei der POST-Anforderung tatsächlich um eine handelt AJAX-Anfrage. Sie können dies tun, indem Sie nach einem Header wie X-Requested-With suchen, den AJAX-Anforderungen normalerweise enthalten. Sie können auch einen anderen benutzerdefinierten Header festlegen und dessen Vorhandensein auf der Serverseite überprüfen. Das ist sicher, da ein Browser einer regulären HTML-Formularübermittlung keine benutzerdefinierten Header hinzufügen würde (siehe oben), sodass Mr Bad Guy dieses Verhalten nicht mit einem Formular simulieren kann.
Wenn Sie Zweifel an AJAX-Anforderungen haben, weil Sie aus irgendeinem Grund nicht nach einem Header wie X-Requested-With suchen können, übergeben Sie das generierte CSRF-Token einfach an Ihr JavaScript und fügen Sie das Token der AJAX-Anforderung hinzu. Es gibt verschiedene Möglichkeiten, dies zu tun. Fügen Sie es entweder wie ein normales HTML-Formular zur Nutzlast hinzu oder fügen Sie der AJAX-Anforderung einen benutzerdefinierten Header hinzu. Solange Ihr Server weiß, wo er in einer eingehenden Anforderung danach suchen muss, und in der Lage ist, ihn mit dem ursprünglichen Wert zu vergleichen, an den er sich aus der Sitzung oder dem Cookie erinnert, sind Sie sortiert.
Der Grund dafür ist, sicherzustellen, dass die Anforderungen von den tatsächlichen Benutzern der Site stammen. Für die Formulare wird ein CSRF-Token generiert, das an die Sitzungen des Benutzers gebunden sein muss. Es wird verwendet, um Anforderungen an den Server zu senden, auf dem das Token sie überprüft. Dies ist eine Möglichkeit zum Schutz vor CSRF, eine andere wäre die Überprüfung des Referrer-Headers.