Gestion de CORS dans les applications Web

0
16
Shutterstock/Gorodenkoff

CORS est un navigateur mécanisme qui permet aux serveurs de spécifier les origines tierces qui peuvent leur demander des ressources. C'est une protection de sécurité qui aide à empêcher les sites malveillants de voler des données appartenant à d'autres origines.

CORS signifie Cross-Origin Resource Sharing. Lorsque CORS est utilisé pour charger une ressource, le navigateur envoie généralement un “preflight” Requête HTTP OPTIONS. Le serveur doit répondre en précisant les origines avec lesquelles il va interagir. Il peut également définir des contraintes supplémentaires, telles que les en-têtes HTTP qui peuvent être envoyés.

Le navigateur vérifie l'origine actuelle et la requête sortante par rapport aux spécifications du serveur. La demande est autorisée à se poursuivre si tous les contrôles sont réussis. Dans le cas contraire, la demande initiale sera annulée. Vous voyez un avertissement dans la console lorsque cela se produit.

Quand CORS est utilisé

Les navigateurs appliquent CORS pour les requêtes Ajax et Fetch. Le mécanisme sera également utilisé pour les polices Web, les textures WebGL et les dessins d'images de canevas avec drawImage(). Toute demande éligible à une origine tierce nécessitera un échange CORS.

CORS ne sera pas appliqué si la demande est considérée comme “simple”. Une requête simple doit être GET, HEAD ou POST avec un type de contenu text/plain, application/x-www-form-urlencoded ou multipart/form-data. Les seuls en-têtes de requête simple autorisés sont Accept, Accept-Language, Content-Language et Content-Type.

Si la demande ne répond pas à tous les critères ci-dessus, un échange CORS sera lancé par les navigateurs modernes. Il est important de reconnaître que CORS est une technologie basée sur un navigateur – vous ne rencontrerez jamais CORS en faisant des demandes manuellement, comme avec curl dans votre terminal.

Les échanges CORS n'envoient pas toujours une demande de contrôle en amont OPTIONS. Un contrôle en amont est utilisé lorsque la demande entraînerait des “effets secondaires” sur le serveur. C'est généralement le cas pour les méthodes de requête autres que GET.

Imaginez une requête POST à ​​/api/users/create. Le serveur créerait toujours un nouvel utilisateur mais le navigateur pourrait refuser l'accès à la réponse si la demande était soumise au CORS. En envoyant d'abord une requête OPTIONS, le serveur a la possibilité de refuser explicitement la vraie requête. Cela garantit que le compte utilisateur n'est pas réellement créé.

Gestion du CORS côté client

Bien que CORS soit une technologie de navigateur, vous ne pouvez pas l'influencer directement avec le code côté client. Cela empêche les scripts malveillants de contourner les protections CORS pour charger des données à partir de domaines tiers.

CORS est généralement transparent, vous ne saurez donc pas qu'il fonctionne. Si un échange CORS échoue, votre code JavaScript verra une erreur de réseau générique. Il n'est pas possible d'obtenir des détails précis sur ce qui s'est mal passé, car cela constituerait un risque pour la sécurité. Les détails complets sont enregistrés dans la console.

La seule façon de résoudre un échec CORS est de s'assurer que votre serveur envoie les en-têtes de réponse corrects. Voyons maintenant comment cela se fait.

Gestion du CORS côté serveur

Vous devez d'abord vous assurer que votre serveur gère correctement les requêtes OPTIONS. Vous devrez peut-être créer une nouvelle route dans votre framework Web. Vous devrez généralement accepter les requêtes OPTIONS sur chaque point de terminaison susceptible de recevoir une requête cross-origin d'un navigateur. La réponse n'a pas besoin d'avoir un corps mais doit inclure des en-têtes spécifiques qui indiquent au navigateur comment procéder.

Commencez par ajouter l'en-tête Access-Control-Allow-Origin. Cela spécifie l'origine tierce autorisée à communiquer avec votre point de terminaison. Une seule origine peut être spécifiée ; vous pouvez gérer plusieurs origines en définissant dynamiquement la valeur de l'en-tête sur l'origine à partir de laquelle la demande a été envoyée. Vous pouvez obtenir l'origine actuelle à partir de l'en-tête de la demande Origin.

Access-Control-Allow-Origin accepte * comme valeur générique spéciale. Cela autorisera les requêtes CORS de toutes origines. Faites attention lorsque vous utilisez ce – être précis avec les origines autorisées vous donne plus de contrôle et empêche les scripts malveillants de demander des données à votre serveur.

Access-Control-Allow-Origin doit être inclus dans la réponse de votre serveur à la demande réelle, ainsi que dans la réponse OPTIONS. Une fois cet en-tête unique configuré, un échange de base avec un client navigateur tiers sera autorisé.

Spécification des en-têtes Cross-Origin

Les requêtes CORS ne prennent généralement en charge que le “simple” en-têtes de requête répertoriés ci-dessus. Si vous devez utiliser un autre en-tête, tel que Authorization ou un en-tête personnalisé, votre serveur devra l'autoriser explicitement dans la réponse de contrôle en amont.

Définissez l'en-tête Access-Control-Allow-Headers. Sa valeur doit être une liste de noms d'en-tête séparés par des virgules qui seront acceptés avec la vraie requête.

Access-Control-Allow-Headers : Authorization, X-Custom-Header

Le navigateur autorise désormais la poursuite d'une requête avec les en-têtes Authorization ou X-Custom-Header.

Lorsque le navigateur envoie une demande de contrôle en amont CORS, il enverra l'en-tête Access-Control-Request-Headers. Celui-ci contient la liste des en-têtes qui seront envoyés avec la demande réelle. Votre code de serveur peut utiliser ces informations pour déterminer comment répondre à la demande de contrôle en amont.

Limitation à des méthodes de requête spécifiques

De la même manière que pour spécifier les en-têtes de requête, les points de terminaison du serveur peuvent définir quelles méthodes HTTP doivent être autorisées pour l'origine croisée. Définissez l'en-tête Access-Control-Allow-Methods en tant que liste de noms de méthodes séparés par des virgules.

Access-Control-Allow-Methods : GET, POST, DELETE

Le navigateur envoie le Access-Control-Request- En-tête de méthode avec les contrôles en amont CORS. Cela permet à votre serveur de connaître la méthode HTTP qui sera utilisée pour effectuer la requête finale.

Cookies et informations d'identification

Les demandes CORS n'envoient normalement pas de cookies car ils pourraient contenir des informations d'identification sensibles identifiant l'expéditeur. Si vous devez inclure des cookies avec une requête cross-origin, vous devez explicitement l'activer dans votre code côté client :

fetch(“https://localhost/demo”, { mode : “cors”, informations d'identification : “inclure” });

De plus, le serveur doit définir l'en-tête de réponse Access-Control-Allow-Credentials: true pour signaler son accord sur l'échange de cookies avec identifiant.

Lorsque vous utilisez Access-Control-Allow-Credentials, vous ne peut utiliser le caractère générique (*) avec Access-Control-Allow-Origin. Le serveur doit spécifier une origine explicite à la place pour protéger la confidentialité de l'utilisateur. Si le caractère générique est envoyé, le navigateur échouera la demande avec une erreur CORS.

Preflight Caching

Les contrôles en amont CORS OPTIONS ajoutent une surcharge à chaque demande que vous faites. Bien que le retard soit à peine perceptible sur une bonne connexion réseau, il est néanmoins inutile lorsque vous appelez le même point de terminaison plusieurs fois de suite.

Vous pouvez demander au navigateur de mettre en cache réponses de contrôle en amont en définissant l'en-tête Access-Control-Max-Age. La valeur doit être la durée en secondes pendant laquelle le navigateur est autorisé à mettre en cache la réponse. Les demandes ultérieures au même point de terminaison au cours de la période donnée n'enverront pas de contrôle en amont CORS.

Conclusion

CORS peut sembler déroutant la première fois que vous le rencontrez. C'est une technologie de navigateur qui est contrôlée par les réponses du serveur. CORS est inévitable et pourtant incontrôlable, à moins que vous n'ayez accès au code côté serveur avec lequel vous interagissez.

La mise en œuvre réelle de CORS est assez simple. Assurez-vous que votre API ou CDN envoie les bons en-têtes de réponse, notamment Access-Control-Allow-Origin. Vous disposerez alors d'une communication cross-origin sécurisée qui vous aidera à vous protéger des mauvais acteurs.