Invalid CORS request sur une API avec Nginx

ça fonctionne sans nginx, mais pas avec

Le problème exposé dans ce sujet a été résolu.

Bonjour,

En ce moment je fais face à un problème de CORS sur mon api.

Pour résumer un peu la stack, j’ai une api (développée en Java à l’aide du framework Spring boot) qui tourne derrière nginx qui fait office de reverse proxy. Mon api gère les utilisateurs grâce à la bibliothèque spring-security. Jusqu’ici tout va bien.

En local (sans nginx donc), lorsque je lance mon api j’arrive très bien à utiliser tous mes endpoints. Lorsqu’elle se retrouve déployée derrière nginx, mes requêtes GET (même celles qui nécessitent un accès sécurisé par login/password) fonctionnent bien, mais les requêtes de type POST et PUT ne fonctionnent pas.

J’ai bien sur un message d’erreur :

Invalid CORS request

Bon je dois préciser que les même requêtes, lorsqu’elle sont lancées directement en console avec curl fonctionnent très bien, ce qui laisse penser que le problème vient uniquement sur des requêtes XHR.

Pour m’aider il vous faudrait avoir d’autres informations, comme ce bout de code Java dans mon api.

@Bean
public WebMvcConfigurer corsConfigurer() {
        log.info(String.format("Enabled CORS for host %s", domainAllowed));
        return new WebMvcConfigurerAdapter() {
            @Override
            public void addCorsMappings(CorsRegistry registry) {
                registry.addMapping("/**")
                        .allowedOrigins(domainAllowed)
                        .allowedMethods("GET", "PUT", "POST", "DELETE")
                        .allowCredentials(true)
                        .maxAge(1728000);
            }
        };
    }

Qui devrait permettre à l’API en interne d’autoriser les CORS (d’ailleurs le code fait son effet puisque lorsque l’API est utilisée sans nginx elle fonctionne).

Ce bout de configuration nginx devrait vous intéresser aussi

server {
      ssl    on;
      ssl_certificate    /path/to/fullchain.pem;
      ssl_certificate_key    /path/to/privkey.pem;
      location / {
           proxy_set_header X-Forwarded-Host $host;
           proxy_set_header X-Forwarded-Server $host;
           proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

           if ($request_method = 'OPTIONS') {
               add_header 'Access-Control-Allow-Origin' '*';
               add_header 'Access-Control-Allow-Credentials' 'true';
               add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, DELETE, OPTIONS';
               add_header 'Access-Control-Allow-Headers' 'Authorization, DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type';
               add_header 'Access-Control-Max-Age' 1728000;
               add_header 'Content-Type' 'text/plain charset=UTF-8';
               add_header 'Content-Length' 0;
               return 204;
           }

           if ($request_method = 'GET') {
               add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, DELETE, OPTIONS';
               add_header 'Access-Control-Allow-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Content-Range,Range';
               add_header 'Access-Control-Expose-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Content-Range,Range';
           }

           proxy_pass         http://127.0.0.1:8080/; # le port sur lequel tourne mon api en vrai
      }
}

C’est ce bout de conf (qui pour moi est un peu un hack), qui pose problème, je l’ai trouvé sur la toile (et il fonctionnait plutôt bien il y a un an). J’ignore pourquoi ça ne fonctionne plus comme avant, en sachant que sur cette API, j’ai essentiellement mis à jour 2 choses entre temps :

  1. la version de mon framework spring boot (2.0 à 2.2)
  2. la version de nginx (j’ai actuellement la 1.14.2, mais je ne sais plus laquelle j’avais avant)

Si une âme charitable pouvais m’aider là dessus, j’ai fait pas mal de tests non concluants.

PS: Je me sers de l’outil postman (qui fait des requêtes XHR lui) pour tester le fonctionnement de mon API pour info.

PS 2: J’ai le souvenir que @Eskimon a déjà eu ce genre de souci, mais avec Django plutot (je te ping au cas ou).

Merci d’avance.

Si l’API fonctionne bien sans nginx en reverse, alors nginx ne devrait pas ajouter les headers. Peut être que c’est ça qui créé une confusion niveau browser ? (edit: j’avais pas vu le return dans la conf)

Quand tu fais une requête OPTION en GET sur ton nginx, ça sort quels headers ?

+0 -0

J’ai eu le même souci que toi en début d’année avec un webservice écrit en Node. Pas de problème pendant 2 ans, pourquoi maintenant ? Je ne sais toujours pas.

Semble t-il le problème venait du wildcard qui ne suffisait pas pour confirmer la sécurité de l’application. J’ai pu entourlouper le système CORS en récupérant le nom de domaine de la requête et en le renvoyant comme "domaine légitime".

Ce qui se modélise en code par un simple booléen d’acceptation (j’en étais presque déçu :p ) :

this._sock = require('socket.io')(server);
this._sock.origins((origin, callback) => callback(null, true)); // <-- ICI

Il était 2h du matin, l’application faisait tourner 3 entreprises le lendemain … honnêtement je n’ai pas cherché à comprendre mais si vous avez la réponse, je suis preneur ! Le plus étrange étant que je n’ai pas eu d’autres problèmes CORS sur des applications similaires.

Quand tu fais une requête OPTION en GET sur ton nginx, ça sort quels headers ?

Nek

J’obtiens les headers suivants :

access-control-allow-credentials →true
access-control-allow-headers →Authorization, DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type
access-control-allow-methods →GET, POST, PUT, DELETE, OPTIONS
access-control-allow-origin →*
access-control-max-age →1728000
connection →keep-alive
content-length →0
content-type →text/plain charset=UTF-8
server →nginx/1.14.2

@Yarflam : arf, ça ne m’aide pas beaucoup. J’ai un peu plus de temps pour chercher une vrai solution moi. J’aimerai ne pas en arriver à truander le système.

Oui ma solution est a adapter. Ce n’était pas le même protocole qui était concerné et j’avais besoin du wildcard pour mes sous-domaines dynamiques. Si c’est le même problème et que tu as qu’un seul nom, il te faudrait remplacer le wildcard par le domaine.

Bonjour a tous, j’ai trouvé d’ou venais mon problème, il n’était pas là ou je le pensais (nginx), mais au niveau de la configuration de mon api.

Vous vous souvenez de ce code Java posté dans le premier post ?

@Bean
public WebMvcConfigurer corsConfigurer() {
        log.info(String.format("Enabled CORS for host %s", domainAllowed));
        return new WebMvcConfigurerAdapter() {
            @Override
            public void addCorsMappings(CorsRegistry registry) {
                registry.addMapping("/**")
                        .allowedOrigins(domainAllowed)
                        .allowedMethods("GET", "PUT", "POST", "DELETE")
                        .allowCredentials(true)
                        .maxAge(1728000);
            }
        };
    }

Le fait est que la variable domainAllowed était par défaut configurée sur une url locale. Sauf que j’avais oublié de la configurer sur * lorsque je la déploie en ligne.

Merci a ceux qui se sont penchés sur mon problème qui finalement était une faute d’inattention.

Connectez-vous pour pouvoir poster un message.
Connexion

Pas encore membre ?

Créez un compte en une minute pour profiter pleinement de toutes les fonctionnalités de Zeste de Savoir. Ici, tout est gratuit et sans publicité.
Créer un compte