web-dev-qa-db-fra.com

Un cookie CSRF doit-il être HttpOnly?

Nous avons récemment reçu un rapport de sécurité contenant:

Cookie (s) sans indicateur HttpOnly défini

vulnérabilité, que nous avions apparemment dans l'une de nos applications internes.

Le correctif appliqué était aussi simple que de définir le Django's CSRF_COOKIE_HTTPONLY paramètre de configuration à True.

Mais c'est ce qui m'a dérouté. Django dit:

Désigner le cookie CSRF comme HttpOnly n'offre aucune protection pratique car CSRF est uniquement destiné à protéger contre les attaques interdomaines. Si un attaquant peut lire le cookie via JavaScript, ils sont déjà sur le même domaine pour autant que le navigateur le sache, ils peuvent donc faire tout ce qu'ils veulent de toute façon. (XSS est un trou beaucoup plus grand que CSRF.)

Bien que le paramètre offre peu d’avantages pratiques, il est parfois requis par les auditeurs de sécurité.

Cela signifie-t-il qu'il n'y a pas de vulnérabilité réelle ici et que nous devons simplement nous conformer aux règles d'audit de sécurité?

59
alecxe

Comme joe dit , cela ne présente aucun avantage réel en termes de sécurité. C'est un pur théâtre de sécurité. Je voudrais souligner cela à partir de la documentation :

Si vous l'activez et devez envoyer la valeur du jeton CSRF avec une demande AJAX, votre JavaScript doit extraire la valeur d'un formulaire de jeton CSRF caché sur la page plutôt que du cookie.

L'objectif de l'indicateur HttpOnly est de rendre la valeur du cookie non disponible à partir de JavaScript, afin qu'il ne puisse pas être volé en cas de vulnérabilité XSS. Mais le jeton CSRF doit d'une manière ou d'une autre être disponible afin qu'il puisse être soumis deux fois - c'est tout le point avec lui, après tout. Donc Django résout ce problème en incluant la valeur dans un champ de formulaire masqué. Cela annule tout l'avantage de HttpOnly, car un attaquant peut simplement lire la valeur du champ de formulaire au lieu du cookie.

67
Anders

C'est exact. C'est un faux positif et la personne qui vous fournit cette constatation ne comprend malheureusement pas ce qu'elle fait malheureusement. Quelqu'un qui a compris les risques d'attaques mitm et csrf ne vous le fournirait jamais.

10
joe

Je pense que le principal point de confusion ici est que les Django docs parlent spécifiquement du [~ # ~] csrf [~ # ~] cas d'utilisation pour un biscuit. Afin de comprendre pourquoi l'indicateur httpOnly n'ajoute aucune valeur à la prévention du CSRF, vous devez comprendre le CSRF et le fonctionnement des cookies.

CSRF est lorsqu'un tiers déclenche le navigateur de votre utilisateur pour faire une demande à votre serveur, et son navigateur envoie automatiquement les cookies de votre serveur avec la demande, comme prévu. Ce que vous ne voulez pas, c'est que votre serveur interprète cette demande comme venant réellement de votre utilisateur, vous utilisez donc une technique CSRF mitigation . L'intérêt de l'atténuation CSRF est de pouvoir détecter lorsque la demande ne provient pas de votre propre domaine (c'est-à-dire de l'interaction de votre utilisateur avec votre application) .

En bref, comment fonctionnent les cookies: chaque fois que le navigateur d'un utilisateur envoie une demande à votre domaine/serveur, il envoie automatiquement tous les cookies associés à votre domaine, quel que soit l'indicateur httpOnly. Les cookies permettent donc à votre client ou à votre serveur de joindre au navigateur d'un utilisateur des informations qui seront automatiquement renvoyées sur votre serveur avec toute demande de suivi. Les cookies avec l'indicateur httpOnly ne sont pas accessibles depuis javascript. Ils ne devraient probablement pas être considérés comme un endroit sûr pour stocker des informations, mais ils fournissent les fonctionnalités annoncées.

Retour à CSRF implémenté à l'aide d'un cookie - dans ce cas le drapeau httpOnly est inutile - le nœud du CSRF est qu'ils ne le font pas besoin de lire les cookies de votre utilisateur, ils ont juste besoin du navigateur de votre utilisateur pour envoyer les cookies associés à votre serveur avec la demande réseau qu'ils l'ont forcé à envoyer. L'indicateur httpOnly, en général, apporte une valeur en ce qu'il empêche l'accès client à ces cookies, et si votre serveur renvoie des cookies, vous devriez probablement les créer httpOnly. Si vous utilisez un cookie pour CSRF, vous ne devriez pas le faire et vous devriez passer votre temps à repenser cela plutôt que d'en faire un cookie httpOnly. Donc, en général, il semble que ce soit une bonne règle de base - votre serveur ne devrait pas envoyer de cookies non-httpOnly à moins qu'il ne soit spécifiquement destiné à être accédé par le client javascript.

5
colllin

La seule façon dont la prévention CSRF avec double soumission peut fonctionner est d'envoyer le nonce dans un cookie. Si vous l'envoyez dans le corps de réponse HTTP, il peut dans certains cas être analysé par un script envoyant une demande interdomaine (si vous avez autorisé CORS pour cette page), ce qui va à l'encontre de l'objectif de protection contre CSRF. L'idée est que les scripts sur le domaine X ne peuvent pas obtenir la valeur des cookies sur le domaine Y, c'est l'un des principaux piliers de la sécurité sur le Web.

Avec les cookies HTTPOnly, vous ne pourrez pas vous protéger contre CSRF en utilisant la méthode la plus courante - à savoir la double soumission d'un nonce via les cookies et un script sur la page capable de lire les cookies. Voici comment fonctionne cette technique:

1) Générez une valeur nonce que vous stockez sur le serveur pour la session. Il peut s'agir de l'ID de session lui-même ou de quelque chose stocké dans les données associées à la session.

2) Envoyez ceci au client via les en-têtes des cookies sans HTTPSeulement, demandez à Javascript de le saisir et de le stocker (par exemple à court terme ou dans sessionStorage)

3) Soumettez-le avec chaque demande que vous souhaitez protéger contre le CSRF. La demande aurait le sessionId dans le cookie, et également ce nonce dans le corps de la demande ou dans la chaîne de requête d'URL (par exemple pour les demandes GET). Si vous craignez que le nonce se termine dans les journaux ou autre, vous pouvez utiliser à la place Web Crypto pour signer les charges utiles de demande avec HMAC en utilisant ce nonce

4) Le serveur recherchera les données de session et vérifiera si le nonce ne correspond pas, lance une erreur et génère un autre nonce et envoie le cookie. Assurez-vous d'envoyer les nonces uniquement dans les cookies!

Il est regrettable mais vrai que de nombreux outils "d'audit de sécurité" commencent à signaler les cookies non marqués avec httpOnly et recommandent que ce drapeau soit ajouté. Ce drapeau est malheureusement pire qu'inutile: c'est un théâtre de sécurité.

Je ne parle que du drapeau httpOnly. C'est pire qu'inutile, car cela vous fait penser que vous avez esquivé une sorte de balle, alors qu'en fait, la même classe d'attaque peut toujours se produire: l'attaquant doit créer un script pour envoyer le cookie à son serveur, donc ils pourraient tout aussi bien avoir ce script exécute les requêtes réelles dans le contexte de votre session autorisée, de la même manière qu'ils le feraient s'ils avaient votre cookie. Ils écriraient le script à l'avance. Aucun véritable attaquant ne resterait là à 3 heures du matin pour faire des demandes car leur victime a finalement activé un script qui leur a envoyé le cookie. Beaucoup plus probable, ce script est déjà pré-programmé pour faire ce qu'il doit faire. Et si les cookies httpOnly n'existaient pas, les gens se soucieraient davantage de nettoyer leur sortie Javascript pour empêcher XSS, qui est le seul moyen correct de prévenir cette attaque.

3
Gregory Magarshak

La désignation du cookie CSRF comme HttpOnly n'offre aucune protection pratique, car CSRF sert uniquement à protéger contre les attaques interdomaines.

Cela peut être stipulé de manière beaucoup plus générale, et de manière plus simple en supprimant l'aspect technique du "cookie CSRF".

La définition d'un cookie comme HttpOnly, par définition, protège uniquement contre l'accès via document.cookie ou méthodes JS équivalentes. Il n'empêche aucune interaction HTTP qui pourrait avoir été causée par le code JS; toute interaction que l'utilisateur fait via des éléments HTML, comme une soumission de formulaire, peut être lancée par JS. Il n'y a pas de distinction significative sur la façon dont quelque chose a commencé; en fait, vous pouvez revendiquer "l'utilisateur l'a démarré" en pointant sur l'utilisateur en tapant l'URL de la page Web actuelle ou celle d'une page Web liée à la page Web actuelle.

C'est aussi la raison pour laquelle le concept de "lecture automatique de vidéo" n'est pas bien défini et ne peut pas être empêché de manière fiable: ce qui constitue une action volontaire de l'utilisateur pour démarrer une vidéo est un concept d'interface utilisateur, pas un DOM (Document Object Model) concept. Le navigateur ne sait pas que la lecture automatique de l'utilisateur a fait un geste pour lire une vidéo, à moins que la vidéo ne démarre avant que l'utilisateur ne bouge (comme "espace pour faire défiler vers le bas"). (On peut essayer de "wack a mole" la lecture automatique dans quelques cas, comme on peut essayer de "wack a mole" (détecter, mettre sur liste noire) des publicités Web ennuyantes ou partager des informations avec des domaines tiers, mais sans garantie de couverture .)

À moins que JS ne soit complètement désactivé sur un domaine, toute action de l'utilisateur à l'intérieur du cadre contrôlé par le site Web doit simplement être considérée comme réalisable par script du site Web. Sur le Web moderne, qui désactive complètement JS sur la plupart des domaines? Presque personne.

L'observation généralisée est donc:

Désigner un cookie comme HttpOnly n'offre aucune protection pratique contre les attaques qui effectuent des actions que l'utilisateur pourrait effectuer via l'interface du site Web.

Notez que la lecture de tous les cookies (y compris ceux marqués HttpOnly) ne se fait pas par l'interface du site Web, elle ne peut l'être qu'avec l'outil Inspector du navigateur ou le proxy HTTP pour les cookies envoyés via HTTP.

3
curiousguy

L'attribut httpOnly peut être omis du cookie anti-CSRF dans Django car, comme beaucoup d'autres réponses et même la question mise en évidence, le code javascript s'exécutant dans les navigateurs victimes qui a chargé un navigateur non autorisé Origin ne pourra pas lire les réponses authentifiées de l'origine autorisée, avec ou sans l'attribut, en raison de la même politique d'origine.

(Ne mélangeons pas l'exigence stricte pour le cookie de session avec celle pour le cookie anti-CSRF).

Django attend des développeurs qu'ils remplissent le formulaire HTML avec le jeton anti-CSRF associé (ou le même) avec le XSRF-TOKEN biscuit.

https://github.com/Django/django/blob/f283ffaa84ef0a558eb466b8fc3fae7e6fbb547c/Django/middleware/csrf.py#L136

Les auteurs Django sont assez prudents pour stipuler la nécessité de l'attribut Secure (qui s'applique à la fois au cookie de session et à l'anti-CSRF). Ils pourraient aussi bien mentionner le besoin d'ajouter le Strict-Transport-Security en-tête de réponse pour éviter l'injection de cookies et/ou l'écoute de l'intégralité de l'interaction en laissant les navigateurs se glisser dans le lien http: // et en réécrivant le trafic non crypté.

Les auteurs du framework ne sont pas stricts sur l'attribut httpOnly car, grâce à la même politique d'origine, les origines non autorisées ne pourraient pas lire les cookies via le code javascript qu'ils génèrent pour les navigateurs; leurs scripts côté serveur tentant d'obtenir les détails du formulaire et les en-têtes de réponse de l'origine autorisée ne recevront que des réponses non authentifiées.

Je suis juste tombé sur une exigence difficile de ne PAS autoriser httpOnly pour un XSRF-TOKEN cookie lorsqu'il est utilisé comme seule source pour les applications à page unique. SPA reposant sur le XSRF-TOKEN le cookie de réponse est toujours sécurisé. Les origines non autorisées, encore une fois, ne pourront pas lire le bon XSRF-TOKEN cookie de réponse en raison de la même politique d'origine. Et les scripts côté serveur non autorisés ne pourraient pas pré-récupérer le bon XSRF-TOKEN cookie de réponse non plus (encore une fois, car les scripts manquent d'authentification avec le serveur autorisé).

https://github.com/expressjs/csurf#single-page-application-spa

2
eel ghEEz

Bien que le jeton CSRF ne soit pas un secret sur une page avec un formulaire protégé par CSRF (et pourrait être volé à l'aide de XSS), vous pouvez avoir une vulnérabilité XSS dans une page sans formulaire. Là, vous ne pouvez obtenir le jeton que depuis le cookie mais pas depuis un champ caché. Dans ce cas, la sécurité est améliorée en utilisant un cookie HttpOnly.

Il existe toujours un moyen d'obtenir le jeton en demandant une page contenant un formulaire via javascript. Il peut y avoir des moyens d'empêcher cela, mais sur la plupart des sites, cette attaque sera possible.

1
allo