CSRF-Token bei Verwendung der zustandslosen (= sitzungslosen) Authentifizierung erforderlich?

125

Ist es erforderlich, CSRF-Schutz zu verwenden, wenn die Anwendung auf einer zustandslosen Authentifizierung basiert (unter Verwendung von HMAC)?

Beispiel:

  • Wir haben eine App für eine einzelne Seite (andernfalls müssen wir das Token an jeden Link anhängen : <a href="...?token=xyz">...</a>.

  • Der Benutzer authentifiziert sich mit POST /auth. Bei erfolgreicher Authentifizierung gibt der Server ein Token zurück.

  • Das Token wird über JavaScript in einer Variablen in der Einzelseiten-App gespeichert.

  • Dieses Token wird verwendet, um auf eingeschränkte URLs wie zuzugreifen /admin.

  • Das Token wird immer in HTTP-Headern übertragen.

  • Es gibt KEINE HTTP-Sitzung und KEINE Cookies.

Soweit ich weiß, sollte es (?!) Keine Möglichkeit geben, Cross-Site-Angriffe zu verwenden, da der Browser das Token nicht speichert und es daher nicht automatisch an den Server senden kann (dies würde bei der Verwendung von Cookies / passieren). Session).

Vermisse ich etwas

Benjamin M.
quelle
6
Seien Sie vorsichtig mit Basic Auth. Viele Browser senden automatisch die grundlegenden Authentifizierungsheader für den Rest der Sitzung. Dies kann die Basisauthentifizierung für CSRF genauso anfällig machen wie die Cookie-Authentifizierung.
Phylae

Antworten:

159

Ich habe einige Informationen zu CSRF + gefunden, bei denen keine Cookies zur Authentifizierung verwendet wurden:

  1. https://auth0.com/blog/2014/01/07/angularjs-authentication-with-cookies-vs-token/
    "Da Sie sich nicht auf Cookies verlassen, müssen Sie sich nicht vor standortübergreifenden Anfragen schützen."

  2. http://angular-tips.com/blog/2014/05/json-web-tokens-introduction/
    "Wenn wir Cookies verwenden, müssen Sie wirklich CSRF durchführen, um Cross-Site-Anfragen zu vermeiden. Das können wir Vergessen Sie bei der Verwendung von JWT, wie Sie sehen werden. "
    (JWT = Json Web Token, eine Token-basierte Authentifizierung für zustandslose Apps)

  3. http://www.jamesward.com/2013/05/13/securing-single-page-apps-and-rest-services
    "Der einfachste Weg, eine Authentifizierung durchzuführen, ohne CSRF-Schwachstellen zu riskieren, besteht darin, die Verwendung von Cookies zur Identifizierung des Benutzers einfach zu vermeiden ""

  4. http://sitr.us/2011/08/26/cookies-are-bad-for-you.html
    "Das größte Problem mit CSRF ist, dass Cookies absolut keinen Schutz gegen diese Art von Angriff bieten. Wenn Sie die Cookie-Authentifizierung verwenden Sie müssen auch zusätzliche Maßnahmen zum Schutz vor CSRF ergreifen. Die grundlegendste Vorsichtsmaßnahme, die Sie treffen können, besteht darin, sicherzustellen, dass Ihre Anwendung als Reaktion auf GET-Anforderungen niemals Nebenwirkungen aufweist. "

Es gibt viele weitere Seiten, auf denen angegeben wird, dass Sie keinen CSRF-Schutz benötigen, wenn Sie keine Cookies zur Authentifizierung verwenden. Natürlich können Sie weiterhin Cookies für alles andere verwenden, aber vermeiden Sie es, etwas darin zu speichern session_id.


Wenn Sie sich an den Benutzer erinnern müssen, gibt es zwei Möglichkeiten:

  1. localStorage: Ein Schlüsselwertspeicher im Browser. Die gespeicherten Daten sind auch dann verfügbar, wenn der Benutzer das Browserfenster schließt. Auf die Daten können andere Websites nicht zugreifen, da jede Website einen eigenen Speicher erhält.

  2. sessionStorage: Auch ein im Browser vorhandener Datenspeicher. Der Unterschied ist: Die Daten werden gelöscht, wenn der Benutzer das Browserfenster schließt. Es ist jedoch weiterhin nützlich, wenn Ihre Webanwendung aus mehreren Seiten besteht. Sie können also Folgendes tun:

    • Der Benutzer meldet sich an und speichert das Token sessionStorage
    • Der Benutzer klickt auf einen Link, der eine neue Seite lädt (= ein echter Link und kein Ersetzen von Javascript-Inhalten).
    • Sie können weiterhin von auf auf das Token zugreifen sessionStorage
    • Zum Abmelden können Sie das Token entweder manuell löschen sessionStorageoder warten, bis der Benutzer das Browserfenster schließt, in dem alle gespeicherten Daten gelöscht werden.

(für beide schauen Sie hier: http://www.w3schools.com/html/html5_webstorage.asp )


Gibt es offizielle Standards für die Tokenauthentifizierung?

JWT (Json Web Token): Ich denke, es ist immer noch ein Entwurf, aber er wird bereits von vielen Menschen verwendet und das Konzept sieht einfach und sicher aus. (IETF: http://tools.ietf.org/html/draft-ietf-oauth-json-web-token-25 )
Es gibt auch Bibliotheken für viele Frameworks. Google einfach dafür!

Benjamin M.
quelle
37
Tolle Zusammenfassung zu CSRF! Ich werde darauf hinweisen, dass das Speichern Ihrer Token in localStorage oder sessionStorage anfällig für XSS-Angriffe ist und dass die Daten von Skripten auf der Seite angezeigt werden können. Wenn Sie also ein kompromittiertes Skript von einem CDN bereitgestellt haben oder wenn sich in einem Ihrer Token schädlicher Code befindet JS-Bibliotheken können sie das Token aus diesen Speicherplätzen stehlen. Siehe: Stormpath.com/blog/… Ich denke, der sicherste Ansatz besteht darin, ein JWT + CSRF-Token im Cookie zu speichern und dann Ihr berechnetes JWT mit dem darin enthaltenen CSRF-Token im Anforderungsheader zu platzieren.
Aaron Gray
Zu: "Die grundlegendste Vorsichtsmaßnahme, die Sie treffen können, besteht darin, sicherzustellen, dass Ihre Anwendung als Reaktion auf GET-Anforderungen niemals Nebenwirkungen aufweist." Kann ein CSRF-Angriff eine POST-Anfrage vortäuschen?
Costa
Abhängig von der serverseitigen Anwendung kann dies möglich sein. Es gibt Web Frameworks, die so etwas wie verwenden http://.../someRestResource?method=POST. Es handelt sich also im Grunde genommen um eine GETAnforderung, die von der Serveranwendung jedoch als POSTAnforderung interpretiert wird , da sie so konfiguriert wurde, dass der methodParameter anstelle des HTTP-Headers verwendet wird. ...In Bezug auf die gängigen Webbrowser erzwingen sie die Same-Origin-Richtlinie und führen nur GETAnforderungen an fremde Server aus. Es könnte jedoch möglich sein, POSTAnforderungen auszuführen , wenn der Webbrowser diese Webstandards (Fehler, Malware) nicht anwendet.
Benjamin M
1
Ergänzung zu Server Side App: Es ist immer noch nicht möglich, einen Anfragetext zu senden, da die gängigen Browser dies nicht zulassen. Wenn die Server-App dies zulässt method=POST, kann möglicherweise auch body={someJson}der Standardanforderungstext überschrieben werden. Das ist wirklich schlechtes API-Design und extrem riskant. Wenn Ihre Server-App dies zulässt http://...?method=POST&body={someJson}, sollten Sie jedoch wirklich überlegen, was Sie dort getan haben und warum und ob dies überhaupt erforderlich ist. (Ich würde sagen, in 99.9999% der Fälle ist es nicht notwendig). Außerdem können Browser auf diese Weise nur wenige Kilobyte senden.
Benjamin M
@BenjaminM Beachten Sie, dass die Same Origin-Richtlinie nur verhindert, dass der JavaScript-Code auf das Ergebnis zugreift. Während die Anforderung "blockiert" ist, erreicht sie tatsächlich den Server - jsbin.com/mewaxikuqo/edit?html,js,output Ich habe dies nur unter Firefox getestet. Sie können jedoch Entwickler-Tools öffnen und feststellen, dass der Remote-Server die gesamte Anforderung tatsächlich sieht, obwohl "Cross-Origin Request Blocked" angezeigt wird. Aus diesem Grund müssen Sie Token oder benutzerdefinierte Header (und wenn möglich beide) für alle Ihre POST-Anfragen haben
Yoni Jah,
59

TL; DR

Wenn ein JWT ohne Cookies verwendet wird, ist kein CSRF-Token erforderlich - ABER! Indem Sie JWT in session / localStorage speichern, legen Sie Ihre JWT- und Benutzeridentität offen, wenn Ihre Site eine XSS-Sicherheitsanfälligkeit aufweist (ziemlich häufig). Es ist besser , einen hinzuzufügen csrfTokenSchlüssel zum JWT und speichern Sie die JWT in einem Cookie mit secureund http-onlyAttribute gesetzt.

Lesen Sie diesen Artikel mit einer guten Beschreibung für weitere Informationen https://stormpath.com/blog/where-to-store-your-jwts-cookies-vs-html5-web-storage

Sie können diesen CSRF-Schutz zustandslos machen, indem Sie einen xsrfToken JWT-Anspruch einfügen:

{ "iss": "http://galaxies.com", "exp": 1300819380, "scopes": ["explorer", "solar-harvester", "seller"], "sub": "[email protected]", "xsrfToken": "d9b9714c-7ac0-42e0-8696-2dae95dbc33e" }

Sie müssen das csrfToken also sowohl in localStorage / sessionStorage als auch im JWT selbst speichern (das in einem Nur-http-Cookie und einem sicheren Cookie gespeichert ist). Stellen Sie dann zum Schutz der CSRF sicher, dass das CSRF-Token im JWT mit dem übermittelten CSRF-Token-Header übereinstimmt.

Scott Jungwirth
quelle
2
Sollte man die Verwendung von CSRF-Token während der API-Authentifizierung des Benutzers ausnehmen?
user805981
3
Es ist erwähnenswert (wie andere auch in den Kommentaren zum Quelllink erwähnt haben), dass jede CSRF-Minderung, die a) Cookies verwendet, die nicht nur http sind oder b) das CSRF-Token im lokalen Speicher speichert, für XSS anfällig ist. Dies bedeutet, dass der vorgestellte Ansatz dazu beitragen kann, die JWT vor einem Angreifer mit XSS geheim zu halten. Ein Angreifer kann jedoch weiterhin eine böswillige Anfrage auf Ihrer API ausführen, da er eine gültige JWT bereitstellen kann (über das Cookie, danke Browser). und CSRF-Token (Lesen über injiziertes JS aus dem lokalen Speicher / Cookie).
Johannes Rudolph
1
Tatsächlich kann Sie sogar ein CSRF-Token auf dieser XSS-Ebene nicht schützen, da Sie davon ausgehen, dass der Angreifer auf localStorage zugreifen kann. Derzeit können Sie nur auf Zugriff auf Skriptebene zugreifen, um das CSRF-Token zu überprüfen .
gültig
1
Ist es nicht das, was @JohannesRudolph sagte? Sobald Sie das CSRF-Token in einem Webspeicher / Nicht-http-only-Cookie speichern, erhöhen Sie den Footprint eines XSS-Angriffs, da auf diese über JS zugegriffen werden kann.
Adam-Beck
1
Kein totaler Experte hier, aber wenn Sie immer noch wie am Anfang mit XSS konfrontiert sind, bin ich mir nicht sicher, welcher Teil Es ist besser hinzuzufügen ... wirklich gilt. Wahrscheinlich ist es für einen Angreifer etwas (?) Komplizierter, an CSRF-Token zu gelangen, aber am Ende kann er immer noch eine Anfrage in Ihrem Namen ausführen, auch ohne das JWT-Token tatsächlich zu kennen. Ist das korrekt? Danke
Superjos