33 points par GN⁺ 2025-03-04 | 1 commentaires | Partager sur WhatsApp
  • En réfléchissant aux Cross-Site Request, il n’était pas évident au départ de comprendre pourquoi il fallait à la fois une protection CSRF et CORS. Mais il faut pas mal de mots pour l’expliquer

CSRF et CORS

  • CSRF (Cross-Site Request Forgery)
    • Autrefois courant, mais aujourd’hui ce n’est presque plus un problème car la plupart des frameworks web fournissent une protection par défaut
    • Mode d’attaque : amener un utilisateur à cliquer sur un formulaire depuis un site malveillant afin de déclencher une requête cross-site
    • Méthode de défense : vérifier que la requête ne provient pas d’un autre site
  • CORS (Cross-Origin Resource Sharing)
    • Fait partie de la spécification HTTP et définit comment autoriser certaines requêtes cross-site
    • Utilise des requêtes préliminaires (preflight) et des en-têtes de réponse pour indiquer quelles origines peuvent envoyer des requêtes

Alors, les requêtes cross-site sont-elles autorisées par défaut, ce qui nécessite une protection CSRF, ou bien bloquées par défaut, ce qui nécessite CORS pour les autoriser ? La réponse est les deux.

Fonctionnement de base

  • Same-origin policy
    • Politique de sécurité imposée par le navigateur
    • En général, les écritures cross-site sont autorisées, mais la lecture est interdite
    • Par exemple, le navigateur autorise une requête POST via un formulaire, mais ne permet pas de lire la réponse
  • Politique de cookies SameSite
    • En 2019, le comportement par défaut des cookies a changé
    • Auparavant, les cookies étaient toujours envoyés dans les requêtes cross-site
    • Le nouvel attribut SameSite a été ajouté, et sa valeur par défaut est passée à Lax
    • En 2025, 96 % des navigateurs prennent en charge l’attribut SameSite, et 75 % appliquent la nouvelle valeur par défaut (Lax)
    • Cependant, Safari ne l’a pas appliqué comme valeur par défaut, et UCBrowser ne le prend toujours pas en charge
  • Différence entre site et origine
    • Origine : combinaison de protocole + nom d’hôte + port
    • Site : combinaison de protocole + domaine de plus haut niveau + 1 (les sous-domaines et le port sont ignorés)

CORS

  • CORS est un mécanisme qui autorise, à titre d’exception, la same-origin policy pour certaines origines
  • Avant d’envoyer la requête, le navigateur envoie une requête preflight de type OPTIONS
  • Le serveur définit les règles d’autorisation via les en-têtes de réponse (avec les en-têtes Access-Control-*)
  • Types de requêtes auxquels CORS s’applique :
    • fetch et XMLHttpRequest
    • Web fonts
    • Textures WebGL
    • Images / frames vidéo dessinées dans un canvas avec drawImage
    • Images utilisées dans la propriété CSS shape-outside
  • En revanche, la soumission de formulaires n’est pas soumise à CORS
    • La balise <form> de HTML 4.0 autorisait déjà les requêtes cross-site depuis très longtemps
    • Les serveurs existants devaient donc déjà être conçus pour se défendre contre les attaques CSRF
    • Pour partager la réponse, le serveur doit définir Access-Control-Allow-Origin, mais la requête elle-même est acceptée sans preflight

Question : comment cette approche reste-t-elle cohérente avec la politique SameSite ?

Méthodes de protection CSRF

  • Les requêtes d’écriture cross-site sont autorisées, mais la réponse n’est pas partagée
    • La plupart des sites web ne souhaitent pas autoriser les écritures cross-site
  • Méthode standard de défense contre le CSRF
    • Inclure et valider un token CSRF propre à chaque utilisateur dans la requête
    • Méthodes :
      • Soumission de formulaire : ajouter le token dans un champ masqué (hidden input)
      • Requêtes JS : le stocker dans un cookie ou une balise meta, puis l’inclure dans un en-tête ou un paramètre de requête
  • Les requêtes JS sont à l’origine bloquées en cross-site par défaut
    • Mais elles sont autorisées pour les requêtes same-site
    • En incluant un token CSRF, il est possible de valider toutes les requêtes de la même manière
  • Avantages de sécurité supplémentaires
    • Le mécanisme fonctionne en partant du principe que le navigateur bloque par défaut la lecture de la réponse
    • C’est plus sûr que de vérifier l’en-tête Origin

Question : dans certains frameworks, les tokens CSRF changent périodiquement. Pourquoi ?

Rôle du navigateur

  • Le cœur de la sécurité web dépend du fait que le navigateur est digne de confiance
  • Le navigateur :
    • applique la same-origin policy
    • empêche la lecture de la réponse lorsqu’elle n’est pas autorisée
    • décide d’appliquer ou non la valeur par défaut SameSite=Lax
    • implémente CORS et envoie des requêtes preflight sûres

Nous devons faire confiance au navigateur que nous utilisons.

Conclusion

  • Si SameSite=Lax était pris en charge par 100 % des navigateurs, la sécurité serait renforcée, mais
    aujourd’hui il existe encore une exception où seules les requêtes POST cross-site restent autorisées
  • Les développeurs doivent donc continuer à prendre la protection CSRF en compte

« Internet devient de plus en plus sûr, mais en contrepartie, la compatibilité avec le passé diminue elle aussi progressivement. »

Sources

  1. Same-origin policy
  2. caniuse SameSite cookie attribute
  3. OWASP CSRF cheatsheet
  4. CORS wiki with requirements
  5. CORS spec
  6. CORS on MDN
  7. Preflight request
  8. Origin request header
  9. Origin and Site

1 commentaires

 
GN⁺ 2025-03-04
Commentaires sur Hacker News
  • CORS est le mécanisme par lequel le serveur indique explicitement au navigateur quelles requêtes cross-origin sont autorisées à lire la réponse

    • Par défaut, le navigateur bloque la lecture de la réponse par un script cross-origin
    • Sauf autorisation explicite, le domaine à l’origine de la requête ne peut pas lire la réponse
    • Par exemple, un script sur evil.com peut envoyer une requête à bank.com/transactions pour tenter de lire l’historique des transactions de la victime
    • Le navigateur autorise la requête à atteindre bank.com, mais empêche evil.com de lire la réponse
  • La protection CSRF empêche des requêtes cross-origin malveillantes d’effectuer des actions non autorisées au nom d’un utilisateur authentifié

    • Par exemple, un script sur evil.com peut envoyer une requête pour effectuer une action sur bank.com (par exemple, transférer de l’argent via bank.com/transfer?from=victim&to=hacker)
    • La protection CSRF côté serveur de bank.com la rejette (probablement parce que la requête ne contient pas de jeton CSRF secret)
  • La protection CSRF concerne la protection en écriture, tandis que CORS concerne la protection en lecture

  • Les requêtes initiées en JS ne sont pas autorisées cross-site par défaut

    • Avec fetch(), il est possible d’initier une requête cross-site en n’utilisant que des en-têtes autorisés
  • Il semble y avoir une meilleure explication de ce sujet

    • Fourniture d’un lien vers un blog connexe
  • Réponse à la question du billet de blog

    • L’élément <form> de HTML 4.0 peut soumettre une requête simple vers n’importe quelle origine
    • Une question a été posée sur la façon dont cela s’articule avec l’initiative SameSite
  • En 2022, un paragraphe a été ajouté à l’article MDN sur CORS pour clarifier l’origine du terme « requête simple »

    • Auparavant, il était seulement indiqué que ce terme n’apparaissait pas dans la spécification fetch
    • En 2019, il n’y avait aucune mention des navigateurs dont les protections anti-CSRF prenaient en charge SameSite=Lax ou le définissaient par défaut
  • Il est déroutant que SameSite ait été ajouté indépendamment de la pré-requête CORS

    • On se demande pourquoi les éditeurs de navigateurs n’ont pas exigé une pré-requête pour toutes les requêtes POST cross-origin
  • On peut penser qu’il est sûr de ne pas utiliser de protection CSRF, mais certaines bibliothèques (par exemple django rest framework) peuvent traiter des formulaires HTML si l’en-tête Content-Type est défini

    • Cela permet de publier un formulaire sur le site d’un utilisateur pour envoyer des requêtes en son nom
  • Question sur la raison pour laquelle les jetons CSRF sont renouvelés

    • OWASP affirme que c’est plus sûr, mais la raison n’est pas claire
  • Demande d’un organigramme pour un sujet complexe

    • Souhait d’une nouvelle plateforme d’application et d’un nouvel ensemble de standards
  • Ces mécanismes ne facilitent pas le diagnostic

    • Expérience répétée d’erreurs opaques dans des cas d’usage légitimes mal configurés
  • Avant l’arrivée de CORS, il est difficile de comprendre pourquoi il était possible d’envoyer des requêtes vers des endpoints arbitraires autres que l’origine de la page sans pouvoir voir la réponse

    • On se demande si cela s’est retrouvé dans la spécification par accident, si cela a été pensé volontairement en anticipant les XSS, ou si un navigateur dominant s’est comporté ainsi et que les autres ont suivi
  • Confusion autour de la protection CSRF

    • On se demande ce qui empêche un attaquant d’obtenir un jeton CSRF sur goodsite.com, de le placer sur badsite.com, puis de piéger Alice pour qu’elle soumette depuis badsite.com une requête vers goodsite.com