2015-12-07 19 views
5

Sto utilizzando Nginx come proxy inverso di un'applicazione di avvio Spring. Uso anche Websockets con i messaggi sockjs e stomp.Autenticazione Websocket proxy inverso Nginx - HTTP 403

Ecco la configurazione del contesto.

<websocket:message-broker application-destination-prefix="/app"> 
    <websocket:stomp-endpoint path="/localization" > 
     <websocket:sockjs/> 
    </websocket:stomp-endpoint> 
    <websocket:simple-broker prefix="/topic" /> 
</websocket:message-broker> 

Ecco il codice del client:

var socket = new SockJS(entryPointUrl); 
var stompClient = Stomp.over(socket); 

var _this = this; 

stompClient.connect({}, function() { 
    stompClient.subscribe('/app/some-url', function (message) { 
     // do some stuff 
    }); 
}); 

ho anche Primavera di sicurezza per proteggere alcuni contenuti.

@Configuration 
@Order(4) 
public static class FrontendSecurityConfig extends WebSecurityConfigurerAdapter { 

    @Override 
    protected void configure(HttpSecurity http) throws Exception { 
     http.authorizeRequests() 
       .antMatchers("/js/**", "/css/**", "/webjars/**").permitAll() 
       .anyRequest().authenticated() 
       .and() 
       .formLogin().loginPage("/login").permitAll() 
       .and() 
       .logout().permitAll(); 
    } 

} 

Tutto funziona alla grande, mi aspetto quando eseguo questa applicazione dietro un reverse proxy Nginx. Ecco la configurazione inversa:

proxy_pass http://testsysten:8080; 

    proxy_set_header X-Real-IP $remote_addr; 
    proxy_set_header Host $host; 
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 

    # WebSocket support (nginx 1.4) 
    proxy_http_version 1.1; 
    proxy_set_header Upgrade $http_upgrade; 
    proxy_set_header Connection $http_connection; 

    # Max body size 
    client_max_body_size 10M; 

La connessione fallisce sempre con un codice HTTP 403.

Sto usando la versione 1.9.7.

Avete qualche idea, perché il client non viene autenticato?

Conosco domande simili, come this one ma le soluzioni non funzionano affatto.

Aggiornamento

Sono riuscito a eseguire l'applicazione su HTTP. Devo passare il token CSRF nella configurazione Nginx. Nuova configurazione:

proxy_pass http://testsysten:8080; 

    proxy_set_header X-Real-IP $remote_addr; 
    proxy_set_header Host $host; 
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 

    # Pass the csrf token (see https://de.wikipedia.org/wiki/Cross-Site-Request-Forgery) 
    # Default in Spring Boot 
    proxy_pass_header X-XSRF-TOKEN; 

    # WebSocket support (nginx 1.4) 
    proxy_http_version 1.1; 

Solo il reindirizzamento manca su HTTPS. Nei registri primavera è vedere seguente voce:

o.s.w.s.s.t.h.DefaultSockJsService - Processing transport request: GET http://testsystem:80/localization/226/3mbmu212/websocket 

Sembra come Nginx Proxy ha bisogno di riscrivere il alla porta giusta.

risposta

7

Ho risolto il problema da solo. Fondamentalmente, Nginx deve passare alcuni valori di intestazione aggiuntivi se si desidera utilizzare Websocket e Spring Security. Le seguenti linee devono essere aggiunte a location sezione nella configurazione Nginx:

# Pass the csrf token (see https://de.wikipedia.org/wiki/Cross-Site-Request-Forgery) 
    # Default in Spring Boot and required. Without it nginx suppresses the value 
    proxy_pass_header X-XSRF-TOKEN; 

    # Set origin to the real instance, otherwise a of Spring security check will fail 
    # Same value as defined in proxy_pass 
    proxy_set_header Origin "http://testsysten:8080"; 
0

avevo affrontato un problema simile. Non ero in grado di utilizzare l'autenticazione di base di Spring Security con NGINX. Oltre all'impostazione di proxy_pass_header X-XSRF-TOKEN;, dovevo anche impostare underscores_in_headers on;, poiché NGINX per impostazione predefinita non consente intestazioni con caratteri di sottolineatura e il token CSRF è denominato _csrf.

Quindi il mio file di configurazione finale si presentava così:

server { 
    underscores_in_headers on; 
    listen 80 default_server; 
    listen [::]:80 default_server ipv6only=on; 

    root /usr/share/nginx/html; 
    index index.html index.htm; 

    # Make site accessible from http://localhost/ 
    server_name localhost; 

    location/{ 
      # First attempt to serve request as file, then 
      # as directory, then fall back to displaying a 404. 
      try_files $uri $uri/ =404; 
      # Uncomment to enable naxsi on this location 
      # include /etc/nginx/naxsi.rules 
    } 
    location /example/ { 
      proxy_pass_header X-XSRF-TOKEN; 
      proxy_pass  http://localhost:8080/; 
    } 
} 
0

Ho risolto questo problema senza intestazione CSRF in Nginx proxy.

La mia pila: spring-boot, spring-security (con redis session store), spring-boot-websocket with default STOMP implementation, NGINX per servire frontend e proxy ad altri servizi che frontend consumano.

In prima volta che uso il default configuration show in the NGINX Blog here e qui (copia e incolla per la storia):

http { 
    map $http_upgrade $connection_upgrade { 
     default upgrade; 
     '' close; 
    } 

    upstream websocket { 
     server 192.168.100.10:8010; 
    } 

    server { 
     listen 8020; 
     location/{ 
      proxy_pass http://websocket; 
      proxy_http_version 1.1; 
      proxy_set_header Upgrade $http_upgrade; 
      proxy_set_header Connection $connection_upgrade; 
     } 
    } 
} 

Ma non funzionano, ancora 403 Proibita.

Ho risolto questo problema con la configurazione di seguito (il vero e proprio parte importante fissare websocket è # WebSocket Proxy):

worker_processes 1; 

events { 
    worker_connections 1024; 
} 

http { 

    include  mime.types; 
    default_type application/octet-stream; 
    sendfile  on; 
    keepalive_timeout 65; 

    server { 
     listen  30010; 
     server_name localhost; 
     client_max_body_size 10M; 

     location/{ 
      root /usr/share/nginx/html; 
      index index.html index.htm; 
     } 

     # Backend API Proxy 
     location /api { 
      proxy_pass http://192.168.0.100:30080; 
      proxy_set_header Host $http_host; 
      proxy_set_header Access-Control-Allow-Origin 192.168.0.100; 
      proxy_set_header X-Real-IP $remote_addr; 
      proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 
      proxy_set_header X-NginX-Proxy true; 
      rewrite ^/api/?(.*) /$1 break; 
      proxy_redirect off; 
     } 

     # CDN Proxy 
     location ~ ^/cdn/(.*) { 
      proxy_pass http://192.168.0.110:9000; 
      rewrite ^/cdn/(.*) /$1 break; 
     } 

     # This is the configuration that fix the problem with WebSocket 
     # WebSocket Proxy 
     location /ws { 
      proxy_pass http://192.168.0.120:30090; 
      proxy_http_version 1.1; 
      proxy_set_header Upgrade $http_upgrade; 
      proxy_set_header Connection "upgrade"; 
      proxy_set_header Host $http_host; 
      proxy_set_header Access-Control-Allow-Origin 192.168.0.120; 
      proxy_set_header X-Real-IP $remote_addr; 
      proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 
      proxy_set_header X-NginX-Proxy true; 
     } 

    } 

} 
1

La soluzione accettata non ha funzionato per me anche se ero con una classica configurazione HTTPS:

server { 
    listen 443 ssl; 
    location /ws { 
     proxy_http_version 1.1; 
     proxy_set_header Upgrade $http_upgrade; 
     proxy_set_header Connection "upgrade"; 
     proxy_set_header Host $http_host; 
     proxy_pass http://127.0.0.1:8888; 
    } 
... 

il problema è che la primavera controlla l'origine e in particolare che il codice mi stava causando problemi:

// in org.springframework.web.util.UriComponentsBuilder.adaptFromForwardedHeaders(HttpHeaders): 
     if ((this.scheme.equals("http") && "80".equals(this.port)) || 
       (this.scheme.equals("https") && "443".equals(this.port))) { 
      this.port = null; 
     } 

In questo codice lo schema è 'http' e la porta è 8888, che non viene scartata perché non è la porta standard.

Il browser tuttavia colpisce https://myserver/ e la porta 443 viene omessa perché è quella HTTPS predefinita.

Pertanto, le porte non corrispondono (vuoto! = 8888) e il controllo dell'origine non riesce.

entrambi i casi è possibile disattivare i controlli origine in WebSockets Primavera:

registry.addHandler(resgisterHandler(), "/ws").setAllowedOrigins("*"); 

o (probabilmente più sicuro) è possibile aggiungere lo schema e la porta alla configurazione di proxy Nginx:

proxy_set_header X-Forwarded-Proto $scheme; 
    proxy_set_header X-Forwarded-Port $server_port; 

Se sono interessati, quelle intestazioni vengono lette in

org.springframework.web.util.UriComponentsBuilder.adaptFromForwardedHeaders(HttpHeaders)