2017-10-03 3 views
0

Ich habe einen Spring Boot-Server hinter einem Nginx-Reverse-Proxy, auf den ich über Fetch von einer React-App zugreife. Das Frontend wird von einem anderen Port bedient, daher muss ich CORS auf dem Server aktivieren. In den meisten Fällen funktioniert das sehr gut, aber etwa 1% meiner Benutzer erhalten als Antwort auf die OPTIONS-Preflight-Anfrage 403, und ich brauche Hilfe, um herauszufinden, warum. Das größte Problem, das ich habe, ist, dass ich das Problem auf keiner meiner Maschinen reproduzieren kann.403 beim POST-Preflight (manchmal)

Frühling Boot-CORS config:

@Bean 
public FilterRegistrationBean corsFilter() { 
    CorsConfiguration config = new CorsConfiguration(); 
    config.addAllowedOrigin("https://example.com"); 
    config.addAllowedHeader("*"); 
    config.addAllowedMethod("GET"); 
    config.addAllowedMethod("PUT"); 
    config.addAllowedMethod("POST"); 
    config.addAllowedMethod("DELETE"); 
    config.addAllowedMethod("PATCH"); 

    UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); 
    source.registerCorsConfiguration("/**", config); 

    FilterRegistrationBean bean = new FilterRegistrationBean(new CorsFilter(source)); 
    bean.setOrder(Ordered.HIGHEST_PRECEDENCE); 
    return bean; 
} 

Nginx config (3000 NodeJS Frontend dient, und 3001 ist Frühling Boot):

server { 
    ... 

    location/{ 
     proxy_pass http://localhost:3000; 
     proxy_http_version 1.1; 
     proxy_set_header Upgrade $http_upgrade; 
     proxy_set_header Connection 'upgrade'; 
     proxy_set_header Host $host; 
     proxy_cache_bypass $http_upgrade; 
    } 

    location /api/v1/ { 
     proxy_pass http://localhost:3001; 
     proxy_http_version 1.1; 
     proxy_set_header Upgrade $http_upgrade; 
     proxy_set_header Connection 'upgrade'; 
     proxy_set_header Host $host; 
     proxy_cache_bypass $http_upgrade; 
    } 

    ... 
} 

Nginx Log-Format (ich einige Teile zur Klarheit entfernt):

Mit Blick auf die Nginx access.log habe ich 2 Arten von Protokollzeilen wh festgenagelt ere 403 Show:

"OPTIONS /api/v1/oauth/token?grant_type=password&username=user%40example.com&password=****" 403 "https://www.example.com/login" "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36" 

Bedeutung Windows 7 Chrome 61 und

"OPTIONS /api/v1/oauth/token?grant_type=password&username=user%40example.com&password=****" 403 "-" "Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko" 

Bedeutung Windows 7 IE11.

Andere Benutzer, die das gleiche Setup von Betriebssystem und Browser verwenden, haben keine Probleme.

Daten manuell gesendet mit fetch:

URL: https://example.com:3001/api/v1/oauth/token?grant_type=password&username=user%40example.com&password=**** 
Method: POST 
Headers: 
    Authorization: Basic XXXXXXXXXXX= 
    Content-Type: application/x-www-form-urlencoded 
Body: undefined 

Actual Parameter im preflight Anfrage für einen Arbeits Benutzer (von Chromkonsole):

Anfrage-Header:

OPTIONS /api/v1/oauth/token?grant_type=password&username=user%40example.com&password=**** HTTP/1.1 
Host: https://example.com:3001 
Connection: keep-alive 
Access-Control-Request-Method: POST 
Origin: https://example.com:3000 
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.79 Safari/537.36 
Access-Control-Request-Headers: authorization 
Accept: */* 
Referer: https://example.com:3000/login 
Accept-Encoding: gzip, deflate 
Accept-Language: en-US,en;q=0.8,sv;q=0.6 

Antwortheader:

HTTP/1.1 200 
Access-Control-Allow-Origin: https://example.com:3000 
Vary: Origin 
Access-Control-Allow-Methods: GET,PUT,POST,DELETE,PATCH 
Access-Control-Allow-Headers: authorization 
Content-Length: 0 
Date: Tue, 03 Oct 2017 16:01:37 GMT 

Meine Vermutung wäre, dass etwas nicht stimmt mit der Art, wie ich die Abrufanforderung sende, oder dass ich die Header falsch konfiguriert habe. Aber bis jetzt konnte ich es nicht lösen.

Jede Hilfe wäre mächtig geschätzt.

Antwort

0

Ich habe endlich den Fehler gefunden, und es war meine eigene Schuld vollständig.

Wie in der Nginx-Datei access.log zu sehen ist, hat eines der fehlerhaften Preflights eine $http_referer, das ist der Ursprungs-Header von www.example.com/login. Dies wird natürlich ein Preflight fehlschlagen, da meine CORS Config nur example.com, ohne die www Subdomain erlaubt.

ich dies habe durch Hinzufügen server Blöcke zur Nginx Konfiguration festgelegt, so dass alle Anforderungen von der www Sub-Domain eine Umleitung an die nicht www Domain zurückkehren, einen 301 Permanently moved mit:

server { 
    ... 

    listen 443 ssl; 

    server_name example.com; 

    location/{ 
      proxy_pass http://localhost:3000; 
      proxy_http_version 1.1; 
      proxy_set_header Upgrade $http_upgrade; 
      proxy_set_header Connection 'upgrade'; 
      proxy_set_header Host $host; 
      proxy_cache_bypass $http_upgrade; 
    } 

    location /api/v1/ { 
      proxy_pass http://localhost:3001; 
      proxy_http_version 1.1; 
      proxy_set_header Upgrade $http_upgrade; 
      proxy_set_header Connection 'upgrade'; 
      proxy_set_header Host $host; 
      proxy_cache_bypass $http_upgrade; 
    } 

    ... 
} 

server { 
    server_name www.example.com example.com; 

    return 301 https://example.com$request_uri; 
} 

server { 
    listen 443 ssl; 

    server_name www.example.com; 

    return 301 https://example.com$request_uri; 
} 

Beachten Sie, dass ich auch umleiten Sie alle http Verkehr zu https, um alles verschlüsselt zu halten.

Auf diese Weise kann ich sicher sein, dass alle Anfragen meine 2 Server mit https://example.com als Ursprung eingeben, und die CORS-Konfiguration nicht geändert werden muss.