Nginx Reverse Proxy Websocket Authentication – HTTP 403

Вопрос:Я использую Nginx в качестве обратного прокси-сервера приложения загрузки Spring. Я также использую Websockets с сообщениями sockjs и stomp. Вот контекстная конфигурация. Вот код клиента: var socket = new SockJS(entryPointUrl); var stompClient = Stomp.over(socket); var _this = this; stompClient.connect({}, function () { stompClient.subscribe('/app/some-url', function

Вопрос:

Я использую Nginx в качестве обратного прокси-сервера приложения загрузки Spring. Я также использую Websockets с сообщениями sockjs и stomp.

Вот контекстная конфигурация.

<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>

Вот код клиента:

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 }); });

Я также вам Spring Безопасность для защиты некоторого контента.

@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(); } }

Все отлично работает, ожидайте, когда я запустил это приложение за обратным прокси-сервером Nginx. Вот обратная конфигурация:

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;

Соединение всегда с кодом HTTP 403.

Я использую версию 1.9.7.

Есть ли у вас какие-либо идеи, почему клиент не получает аутентификацию?

Я знаю похожие вопросы, такие как этот, но решения не работают вообще.

Update

Мне удалось запустить приложение через HTTP. Мне нужно передать токен CSRF в конфигурации Nginx. Новая конфигурация:

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 # Default in Spring Boot proxy_pass_header X-XSRF-TOKEN; # WebSocket support (nginx 1.4) proxy_http_version 1.1;

Только отсутствует перенаправление по HTTPS. В журналах Spring отображается следующая запись:

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

Кажется, что Nginx Proxy необходимо переписать в правый порт.

Лучший ответ:

Я решил проблему самостоятельно. В принципе, Nginx необходимо передать некоторые дополнительные значения заголовка, если вы хотите использовать Websocket и Spring Security. Следующие строки должны быть добавлены в раздел location в вашей конфигурации Nginx:

# Pass the csrf token (see # 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»; Ответ №1

Принятое решение не сработало для меня, хотя я использовал очень классическую конфигурацию 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 ; } …

Проблема в том, что Spring проверяет происхождение, и именно этот код вызывает у меня проблемы:

// 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; }

В этом коде схема “http”, а порт – 8888, которая не отбрасывается, поскольку это не стандартный порт.

Однако браузер обращается к https://myserver/, а порт 443 опущен, поскольку он является HTTPS по умолчанию.

Поэтому порты не совпадают (пустые!= 8888), и проверка происхождения не выполняется.

Либо вы можете отключить проверки происхождения в Spring WebSockets:

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

или (вероятно безопаснее) вы можете добавить схему и порт в конфигурацию прокси-сервера NGINX:

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

Если вам интересно, эти заголовки читаются в

org.springframework.web.util.UriComponentsBuilder.adaptFromForwardedHeaders(HttpHeaders) Ответ №2

У меня возникла аналогичная проблема. Мне не удалось использовать базовую проверку безопасности Spring с помощью NGINX. Помимо установки proxy_pass_header X-XSRF-TOKEN;, мне также пришлось установить underscores_in_headers on;, так как NGINX по умолчанию не позволяет заголовкам с символами подчеркивания, а токен CSRF имеет имя _csrf.

Итак, мой окончательный файл конфигурации выглядел так:

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/; } } Ответ №3

Я решил эту проблему без заголовка CSRF в прокси-сервере NGINX.

Мой стек: spring -boot, spring -security (с хранилищем сеансов redis), spring -boot-websocket со стандартным STOMP внедрение, NGINX для обслуживания интерфейса и проксирования других сервисов, которые используют интерфейс.

В первый раз я использую конфигурацию по умолчанию в блоге NGINX здесь и здесь (скопируйте и вставьте в историю):

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; } } }

Но не работает, все еще 403 Запрещено.

Я исправил эту проблему с приведенной ниже конфигурацией (настоящая важная часть для исправления 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 ; 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 ; rewrite ^/cdn/(.*) /$1 break; } # This is the configuration that fix the problem with WebSocket # WebSocket Proxy location /ws { proxy_pass ; 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; } } }

Оцените статью
Добавить комментарий