95 votes

Configuration correcte de S3 + Cloudfront CORS ?

Mon application stocke les images sur S3, puis les transmet par proxy via Cloudfront. Je suis impatient d'utiliser la nouvelle prise en charge CORS de S3 pour pouvoir utiliser les méthodes de canevas HTML5 (qui ont une politique d'origine croisée), mais je n'arrive pas à configurer correctement mon S3 et mon Cloudfront. Je rencontre toujours le problème "Uncaught Error : SECURITY_ERR : DOM Exception 18" lorsque j'essaie de convertir une image en élément canvas.

Voici ce que j'ai pour l'instant :

S3

<CORSConfiguration>
  <CORSRule>
    <AllowedOrigin>MY_WEBSITE_URL</AllowedOrigin>
    <AllowedMethod>GET</AllowedMethod>
    <MaxAgeSeconds>3000</MaxAgeSeconds>
    <AllowedHeader>*</AllowedHeader>
  </CORSRule>
  <CORSRule>
    <AllowedOrigin>MY_CLOUDFRONT_URL</AllowedOrigin>
    <AllowedMethod>GET</AllowedMethod>
    <AllowedHeader>*</AllowedHeader>
    </CORSRule>
  </CORSConfiguration>

Cloudfront

Origines

Origin Protocol Policy: Match Viewer

HTTP Port: 80

HTTPS Port: 443

Comportements

Origin: MY_WEBSITE_URL

Object Caching: Use Origin Cache Headers

Forward Cookies: None

Forward Query Strings: Yes

Il y a quelque chose qui m'échappe ?

UPDATE : Je viens d'essayer de changer les en-têtes en

<AllowedHeader>Content-*</AllowedHeader>
<AllowedHeader>Host</AllowedHeader>

sur la base de cette question Amazon S3 CORS (Cross-Origin Resource Sharing) et le chargement de polices inter-domaines de Firefox

Toujours rien.

MISE À JOUR : PLUS D'INFORMATIONS SUR DEMANDE

Request
URL:https://d1r5nr1emc2xy5.cloudfront.net/uploaded/BAhbBlsHOgZmSSImMjAxMi8wOS8xMC8xOC81NC80Mi85NC9ncmFzczMuanBnBjoGRVQ/32c0cee8
Request Method:GET
Status Code:200 OK (from cache)

UPDATE

Je pense que ma requête n'était peut-être pas correcte, j'ai donc essayé d'activer CORS avec

img.crossOrigin = '';

mais ensuite l'image ne se charge pas et je reçois l'erreur : Le chargement d'une image d'origine croisée est refusé par la politique de partage des ressources d'origine croisée.

169voto

cha Points 1743

Le 26 juin 2014, AWS a publié approprié Vary : Origine comportement sur CloudFront donc maintenant tu as juste

  1. Définissez une configuration CORS pour votre seau S3 en incluant

    <AllowedOrigin>*</AllowedOrigin>

  2. Dans CloudFront -> Distribution -> Comportements pour cette origine

    • Méthodes HTTP autorisées : +OPTIONS
    • Méthodes HTTP mises en cache +OPTIONS
    • Cache basé sur des en-têtes de requête sélectionnés : Mettre sur une liste blanche les Origin en-tête.
  3. Attendez environ 20 minutes pendant que CloudFront propage la nouvelle règle.

Maintenant, votre distribution CloudFront devrait mettre en cache différentes réponses (avec les en-têtes CORS appropriés) pour différents en-têtes d'origine du client.

73voto

Pour compléter Réponse de @Brett . Il existe des pages de documentation AWS qui détaillent CORS sur CloudFront y CORS sur S3 .

Les étapes qui y sont détaillées sont les suivantes :

  1. Dans votre seau S3, allez dans Permissions -> configuration CORS
  2. Ajouter des règles pour CORS dans l'éditeur, l'onglet <AllowedOrigin> est la règle la plus importante. Sauvegardez la configuration. enter image description here
  3. Dans votre distribution CloudFront, allez dans Comportement -> choisir un comportement -> Modifier
  4. Selon que vous voulez OPTIONS que les réponses soient mises en cache ou non, il y a deux façons de procéder selon AWS :
  • Si vous souhaitez que les réponses OPTIONS soient mises en cache, procédez comme suit :
    • Choisissez les options pour les paramètres de comportement de cache par défaut qui permettent la mise en cache des réponses OPTIONS.
    • Configurez CloudFront pour transférer les en-têtes suivants : Origin, Access-Control-Request-Headers, et Access-Control-Request-Method.
  • Si vous ne souhaitez pas que les réponses OPTIONS soient mises en cache, configurez CloudFront de la manière suivante pour transférer l'en-tête Origin, ainsi que tous les autres en-têtes nécessaires par votre origine

enter image description here

Et avec cela, CORS de CloudFront avec S3 devrait fonctionner.

6voto

Cymen Points 4176

MISE À JOUR : ceci n'est plus vrai avec les changements récents sur CloudFront. Youpi ! Voir les autres réponses pour les détails. Je laisse ceci ici pour le contexte/l'histoire.

Problème

CloudFront ne prend pas en charge CORS à 100 %. Le problème réside dans la façon dont CloudFront met en cache la réponse à la demande. Toute autre demande pour la même URL après cela entraînera la mise en cache de la demande. quelle que soit l'origine . L'élément clé est qu'il inclut les en-têtes de réponse de l'origine.

Première requête avant que CloudFront n'ait mis en cache quoi que ce soit à partir de Origin: http://example.com a un en-tête de réponse de :

Access-Control-Allow-Origin: http://example.com

Deuxième demande de Origin: https://example.com (notez que c'est HTTPS et non HTTP) a également l'en-tête de réponse de :

Access-Control-Allow-Origin: http://example.com

Parce que c'est ce que CloudFront a mis en cache pour l'URL. Ce n'est pas valide. La console du navigateur (dans Chrome au moins) affichera un message de violation CORS et les choses s'arrêteront.

Solution de rechange

La solution proposée consiste à utiliser des URL différentes pour des origines différentes. L'astuce consiste à ajouter une chaîne de requête unique qui est différente afin qu'il y ait un enregistrement en cache par origine.

Nos URLs seraient donc quelque chose comme :

http://.../some.png?http_mysite.com
https://.../some.png?https_mysite.com

Cela fonctionne en quelque sorte, mais n'importe qui peut faire en sorte que votre site fonctionne mal en intervertissant les chaînes de requête. Est-ce probable ? Probablement pas, mais le débogage de ce problème est très compliqué.

La bonne solution consiste à ne pas utiliser CloudFront avec CORS jusqu'à ce qu'il prenne entièrement en charge CORS.

En pratique

Si vous utilisez CloudFront pour CORS, prévoyez une solution de repli vers une autre méthode qui fonctionnera si CORS ne fonctionne pas. Ce n'est pas toujours une option, mais en ce moment, je charge dynamiquement des polices avec JavaScript. Si la requête CORS vers CloudFront échoue, je me rabats sur un proxy côté serveur vers les polices (pas de cross origin). De cette façon, les choses continuent de fonctionner même si CloudFront a obtenu un mauvais enregistrement en cache pour la police.

4voto

Sebastian Brestin Points 151

Pour compléter la réponse précédente, je voudrais partager les étapes d'AWS sur la façon d'activer CORS. Je l'ai trouvé très utile, en fournissant des liens supplémentaires : https://aws.amazon.com/premiumsupport/knowledge-center/no-access-control-allow-origin-error/

De plus, un élément à prendre en compte lorsque vous testez vos modifications, autre que le délai de déploiement de CloudFront, est le cache du navigateur . Je suggère d'utiliser des sessions différentes pour incognito lorsque vous testez vos changements.

4voto

Ankit Shubham Points 910

J'affiche certaines des configurations non triviales que j'ai faites pour que ça fonctionne :

  1. Attribuez un domaine personnalisé à Cloudfront de sorte que le domaine personnalisé soit un sous-domaine à partir duquel le front-end de votre application sera exécuté. Dans le cas de l'OP, il utilise localhost:3000 ; très probablement il teste sur son installation de développement, mais il doit déployer cette application à un certain domaine : appelons-le 'myapp.com'. Il peut donc attribuer un domaine personnalisé, par exemple cdn.myapp.com, pour pointer vers blah.cloudfront.net. Vous devrez créer/importer un certificat SSL personnalisé pour le nouveau domaine personnalisé ; le certificat par défaut de cloudfront ne fonctionnera pas.

  2. Référez-vous à ceci : https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/CNAMEs.html enter image description here

enter image description here Dans le snap de distribution Cloudfront, la première ligne n'a pas de domaine personnalisé, d'où une colonne CNAMEs vide. La deuxième rangée a un domaine personnalisé, c'est pourquoi il est imprimé ici. Vous pouvez vérifier que votre domaine personnalisé a été pointé vers la distribution Cloudfront de cette façon.

  1. Comportement de Cloudfront : Je suppose que vous avez déjà configuré le groupe de clés de confiance car à ce stade, vous avez déjà le cookie signé avec vous. CEPENDANT, vous devrez créer une politique de cache et une politique de demande d'origine personnalisées. enter image description here Voir les captures d'écran suivantes de la politique de mise en cache personnalisée : enter image description here et la politique de demande d'origine : enter image description here Ce qu'il faut noter, c'est que vous devrez mettre ces en-têtes sur une liste blanche : Origin, Access-Control-Request-Method, Access-Control-Allow-Origin, Access-Control-Request-Headers. (Vous remarquerez peut-être que Access-Control-Allow-Origin n'est pas dans la liste déroulante ; allez-y et tapez-le). Autorisez également tous les cookies.

  2. Configuration de S3 CORS : Allez sur le seau S3 et cliquez sur l'onglet des permissions. Faites défiler vers le bas jusqu'à la configuration CORS. Avertissement : j'ai juste collé ce qui a fonctionné pour moi. Le raisonnement derrière cela était que ce S3 allait être accédé par le CDN ou l'application dans mon scénario. J'ai essayé de mettre '*' pour être indulgent, mais la politique CORS sur Chrome s'est plainte que je ne peux pas utiliser une entrée joker dans AllowedOrigins !

[
    {
        "AllowedHeaders": [
            "*"
        ],
        "AllowedMethods": [
            "PUT",
            "POST",
            "GET",
            "HEAD",
            "DELETE"
        ],
        "AllowedOrigins": [
            "cdn.myapp.com",
            "myapp.com",
            "https://cdn.myapp.com",
            "https://myapp.com"
        ],
        "ExposeHeaders": [
            "ETag"
        ]
    }
]
  1. react-player : J'utilise react-player comme ceci (notez que l'option forceHLS est activée, mais c'est encore une fois spécifique à mon cas d'utilisation. Je pense que ce n'est pas obligatoire en général)
<ReactPlayer
    className="react-player"
    url={url}
    controls={controls}
    light={light}
    config={
      {
        file: {
          forceHLS: true,
          hlsOptions: {
            xhrSetup: function (xhr, url) {
              xhr.withCredentials = true; // send cookies
            },
          },
        },
      }
    }
    playIcon={<PlayIcon />}
    width="100%"
    height="100%"
  />

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X