Fermer

février 10, 2021

Proxy NGINX pour CORS – Blogs parfaits


Dans mon dernier projet AEM, j'ai eu un défi particulier avec du code frontal, un appel AJAX et CORS.

Lors de l'exécution du site sur localhost, le code de recherche a tenté de faire un appel AJAX à une recherche API. L'API n'autoriserait pas mon site localhost. Cela signifiait que les développeurs frontaux avaient du mal à faire des tests locaux. Pour résoudre ce problème, J'ai configuré un serveur proxy pour tromper le navigateur en lui faisant croire que CORS a été configuré pour mon site fonctionnant sur localhost.

Qu'est-ce que CORS

CORS signifie partage de ressources cross-origin . C'est un mécanisme par lequel le serveur contrôlera l'accès à ses goodies, si quelqu'un s'exécute sur un domaine différent .

  • Cela se produit entre le navigateur et un serveur (généralement une sorte de point de terminaison d'API) .
  • Le navigateur envoie des informations via HTTP Access-Control-Request – * headers.
  • Le serveur détermine les en-têtes reçus et renvoie Access-Control-Allow- * headers.
  • Le navigateur sait maintenant s'il peut ou non accéder aux ressources de ce serveur.
  • Dans certaines circonstances, le navigateur peut effectuer un pré-vol qui est un test préalable pour faire la vraie requête.
  • Le navigateur ne permettra pas au code frontal de modifier les en-têtes.
  • Le code côté serveur peut changer les en-têtes. Mais, il doit être transparent pour l'application et effectué par un service en aval tel qu'une passerelle API ou le serveur HTTP .

Le Access-Control-Request – * en-têtes CORS dire au serveur

  • Mon domaine actuel (en-tête Origin )
  • Méthode HTTP de la requête ( Access-Control-Request-Method en-tête)
  • Liste des en-têtes dans la requête (en-tête Access-Control-Request-Headers )

Les en-têtes Access-Control-Allow – * CORS indiquent au navigateur

  • L'origine autorisée ([19659019] Access-Control-Allow-Origin [en-tête19659020])
  • Les méthodes autorisées ( Access-Control-Allow-Methods en-tête)

C'est le cœur de CORS. Si le service backend ne renvoie pas les en-têtes Access-Control-Allow – * avec des valeurs correctes, le navigateur ne permettra pas à la requête de continuer.

J'aime considérer l'échange entier comme un Gentlemen's Agreement . Les messieurs sont le navigateur et le serveur. Pourquoi? Parce que c'est un échange informel de données qui dépend de l'honnêteté des deux parties. Vous pouvez rompre l'accord simplement en truquant les en-têtes.

Contournement de CORS

Tout ce que nous devons faire est de tromper le navigateur et / ou le service pour que la requête AJAX puisse continuer. Peut-être que votre navigateur a des commutateurs de sécurité que vous pouvez inverser. Vous pouvez probablement trouver un plugin pour faire l'affaire. L'ajout d'une entrée de fichier hôte afin que vous puissiez exécuter votre site local sur le domaine autorisé peut fonctionner. La meilleure façon à laquelle je pourrais penser serait de configurer un serveur proxy pour s'asseoir entre le code frontal et les services back-end.

Méfiez-vous toujours des serveurs proxy. Après tout, ils peuvent inspecter votre trafic et apporter des modifications à vos charges utiles. Dans notre cas, nous allons basculer les en-têtes CORS requis pour rendre le navigateur et l'API heureux. Et nous le ferons dans la sécurité d'un conteneur Docker local afin de ne jamais envoyer de données.

Configuration d'un service

Si vous avez déjà un service de backend avec CORS activé, c'est parfait! Pour ce test, nous allons mettre en place un service express rapide et sale.

Vous devrez l'ajouter au fichier de vos hôtes:

Le fichier server.js

 const express = exiger ('express');
var chemin = require ('chemin');
const cors = require ('cors');
const corsOpts = {
  origine: /myfrontend.com:3000/,
  allowedHeaders: []
}
const app = express ();
app.get ('/ service', cors (corsOpts), (req, res) => {
        res.send (`bonjour, $ {req.get ('origine')}`);
        console.log (JSON.stringify (req.headers, null, ''));
    })
   .get ('/', cors (corsOpts), (req, res) => {
        res.sendFile (path.join (__ dirname + '/index.html'));
    })
   .options ('*', cors (corsOpts));

serveur de const = app.listen (3000, () => {
    console.log (`serveur écoutant sur le port $ {server.address (). port}`);
});

 Adobe - Du contenu pour tous
Du contenu pour tous

Les entreprises capables de répondre rapidement et systématiquement aux demandes des consommateurs prospèrent à une époque de contenu infini. Découvrez comment créer des expériences fluides pour vos clients omnicanaux.

Obtenez le guide

Le fichier index.html





    
     CORS 



     Réponse: 
   

Et lorsque vous le lancez, vous pouvez accéder à http: // localhost: 3000 / . Notez l'erreur CORS gênante dans la console du navigateur

 L'accès à XMLHttpRequest à 'http://mybackend.com:3000/service' from origin 'http: // localhost: 3000' a été bloqué par la stratégie CORS: Non 'Access L'en-tête -Control-Allow-Origin 'est présent sur la ressource demandée. 

Heureusement, les erreurs CORS sur le navigateur sont explicites. Le navigateur dit: "Je ne peux pas autoriser cela car le serveur ne m'a pas informé que l'origine actuelle est autorisée à faire cette demande."

J'ai mentionné plus tôt, il y a quelques correctifs:

  • Vous pouvez ajouter 127.0.0.1 myfrontend.com dans le fichier de vos hôtes et accédez au site via http://myfrontend.com:3000/ mais éditer le fichier des hôtes peut être peu pratique ou parfois impossible.
  • Vous pouvez modifier server.js pour autoriser localhost, mais nous n'avons pas toujours le contrôle sur les services avec lesquels nous intégrons.
  • Vous pouvez installer un plugin de navigateur tel que Autoriser CORS: Access -Control-Allow-Origin dans Chrome.
  • Vous pouvez ajouter CORS Anywhere dans votre projet si vous avez des compétences en JavaScript.

Configurer un proxy NGINX

Pour mon projet particulier , Docker faisait déjà partie de l'environnement de développement local. Tout ce que j'avais à faire était d'ajouter un service supplémentaire au fichier docker-compose et à quelques fichiers de configuration. Le proxy était assis là, transparent pour les développeurs. En mode d'exécution local, le code de fin de police s'intégrerait au service distant via le proxy local. Sur tous les autres modes d'exécution, il s'intégrerait au service distant.

Le fichier docker-compose.yml

 version: '3.8'

prestations de service:

  Procuration:
    image: nginx: alpin
    ports:
      - 8080: 80
    volumes:
      - ./default.conf.template:/etc/nginx/templates/default.conf.template

Le fichier default.conf.template :

 server {
    écouter 80 default_server;
    nom du serveur _;
    server_name_in_redirect off;

    access_log /var/log/nginx/access.log;
    error_log /var/log/nginx/error.log debug;

    service de localisation {
        proxy_pass http: //host.docker.internal: 3000;
    }
}

Assurez-vous de mettre à jour l'URL sur le JavaScript afin qu'il utilise le proxy fonctionnant sur 8080:

 $ (function () {
    $ .ajax ({
        // url: 'http://mybackend.com:3000/service',
        url: 'http://mybackend.com:8080/service',
        succès: res => {
            $ ('# réponse'). text (res);
         },
        erreur: err => {
            $ ('# réponse'). text (err.statusText);
        }
    })
});

Lancez le service docker-compose et accédez à http: // localhost: 8080 / . Vous voyez toujours la même erreur CORS, mais maintenant vers le service mandaté sur le port 8080.

Modification des demandes et des réponses

Le message d'erreur indique que vous n'avez pas l'en-tête Access-Control-Allow-Origin . Le service renverra cet en-tête si Origin correspond au modèle /myfrontend.com:3000/ . Tromper le service en remplaçant l’en-tête Origin avant de l’envoyer en amont

 location / service {
    proxy_pass http: //host.docker.internal: 3000;
    proxy_set_header Origine http://myfrontend.com:3000;
}

Le service renverra l'en-tête Access-Control-Allow-Origin et les modifications d'erreur CORS

 Accès à XMLHttpRequest à 'http://mybackend.com:8080/service' depuis l'origine «http: // localhost: 3000» a été bloqué par la stratégie CORS: l'en-tête «Access-Control-Allow-Origin» a une valeur «http://myfrontend.com:3000» qui n'est pas égale à l'origine fournie. 

Le navigateur dit que le service n'autorisera que http://myfrontend.com:3000 et vous êtes sur localhost. Tromper le navigateur en remplaçant l’en-tête Access-Control-Allow-Origin .

 location / service {
    proxy_pass http: //host.docker.internal: 3000;
    proxy_set_header Origine http://myfrontend.com:3000;
    proxy_hide_header Contrôle d'accès-Autoriser-Origine;
    add_header Contrôle d'accès-Autoriser-Origine $ http_origin;
}

Premièrement, nous le cachons. Ensuite, nous ajoutons le nôtre avant de renvoyer la réponse. NGINX ne remplacera pas les en-têtes; il y ajoutera. Si vous ne le masquez pas d'abord, vous vous retrouverez avec 2 origines et cela provoquera une autre erreur CORS. Comme je l'ai déjà dit, les erreurs CORS sur le navigateur sont explicites. Essayez-le.

Quelque chose à essayer par vous-même

J'ai mentionné des demandes préalables au vol. Pour en déclencher un, mettez à jour l'appel AJAX pour ajouter un en-tête.

 $ (function () {
    $ .ajax ({
        en-têtes: {'X-Foo': 'bar'},
        url: 'http://mybackend.com:8080/service',
        succès: res => {
            $ ('# réponse'). text (res);
         },
        erreur: err => {
            $ ('# réponse'). text (err.statusText);
        }
    })
});

Dans cet exemple, nous ajouterons l'en-tête X-Foo . Vous noterez que notre implémentation de service n'autorise aucun en-tête supplémentaire. La bonne chose serait de mettre à jour l'implémentation du service. Si vous n'avez aucun contrôle sur cela, vous pouvez utiliser le proxy.

Regardez l'erreur CORS sur le navigateur. Pouvez-vous mettre à jour la réponse au niveau du proxy pour tromper le navigateur?

Conclusion

Nous avons mis en place un exemple simple pour tromper le navigateur et le service en autorisant la requête d'origine croisée. En fonction de vos besoins particuliers, vous devrez peut-être apporter des modifications supplémentaires. À tout le moins, vous avez maintenant une application de test et un proxy.

À propos de l'auteur

Juan Ayala est un développeur principal du cabinet Adobe chez Perficient, Inc., spécialisé dans la plate-forme Adobe Experience et les éléments qui l'entourent .

Plus de cet auteur






Source link