web-dev-qa-db-fra.com

CORS - Quelle est la motivation derrière l’introduction de demandes de contrôle en amont?

Le partage de ressources d'origine croisée est un mécanisme qui permet à une page Web de créer XMLHttpRequests dans un autre domaine (à partir de wikipedia ).

Je bricole la CORS depuis deux jours et je pense comprendre assez bien le fonctionnement de tout.

Ma question ne porte donc pas sur le fonctionnement de CORS/preflight, mais sur la raison pour laquelle le pré-contrôle est proposé comme nouveau type de requête . Je ne vois aucune raison pour laquelle le serveur A doit envoyer un contrôle en amont (PR) au serveur B simplement pour savoir si la demande réelle (RR) sera acceptée ou non - il serait certainement possible pour B d’accepter/de rejeter RR sans tout PR précédent.

Après avoir cherché pas mal de choses, j'ai trouvé cette pièce des informations sur www.w3.org (7.1.5):

Pour protéger les ressources contre les requêtes d'origine croisée qui ne pouvaient pas provenir de certains agents utilisateurs avant que cette spécification n'existe, une requête de contrôle en amont est effectuée pour garantir que la ressource est au courant de cette spécification.

Je trouve que c'est la phrase la plus difficile à comprendre. Mon interprétation (il est préférable de l'appeler "meilleure estimation") est qu'il s'agit de protéger le serveur B contre les requêtes du serveur C qui ne sont pas au courant des spécifications.

Quelqu'un peut-il s'il vous plaît expliquer un scénario/montrer un problème que PR + RR résout mieux que RR seul?

324
jan groth

J'ai passé un certain temps à me demander quel était l'objectif de la demande de contrôle en amont, mais je pense que je l'ai compris maintenant.

L'idée clé est que les demandes de contrôle en amont ne sont pas une chose sécurité. Plutôt, ils sont une chose ne pas changer les règles.

Les demandes de contrôle en amont n’ont rien à voir avec la sécurité, elles n’ont aucune incidence sur les applications en cours de développement, qui connaissent la CORS. Au lieu de cela, le mécanisme de contrôle en amont bénéficie aux serveurs qui ont été développés sans être informés de CORS, et il fonctionne comme un contrôle de cohérence entre le client et le serveur. les deux CORS-conscient. Les développeurs de CORS ont estimé que suffisamment de serveurs reposaient sur l’hypothèse qu’ils ne recevraient jamais, par exemple. une requête DELETE inter-domaines invitant à inventer le mécanisme de contrôle en amont pour permettre aux deux parties de participer. Ils ont estimé que l'alternative, qui aurait été simplement de permettre les appels entre domaines, aurait détruit trop d'applications existantes.

Il y a trois scénarios ici:

  1. Anciens serveurs, qui ne sont plus en développement et développés avant la SCRO. Ces serveurs peuvent supposer qu'ils ne recevront jamais, par exemple. une requête DELETE inter-domaines. Ce scénario est le principal bénéficiaire du mécanisme de contrôle en amont. Oui, ces services pourraient déjà être utilisés abusivement par un agent utilisateur malveillant ou non conforme (et CORS ne fait rien pour changer cela), mais dans un monde avec CORS le mécanisme de contrôle en amont fournit un "contrôle de sécurité" supplémentaire afin que les clients et les serveurs ne se cassent pas, car les règles sous-jacentes du Web ont été modifiées.

  2. Serveurs en cours de développement, mais contenant beaucoup de code ancien et pour lesquels il n'est pas possible/souhaitable de vérifier tout le code ancien pour s'assurer qu'il fonctionne correctement dans un monde interdomaine. Ce scénario permet aux serveurs d’adhérer progressivement à CORS, par exemple. en disant "Maintenant, je vais autoriser cet en-tête", "Maintenant, je vais autoriser ce verbe HTTP", "Maintenant, je vais autoriser l'envoi de cookies/informations d'authentification", etc. Ce scénario bénéficie des avantages suivants: le mécanisme de contrôle en amont.

  3. Nouveaux serveurs écrits avec une connaissance de CORS. Selon les pratiques de sécurité standard, le serveur doit protéger ses ressources contre ( toute requête entrante - les serveurs ne peuvent pas faire confiance aux clients pour ne pas faire de mal. des choses. Ce scénario ne bénéficie pas du mécanisme de contrôle en amont: le mécanisme de contrôle en amont n'apporte aucune sécurité supplémentaire à un serveur qui a correctement protégé ses ressources.

292
Michael Iles

Quelle était la motivation qui a poussé à introduire des requêtes de contrôle en amont?

Les demandes de contrôle en amont ont été introduites afin qu'un navigateur puisse être certain de traiter avec un serveur compatible CORS avant d'envoyer certaines demandes. Ces demandes ont été définies comme étant celles qui étaient à la fois potentiellement dangereuses (changement d’état) et nouvelles (impossible avant CORS en raison de la = politique de la même origine ). L'utilisation de demandes de contrôle en amont signifie que les serveurs doivent accepter (en répondant correctement au contrôle en amont) les nouveaux types de demandes potentiellement dangereux que CORS rend possibles.

C’est le sens de cette partie de la spécification : "Pour protéger les ressources contre les requêtes inter-origines qui ne pourraient pas provenir de certains agents utilisateurs avant que cette spécification n’existe, une demande de contrôle en amont est faite pour garantir que la ressource est au courant. de cette spécification. "

Pouvez-vous me donner un exemple?

Imaginons qu'un utilisateur du navigateur soit connecté à son site bancaire à l'adresse A.com. Lorsqu'ils accèdent au B.com malveillant, cette page inclut du Javascript qui tente d'envoyer une demande DELETE à A.com/account. Puisque l'utilisateur est connecté à A.com, cette demande, si elle est envoyée, inclurait des cookies qui identifient l'utilisateur.

Avant CORS, la politique de la même origine du navigateur l'aurait empêché d'envoyer cette demande. Mais puisque le but de la SCRO est de rendre possible ce type de communication croisée, ce n’est plus approprié.

Le navigateur pourrait simplement envoyer le DELETE et laisser le serveur décider comment le gérer. Mais que se passe-t-il si A.com n'est pas au courant du protocole CORS? Cela pourrait aller de l'avant et exécuter le dangereux DELETE. Il aurait pu présumer que, en raison de la politique de la même origine du navigateur, le navigateur ne pouvait jamais recevoir une telle demande et qu'il n'aurait donc jamais pu être renforcé contre une telle attaque.

Pour protéger ces serveurs non compatibles avec CORS, le protocole exige que le navigateur envoie d'abord une demande de contrôle en amont . Seuls les serveurs sensibles à la CORS peuvent répondre correctement à ce nouveau type de demande, ce qui permet au navigateur de savoir s’il est sûr ou non d’envoyer le fichier DELETE.

Pourquoi tout ce tapage autour du navigateur, l'attaquant ne peut-il pas simplement envoyer une requête DELETE depuis son propre ordinateur?

Bien sûr, mais une telle requête n'inclura pas les cookies de l'utilisateur. L'attaque que cela est conçu pour empêcher repose sur le fait que le navigateur enverra des cookies (en particulier des informations d'authentification pour l'utilisateur) pour l'autre domaine avec la demande.

Cela ressemble à falsification de requête intersites , où un formulaire sur site B.com peut POST à A.com avec les cookies de l'utilisateur et fait des dégâts.

C'est vrai. En d'autres termes, les demandes de contrôle en amont ont été créées pour ne pas augmenter la surface d'attaque CSRF pour les serveurs non compatibles CORS.

Mais en regardant exigences pour les requêtes "simples" qui ne nécessitent pas de preflights, je vois que POST est toujours permis. Cela peut changer d'état et supprimer des données comme un DELETE!

C'est vrai! CORS ne protège pas votre site contre les attaques CSRF. Là encore, sans CORS, vous n'êtes également pas protégé contre les attaques CSRF. Le but des demandes de contrôle en amont est simplement de limiter votre exposition aux CSRF à ce qui existait déjà dans le monde antérieur à la CORS.

Soupir. OK, j'accepte à contrecœur la nécessité de demandes de contrôle en amont. Mais pourquoi devons-nous le faire pour chaque ressource (URL) sur le serveur? Le serveur gère CORS ou non.

Êtes-vous sûr de cela? Il n'est pas rare que plusieurs serveurs gèrent les demandes d'un seul domaine. Par exemple, il se peut que les demandes adressées à A.com/url1 soient gérées par un type de serveur et que les demandes adressées à A.com/url2 soient gérées par un type de serveur différent. En règle générale, le serveur qui gère une seule ressource ne peut pas garantir la sécurité de toutes les ressources de ce domaine.

Bien. Faisons des compromis. Créons un nouvel en-tête CORS qui permet au serveur d'indiquer exactement les ressources pour lesquelles il peut parler, afin d'éviter des demandes de contrôle en amont supplémentaires pour ces URL.

Bonne idée! En fait, l'en-tête Access-Control-Policy-Path a été proposé uniquement à cette fin. En fin de compte, cependant, il a été laissé en dehors de la spécification, apparemment parce que certains serveurs ont incorrectement implémenté la spécification URI de telle sorte que les requêtes sur des chemins qui semblaient sécurisés pour le navigateur ne le seraient pas en réalité sur le serveur. serveurs cassés.

S'agissait-il d'une décision prudente qui privilégiait la sécurité aux performances, permettant aux navigateurs d'implémenter immédiatement la spécification CORS sans mettre en danger les serveurs existants? Ou a-t-il été myope de condamner Internet à un gaspillage de bande passante et à un temps de latence doublé, juste pour compenser les bugs sur un serveur donné à un moment donné?

Les opinions diffèrent.

Eh bien, au moins les navigateurs vont-ils mettre en cache le contrôle en amont pour une seule URL?

Oui. Bien que probablement pas pour très longtemps. Dans les navigateurs WebKit, la durée maximale du cache de contrôle en amont est de actuellement 10 minutes .

Soupir. Eh bien, si je sais que mes serveurs sont compatibles CORS, et n’ont donc pas besoin de la protection offerte par les demandes de contrôle en amont, puis-je les éviter?

Votre seule option réelle est de vous assurer que vous remplissez les exigences pour les demandes "simples". Cela pourrait signifier de laisser de côté les en-têtes personnalisés que vous auriez sinon inclus (comme X-Requested-With), de mentir sur le Content-Type, ou plus.

Quoi que vous fassiez, vous devez vous assurer que vous avez mis en place les protections CSRF appropriées, car la spécification CORS ne traite pas du rejet des demandes "simples", y compris du non sécurisé POST. Comme l'indique la spécification : "les ressources pour lesquelles les requêtes simples ont une signification autre que l'extraction doivent se protéger contre le falsification de requêtes intersites".

158

Pensez au monde des requêtes interdomaines avant CORS. Vous pouvez créer un formulaire POST standard ou utiliser une balise script ou image pour émettre une demande GET. Vous ne pouvez pas créer d'autre type de demande que GET/POST et vous ne pouvez pas émettre d'en-tête personnalisé pour ces demandes.

Avec l'avènement de la SCRO, les auteurs de spécifications ont été confrontés au défi d'introduire un nouveau mécanisme inter-domaines sans rompre la sémantique existante du Web. Ils ont choisi de le faire en donnant aux serveurs un moyen d'adhérer à tout nouveau type de requête. Cette opt-in est la demande de preflight.

Ainsi, les requêtes GET/POST sans en-têtes personnalisés n'ont pas besoin de contrôle en amont, car elles étaient déjà possibles avant CORS. Mais toute demande avec en-têtes personnalisés, ou demandes PUT/DELETE, do nécessite un contrôle en amont, car ils sont nouveaux dans la spécification CORS. Si le serveur ne sait rien de CORS, il répondra sans en-têtes spécifiques à CORS et la demande réelle ne sera pas faite.

Sans la demande de contrôle en amont, les serveurs pourraient commencer à voir les demandes inattendues des navigateurs. Cela pourrait poser un problème de sécurité si les serveurs n'étaient pas préparés à ces types de demandes. Le contrôle en amont de CORS permet aux requêtes interdomaines d'être introduites sur le Web de manière sécurisée.

50
monsur

CORS vous permet de spécifier plus d'en-têtes et de types de méthodes que ce qui était possible auparavant avec l'origine croisée <img src> ou <form action>.

Certains serveurs auraient pu être (mal) protégés en supposant qu'un navigateur ne puisse pas le faire, par exemple. cross-Origin DELETE requête ou cross-Origin avec l'en-tête X-Requested-With, ces demandes sont donc "approuvées".

Le contrôle en amont est exécuté pour s'assurer que le serveur prend réellement en charge CORS et ne fait pas que répondre à des requêtes aléatoires.

32
Kornel

Voici une autre façon de voir les choses, en utilisant du code:

<!-- hypothetical exploit on evil.com -->
<!-- Targeting banking-website.example.com, which authenticates with a cookie -->
<script>
jQuery.ajax({
  method: "POST",
  url: "https://banking-website.example.com",
  data: JSON.stringify({
    sendMoneyTo: "Dr Evil",
    amount: 1000000
  }),
  contentType: "application/json",
  dataType: "json"
});
</script>

Pré-CORS, la tentative d’exploitation ci-dessus échouerait car elle violerait la politique de même origine. Une API conçue de cette manière ne nécessitait pas de protection XSRF, car elle était protégée par le modèle de sécurité natif du navigateur. Il était impossible pour un navigateur antérieur à CORS de générer un JSON POST cross-Origin.

Maintenant, la SCRO arrive sur les lieux - si l’adhésion à la SCAN via le pré-vol n’était pas nécessaire, ce site deviendrait soudainement une énorme vulnérabilité, sans que ce soit de leur faute.

Pour expliquer pourquoi certaines demandes sont autorisées à sauter le pré-vol, ceci est répondu par les spécifications:

Une demande simple d'origine croisée a été définie comme étant congruente avec celles pouvant être générées par des agents utilisateurs actuellement déployés qui ne sont pas conformes à cette spécification.

Pour résoudre ce problème, GET n'est pas pré-piloté car il s'agit d'une "méthode simple" telle que définie au 7.1.5. (Les en-têtes doivent également être "simples" pour éviter le pré-vol). Cela se justifie par le fait qu'une "simple" demande GET d'origine croisée pourrait déjà être exécutée, par exemple. <script src=""> (C’est ainsi que fonctionne JSONP). Etant donné que tout élément avec un attribut src peut déclencher une opération GET à origine croisée, sans pré-vol, il n'y aurait aucun avantage en termes de sécurité à exiger l'exigence de pré-combat sur de "simples" XHR.

15
Dylan Tack

Je pense que les autres réponses ne mettent pas l'accent sur la raison pour laquelle la pré-combat améliore la sécurité.

Scénarios:

1) avec pré-vol. Un attaquant falsifie une requête du site dummy-forums.com alors que l'utilisateur est authentifié auprès de safe-bank.com
Si le serveur ne vérifie pas l'origine et qu'il a une faille, le navigateur émettra une demande de pré-vol, OPTION méthode. Le serveur ne sait rien de ce CORS que le navigateur attend en réponse, donc le navigateur ne fonctionnera pas (aucun dommage).

2) Sans pré-vol. Un attaquant falsifie la demande dans le même scénario que précédemment, le navigateur émettra immédiatement la demande POST ou PUT, le serveur l’acceptera et pourrait la traiter, ce qui pourrait éventuellement causer des torts.

Si l'attaquant envoie une requête directement, croisez Origin, auprès d'un hôte aléatoire, il est fort probable que l'on songe à une requête avec une authentification non. C'est une demande falsifiée, mais pas une demande xsrf. donc le serveur va vérifier les informations d'identification et échouer. CORS n'essaie pas d'empêcher un attaquant disposant des informations d'identification pour émettre des demandes, bien qu'une liste blanche puisse aider à réduire ce vecteur d'attaque.

Le mécanisme de pré-vol ajoute sécurité et cohérence entre les clients et les serveurs. Je ne sais pas si cela vaut la poignée de main supplémentaire pour chaque demande puisque la mise en cache est difficile à utiliser là-bas, mais c'est ainsi que cela fonctionne.

12
Hirako

De plus, pour les méthodes de requête HTTP pouvant causer des effets secondaires sur les données de l'utilisateur (en particulier, pour les méthodes HTTP autres que GET ou pour POST utilisation avec certains types MIME), la spécification oblige les navigateurs à "contrôler en amont" la requête

Source

3
Oliver Weichhold

Les requêtes de contrôle en amont concernant les performances ? Avec les demandes de contrôle en amont, un client peut savoir rapidement si l’opération est autorisée avant d’envoyer une grande quantité de données, par exemple, en méthode JSON avec PUT. Ou avant de voyager des données sensibles dans les en-têtes d'authentification sur le fil.

Le fait de PUT, DELETE et d’autres méthodes, outre les en-têtes personnalisés, n’est pas autorisé par défaut (ils ont besoin d’une autorisation explicite avec les méthodes "Access-Control-Request-Methods" et "Access-Control-Request-Headers"). comme une double vérification, car ces opérations pourraient avoir plus d'implications pour les données utilisateur, plutôt que des requêtes GET. Donc, cela ressemble à:

"J'ai vu que vous autorisiez les requêtes intersites de http: //foo.example , MAIS êtes-vous SÛR que vous autoriserez les requêtes DELETE? Avez-vous pris en compte les impacts que ces requêtes pourraient causer dans les données de l'utilisateur? "

Je n'ai pas compris la corrélation citée entre les demandes de contrôle en amont et les avantages des anciens serveurs. Un service Web qui a été implémenté avant CORS, ou sans aucune connaissance de CORS, ne recevra jamais AUCUNE requête intersite, car sa réponse n'aura d'abord pas l'en-tête "Access-Control-Allow-Origin".

1
Nipo

Dans un navigateur prenant en charge CORS, les requêtes lecture (comme GET) sont déjà protégées par la règle de même origine: ou l'interface de configuration du routeur) ne sera pas en mesure de lire les données renvoyées car la banque ou le routeur ne définit pas l'en-tête Access-Control-Allow-Origin.

Cependant, avec écrit requêtes (comme POST), le dommage est causé lorsque la requête arrive sur le serveur Web. * Un serveur Web peut vérifier l’en-tête Origin pour déterminer si la requête est légitime, mais ceci check n'est souvent pas implémenté car le serveur Web n'a pas besoin de CORS ou est plus ancien que le serveur CORS et suppose donc que les POST entre domaines sont complètement interdites par la règle de même origine.

C’est pourquoi les serveurs Web ont la possibilité de accepter de recevoir des demandes d’écriture entre domaines.

* Essentiellement la version AJAX de CSRF.

1
AndreKR