Le Blog Amazon Web Services

Configuration de CORS sur les API d’Amazon API Gateway

La configuration des paramètres de partage des ressources entre origines multiples (Cross-origin resource sharing en anglais et son acronyme CORS) pour un serveur back-end est un défi typique auquel les développeurs sont confrontés lors de la création d’applications Web. CORS est une couche de sécurité appliquée par les navigateurs modernes permettant à un agent utilisateur d’accéder aux ressources d’un serveur situé sur une autre origine que le site courant. La complexité de CORS conduit souvent les développeurs à l’abandonner complètement en autorisant un accès total avec le paramètre de permissions « * ». Cependant, CORS est un élément essentiel de la posture de sécurité de votre application et doit être correctement configuré.

Cet article explique comment configurer CORS sur les ressources d’Amazon API Gateway  afin d’imposer le principe de moindre privilège à un point de terminaison à l’aide du AWS Serverless Application Model (AWS SAM). Nous couvrirons les différences CORS notables entre les API REST et les API HTTP. Enfin, nous présenterons le générateur de configuration CORS d’Amazon API Gateway. Il s’agit d’un outil conçu par l’équipe AWS Serverless Developer Advocacy pour vous aider à configurer correctement les paramètres CORS.

Vue d’ensemble

CORS est un mécanisme par lequel un serveur limite l’accès par l’utilisation d’en-têtes. Dans les requêtes qui ne sont pas considérées comme simples, le serveur s’appuie sur le navigateur pour effectuer une requête CORS préliminaire (CORS preflight) ou OPTIONS. Une requête complète ressemble à ceci :

Flux requête CORS

Flux requête CORS

  1. L’application initie une requête
  2. Le navigateur envoie une requête CORS préliminaire
  3. Le serveur renvoie une réponse CORS préliminaire
  4. Le navigateur envoie la requête
  5. Le serveur renvoie une réponse
  6. L’application reçoit la réponse

La requête CORS préliminaire vérifie les exigences du serveur en indiquant l’origine, la méthode et les en-têtes à venir dans la requête originale.

requête OPTIONS préliminaire

requête OPTIONS préliminaire

La réponse du serveur diffère en fonction du backend que vous utilisez. Certains serveurs répondent avec l’origine, les méthodes et les en-têtes autorisés pour le point de terminaison.

Réponse CORS préliminaire

Réponse CORS préliminaire

D’autres ne renvoient les en-têtes CORS que si l’origine, la méthode et les en-têtes demandés répondent aux exigences du serveur. Si les exigences ne sont pas satisfaites, la réponse ne contient pas d’en-tête de contrôle d’accès CORS. Le navigateur vérifie l’origine, la méthode et les en-têtes de la requête par rapport aux données renvoyées dans la réponse préliminaire. Si la validation échoue, le navigateur génère une erreur CORS et interrompt la requête. Si la validation est réussie, le navigateur continue avec la requête originale.

Requête originale

Requête originale

Le navigateur n’envoie que l’en-tête access-control-allow-origin pour vérifier l’origine de la demande pendant la requête originale. Le serveur répond ensuite avec les données demandées.

Réponse originale

Réponse originale

C’est à cette étape que de nombreux développeurs rencontrent des problèmes. Remarquez que le point de terminaison de la requête actuelle renvoie l’en-tête access-control-allow-origin. Le navigateur le vérifie à nouveau avant d’agir.

Le contrôle préliminaire et la réponse réelle nécessitent tous deux une configuration CORS, qui se présente différemment selon que vous sélectionnez l’API REST ou l’API HTTP.

Configuration d’API Gateway pour CORS

Bien qu’Amazon API Gateway propose plusieurs types de points de terminaison d’API, cet article se concentre sur l’API REST (v1) et l’API HTTP (v2). Les deux types créent un point de terminaison REST (Representational State Transfer) qui sert de proxy à une fonction AWS Lambda et d’autres services AWS ou points de terminaison tiers. Les deux types traitent les demandes de contrôle préliminaire. Cependant, il existe des différences à la fois dans la configuration et dans le format de la réponse d’intégration.

Terminologie

Avant de parcourir les exemples de configuration, il est important de comprendre certains termes :

  • Ressource : Un identifiant unique pour le chemin de l’API (/customer/reports/{region}). Les ressources peuvent avoir des sous-ressources qui se combinent pour former un chemin unique.
  • Méthode : les méthodes REST (par exemple, GET, POST, PUT, PATCH) que la ressource prend en charge. La méthode ne fait pas partie du chemin mais est transmise par les en-têtes.
  • Point de terminaison : Une combinaison de ressources et de méthodes pour créer une URL d’API unique.

API REST

  • Une utilisation répandue des API REST d’API Gateway est le proxy d’une ou plusieurs fonctions Lambda pour construire un backend serverless. Dans ce modèle, API Gateway ne modifie pas le contenu de la requête ou de la réponse. Par conséquent, l’API REST gère CORS par une combinaison de configuration de requête préliminaire et une réponse correctement formée de la fonction Lambda.

Requêtes préliminaires

La configuration de CORS sur les API REST se fait généralement en quatre lignes de code avec AWS SAM :

Cors:
    AllowMethods: "'GET, POST, OPTIONS'"
    AllowOrigin: "'http://localhost:3000'"
    AllowHeaders: "'Content-type, x-api-key'"

Cet extrait de code crée une ressource API MOCK qui traite toutes les requêtes préliminaires pour cette ressource. Cette configuration est un exemple de l’accès de moindre privilège au serveur. Elle autorise uniquement les méthodes GET, POST et OPTIONS à partir d’un point de terminaison localhost sur le port 3000. De plus, elle n’autorise que les en-têtes CORS Content-type et x-api-key.

Notez que la réponse à la requête préliminaire n’autorise qu’une seule origine à appeler cette API. Pour activer plusieurs origines avec les API REST, utilisez ‘*’ pour l’en-tête access-control-allow-origin. Vous pouvez également utiliser une intégration de fonction Lambda au lieu d’une intégration MOCK pour définir l’en-tête de manière dynamique en fonction de l’origine de l’appelant.

Autorisation

Lors de la configuration de CORS pour les API REST qui nécessitent une authentification, il est important de configurer le point de terminaison de la requête préliminaire sans autorisation requise. La requête préliminaire est générée par le navigateur et n’inclut pas les informations d’identification par défaut. Pour supprimer l’authorizer de la méthode OPTIONS, ajoutez le paramètre AddDefaultAuthorizerToCorsPreflight : false à la configuration de l’autorisation.

Auth:
    AddDefaultAuthorizerToCorsPreflight: false
    Authorizers:
        MyCognitoAuth:
  
  …

Réponse

Dans les configurations de proxy des API REST, les paramètres CORS ne s’appliquent qu’au point de terminaison OPTIONS et ne couvrent que la requête préliminaire effectuée par le navigateur. La fonction Lambda qui sert la méthode doit répondre avec les informations CORS appropriées pour gérer CORS correctement dans la réponse originale. Voici un exemple de réponse correcte :

{
  "statusCode": 200,
  "headers": {
    "access-control-allow-origin":" http://localhost:3000",
  }
  "body": {"message": "hello world"}
}

Dans cette réponse, les parties importantes sont le statusCode renvoyé à l’utilisateur comme état de la réponse et l’en-tête access-control-allow-origin requis par la validation CORS du navigateur.

API HTTP

À l’instar des API REST, les API HTTP d’Amazon API Gateway sont généralement utilisées pour faire proxy avec des fonctions Lambda et sont configurées pour gérer les requêtes préliminaires. Cependant, contrairement aux API REST, les API HTTP gèrent également les CORS pour la réponse originale de l’API.

Requête préliminaire

L’exemple suivant montre comment configurer CORS sur les API HTTP avec AWS SAM :

CorsConfiguration
  AllowMethods:
    - GET
    - POST
    - OPTIONS
  AllowOrigin:
    - http://localhost:3000
    - https://myproddomain.com
  AllowHeaders:
    - Content-type
    - x-api-key

Ce fragment de code configure les API HTTP pour gérer les CORS pour les requêtes préliminaires et les requêtes originales. Notez que la section AllowOrigin autorise plus d’un domaine. Lorsque le navigateur effectue une requête, les API HTTP vérifie la liste pour l’origine reçue. Si elle existe, les API HTTP l’ajoutent à l’en-tête access-control-allow-origin dans la réponse.

Autorisation

Lors de la configuration de CORS pour les API HTTP avec autorisation configurée, les API HTTP configurent automatiquement le point de terminaison de requête préliminaire sans autorisation requise. La seule exception à cette règle est l’utilisation de la route $default. Lors de la configuration d’une route $default, toutes les méthodes et ressources sont gérées par la route par défaut et l’intégration sous-jacente. Cela inclut la méthode de requête préliminaire OPTIONS.

Il existe deux options pour gérer la requête préliminaire. La première, qui est recommandée, consiste à répartir les routes individuellement. Créez une route spécifique pour chaque méthode et ressource si nécessaire. La seconde consiste à créer une méthode OPTIONS /{proxy+} pour remplacer la route $defaut pour les requêtes préliminaires.

Réponse

Contrairement aux API REST, les API HTTP modifient par défaut la réponse à la demande originale en ajoutant les en-têtes CORS appropriées en fonction de la configuration CORS. Voici un exemple de réponse simple :

"hello world"

Les API HTTP construisent ensuite la réponse complète avec vos données, le code de statut et toutes les en-têtes CORS requises :

{
  "statusCode": 200,
  "headers": {
    "access-control-allow-origin":"[appropriate origin]",
  }
  "body": "hello world"
}

Pour définir le code de statut manuellement, configurez votre réponse comme suit :

{
  "statusCode": 201,
  "body": "hello world"
}

Pour gérer la réponse complète comme dans les API REST, définissez le format du contenu sur la version un. Le format du contenu pour l’API HTTP modifie la structure du contenu envoyée à la fonction Lambda et la réponse attendue de la fonction Lambda. Par défaut, l’API HTTP utilise la version deux, qui inclut les paramètres CORS dynamiques. Pour plus d’informations, lisez comment la version du contenu affecte le format de la réponse dans la documentation.

Le générateur de configuration CORS Amazon API Gateway

L’équipe AWS Serverless Developer Advocacy a construit le générateur de configuration CORS d’Amazon API Gateway pour vous aider à configurer CORS pour vos applications serverless.

Générateur de configuration CORS Amazon API Gateway

Générateur de configuration CORS Amazon API Gateway

Commencez par saisir les informations sur la gauche. Le générateur de configuration CORS crée les extraits appropriés pour ajouter les paramètres CORS à votre modèle AWS SAM au fur et à mesure que vous ajoutez des informations. L’outil montre comment ajouter la configuration à toutes les API du modèle en utilisant la section Globals. Vous pouvez également ajouter la configuration à la ressource spécifique d’une API pour n’affecter que cette API.

En outre, le générateur de configuration CORS construit un exemple de réponse basé sur le type d’API que vous utilisez.

Cet utilitaire est actuellement en version préliminaire et nous vous invitons à nous faire part de vos commentaires sur la façon dont nous pouvons l’améliorer. N’hésitez pas à ouvrir un problème sur GitHub à l’adresse https://github.com/aws-samples/amazon-api-gateway-cors-configurator.

Conclusion

CORS peut être un véritable défi à configurer. Pour API Gateway, la configuration de CORS est la question numéro un que les développeurs posent. Dans cet article, nous vous avons donné un aperçu de CORS avec un lien vers une explication approfondie. Nous avons montré ensuite comment configurer API Gateway pour créer l’accès de moindre privilège à votre serveur en utilisant CORS. Nous avons abordé également les différences dans la façon dont les API REST et les API HTTP gèrent CORS. Enfin, nous avons introduit le générateur de configuration CORS d’API Gateway pour vous aider à configurer CORS à l’aide d’AWS SAM.

Nous espérons vous avoir fourni suffisamment d’informations pour que vous puissiez éviter d’utiliser le paramètre « * » pour CORS sur vos serveurs. Prenez le temps de comprendre votre application et limitez les demandes aux seules méthodes que vous prenez en charge et à partir des seuls serveurs d’origine que vous avez prévus.

Pour plus de contenu serverless, rendez-vous sur Serverless Land.

Article original rédigé par Eric Johnson, Principal Developer Advocate, et adapté en français par Charles Rapp, Solutions Architect dans l’équipe AWS France.