Jeton CSRF nécessaire lors de l'utilisation de l'authentification sans état (= sans session)?

125

Est-il nécessaire d'utiliser la protection CSRF lorsque l'application repose sur l'authentification sans état (en utilisant quelque chose comme HMAC)?

Exemple:

  • Nous avons une seule application de la page (sinon nous devons ajouter le jeton sur chaque lien: <a href="...?token=xyz">...</a>.

  • L'utilisateur s'authentifie en utilisant POST /auth. En cas d'authentification réussie, le serveur renverra un jeton.

  • Le jeton sera stocké via JavaScript dans une variable à l'intérieur de l'application à page unique.

  • Ce jeton sera utilisé pour accéder aux URL restreintes telles que /admin.

  • Le jeton sera toujours transmis à l'intérieur des en-têtes HTTP.

  • Il n'y a PAS de session Http et PAS de cookies.

Pour autant que je sache, il ne devrait (?!) Pas y avoir de possibilité d'utiliser des attaques intersites, car le navigateur ne stockera pas le jeton et ne peut donc pas l'envoyer automatiquement au serveur (c'est ce qui se passerait lors de l'utilisation de cookies / Session).

Est-ce que je manque quelque chose?

Benjamin M
la source
6
Faites attention à l'authentification de base. De nombreux navigateurs enverront automatiquement les en-têtes d'authentification de base pour le reste de la session. Cela peut rendre l'authentification de base aussi vulnérable à CSRF que l'authentification par cookie.
phylae

Réponses:

159

J'ai trouvé des informations sur CSRF + en n'utilisant aucun cookie pour l'authentification:

  1. https://auth0.com/blog/2014/01/07/angularjs-authentication-with-cookies-vs-token/
    "puisque vous ne vous fiez pas aux cookies, vous n'avez pas besoin de vous protéger contre les requêtes intersites"

  2. http://angular-tips.com/blog/2014/05/json-web-tokens-introduction/
    "Si nous suivons la voie des cookies, vous devez vraiment faire CSRF pour éviter les requêtes intersites. C'est quelque chose que nous pouvons oubliez lorsque vous utilisez JWT comme vous le verrez. "
    (JWT = Json Web Token, une authentification basée sur des jetons pour les applications sans état)

  3. http://www.jamesward.com/2013/05/13/securing-single-page-apps-and-rest-services
    "Le moyen le plus simple de s'authentifier sans risquer les vulnérabilités CSRF est simplement d'éviter d'utiliser des cookies pour identifier l'utilisateur "

  4. http://sitr.us/2011/08/26/cookies-are-bad-for-you.html
    "Le plus gros problème avec CSRF est que les cookies ne fournissent absolument aucune défense contre ce type d'attaque. Si vous utilisez l'authentification par cookie vous devez également utiliser des mesures supplémentaires pour vous protéger contre la CSRF. La précaution la plus élémentaire que vous pouvez prendre est de vous assurer que votre application n'effectue jamais d'effets secondaires en réponse aux requêtes GET. "

Il y a beaucoup plus de pages, qui indiquent que vous n'avez pas besoin de protection CSRF, si vous n'utilisez pas de cookies pour l'authentification. Bien sûr, vous pouvez toujours utiliser des cookies pour tout le reste, mais évitez de stocker quoi que ce soit comme à l' session_idintérieur.


Si vous devez vous souvenir de l'utilisateur, il existe 2 options:

  1. localStorage: Un magasin de valeurs-clés dans le navigateur. Les données stockées seront disponibles même après que l'utilisateur ferme la fenêtre du navigateur. Les données ne sont pas accessibles par d'autres sites Web, car chaque site dispose de son propre stockage.

  2. sessionStorage: Également un magasin de données dans le navigateur. La différence est la suivante: les données sont supprimées lorsque l'utilisateur ferme la fenêtre du navigateur. Mais cela reste utile si votre webapp se compose de plusieurs pages. Vous pouvez donc faire ce qui suit:

    • L'utilisateur se connecte, puis vous stockez le jeton dans sessionStorage
    • L'utilisateur clique sur un lien, qui charge une nouvelle page (= un lien réel , et pas de remplacement de contenu javascript)
    • Vous pouvez toujours accéder au jeton depuis sessionStorage
    • Pour vous déconnecter, vous pouvez supprimer manuellement le jeton sessionStorageou attendre que l'utilisateur ferme la fenêtre du navigateur, ce qui effacera toutes les données stockées.

(pour les deux, regardez ici: http://www.w3schools.com/html/html5_webstorage.asp )


Existe-t-il des normes officielles pour l'authentification des jetons?

JWT (Json Web Token): Je pense que c'est encore un brouillon, mais il est déjà utilisé par de nombreuses personnes et le concept semble simple et sécurisé. (IETF: http://tools.ietf.org/html/draft-ietf-oauth-json-web-token-25 )
Il existe également des bibliothèques pour de nombreux frameworks disponibles. Juste google pour ça!

Benjamin M
la source
37
Excellent résumé sur CSRF! Je noterai que le stockage de vos jetons dans localStorage ou sessionStorage est vulnérable aux attaques XSS et que les données peuvent être visualisées par des scripts sur la page - donc si vous avez un script compromis servi à partir d'un CDN ou s'il y a du code malveillant dans l'un de vos Bibliothèques JS, ils peuvent voler le jeton hors de ces emplacements de stockage. Voir: stormpath.com/blog/ ... Je pense que l'approche la plus sûre consiste à stocker un jeton JWT + CSRF dans le cookie, puis à placer votre JWT calculé avec le jeton CSRF à l'intérieur dans l'en-tête de la requête.
Aaron Gray
Concernant: "La précaution la plus élémentaire que vous pouvez prendre est de vous assurer que votre application n'effectue jamais d'effets secondaires en réponse aux requêtes GET." Une attaque CSRF peut-elle simuler une requête POST?
Costa
En fonction de l'application côté serveur, cela PEUT être possible. Il existe des cadres Web qui utilisent quelque chose comme http://.../someRestResource?method=POST. Il s'agit donc essentiellement d'une GETrequête, mais l'application serveur l'interprète comme une POSTrequête, car elle a été configurée pour utiliser le methodparamètre au lieu de l'en-tête HTTP. ...En ce qui concerne les navigateurs Web courants, ils appliquent la politique de même origine et n'exécuteront que les GETdemandes adressées aux serveurs étrangers. Bien qu'il pourrait être possible d'exécuter les POSTrequêtes si le navigateur Web ne concerne pas les standards du Web (bug, les logiciels malveillants).
Benjamin M
1
Ajout au Server Side App: Il n'est toujours pas possible d'envoyer un corps de requête, car les navigateurs courants ne le permettent pas. Cependant, si l'application serveur le permet method=POST, elle peut également permettre body={someJson}de remplacer le corps de la demande par défaut. C'est vraiment une mauvaise conception d'API et extrêmement risquée. Cependant, si votre application serveur le permet, http://...?method=POST&body={someJson}vous devriez vraiment réfléchir à ce que vous avez fait là-bas et pourquoi et si cela est nécessaire du tout. (Je dirais que dans 99 9999% des cas, ce n'est pas nécessaire). De plus, les navigateurs ne peuvent envoyer que quelques kilo-octets de cette manière.
Benjamin M
@BenjaminM remarque que la politique de la même origine empêche uniquement le code javaScript d'accéder au résultat.Ainsi, lorsque la requête est "bloquée", elle atteint réellement le serveur - jsbin.com/mewaxikuqo/edit?html,js , sortie Je n'ai testé cela que sur Firefox, mais vous pouvez ouvrir les outils de développement et voir que même si vous obtenez "Cross-Origin Request Blocked", le serveur distant voit en fait la requête entière. c'est pourquoi vous devez avoir des jetons ou des en-têtes personnalisés (et si possible les deux) à toutes vos requêtes POST
Yoni Jah
59

TL; DR

Un JWT, s'il est utilisé sans cookies, élimine le besoin d'un jeton CSRF - MAIS! en stockant JWT dans session / localStorage, vous exposez votre JWT et l'identité de l'utilisateur si votre site présente une vulnérabilité XSS (assez courante). Il est préférable d'ajouter une csrfTokenclé de JWT et de stocker le JWT dans un cookie avec secureet http-onlyattributs définis.

Lisez cet article avec une bonne description pour plus d'informations https://stormpath.com/blog/where-to-store-your-jwts-cookies-vs-html5-web-storage

Vous pouvez rendre cette protection CSRF sans état en incluant une revendication xsrfToken JWT:

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

Vous devrez donc stocker le csrfToken dans localStorage / sessionStorage ainsi que dans le JWT lui-même (qui est stocké dans un cookie http uniquement et sécurisé). Ensuite, pour la protection csrf, vérifiez que le jeton csrf dans le JWT correspond à l'en-tête csrf-token soumis.

Scott Jungwirth
la source
2
Doit-on exempter l'utilisation du jeton CSRF lors de l'authentification par API de l'utilisateur?
user805981
3
Il convient de souligner (comme d'autres l'ont également mentionné dans les commentaires sur le lien source) que toute atténuation CSRF qui utilise a) des cookies, qui ne sont pas uniquement http ou b) stocke le jeton CSRF dans le stockage local est vulnérable à XSS. Cela signifie que l'approche présentée peut aider à garder le JWT secret d'un attaquant utilisant XSS, mais un attaquant serait toujours en mesure d'exécuter une requête malveillante sur votre API car il est capable de fournir un JWT valide (via le cookie, merci navigateur) et jeton CSRF (lu via JS injecté à partir du stockage / cookie local).
Johannes Rudolph
1
En fait, même un jeton CSRF ne peut pas vous protéger à ce niveau de XSS, car vous supposez que l'attaquant peut accéder à localStorage, dont le seul moyen actuellement d'y accéder est d'avoir un accès au niveau du script, auquel ils peuvent quand même jeter un œil au jeton CSRF. .
itsnotvalid le
1
N'est-ce pas ce que disait @JohannesRudolph? Dès que vous stockez le jeton CSRF dans un cookie de stockage Web / non-http uniquement, vous augmentez votre empreinte d'une attaque XSS car celles-ci sont accessibles via JS.
adam-beck
1
Pas un expert total ici, mais si vous êtes toujours exposé à XSS comme vous l'étiez au début, je ne suis pas sûr que la partie qu'il vaut mieux ajouter ... tient vraiment. Il est probablement un peu (?) Plus compliqué pour un attaquant de mettre la main sur le jeton CSRF, mais à la fin, il est toujours en mesure d'effectuer une requête en votre nom, même sans connaître réellement le jeton JWT. Est-ce exact? Merci
superjos