Nginx не получает второй запрос после 100-Contnue, ответ 401

Для приведенной ниже конфигурации запрос 2 не отражается в nginx. Нет журнала ошибок и ничего в журнале доступа для запроса 2.

Проблема начала возникать только после того, как 100-Continue, 401 Unauthorized был введен в качестве первоначального ответа. Если запрос 1 отвечает 101 с прокси-сервера, все (конечное соединение через веб-сокет установлено).

Ожидаемое поведение: второй запрос должен успешно достичь прокси-сервера, а затем — проксируемого сервера. После этого он будет прикрыт к веб-сокету.

Конфигурация Nginx

server {
    listen 443 ssl;
    server_name admin.example.com;
    ssl_certificate       /etc/nginx/server.pem;
    ssl_certificate_key   /etc/nginx/key.pem;
    ssl_session_cache shared:SSL:5m;
    ssl_protocols TLSv1.2;
    ssl_dhparam /etc/ssl/certs/dhparam.pem;
    ssl_ecdh_curve secp384r1;
    server_name_in_redirect on;
    client_max_body_size 100m;

    location /my_line/ {
        proxy_pass        https://y.y.y.y/;
        proxy_set_header  Host y.y.y.y;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection $http_connection;
        proxy_ignore_client_abort on;
        proxy_buffering off;
        proxy_http_version 1.1;
        proxy_set_header Origin '';
        keepalive_timeout 100s;
        proxy_set_header Expect $http_expect;
        proxy_read_timeout 7200;
    }

    error_page  404              /index.html;
    location / {
        root   /usr/share/nginx/html;
        add_header X-Frame-Options DENY always;
        add_header X-Content-Type-Options nosniff always;
        add_header X-XSS-Protection "1; mode=block"  always;
    }
}

ЗАПРОС 1:

GET /myserver/my_line/84620 HTTP/1.1
Connection: Upgrade
Authorization: Basic ODQ2MjA6c3MxOE1VRUs5UEF6RTB5eHoyVmpSZ0Roc3VyV0tCcA==
User-Agent: MyApp/WebSocketClient/
Host: x.x.x.x
Upgrade: websocket
Sec-WebSocket-Key: DhaIyjupEbTHXQvX3asVeA==
Sec-WebSocket-Protocol: Web_Proxy
Sec-WebSocket-Version: 13
Sec-WebSocket-Extensions: mux
Expect: 100-continue

ответ 1

HTTP/1.1 100 Continue
Server: nginx
Date: Mon, 09 Dec 2019 16:33:51 GMT
Connection: keep-alive

ответ 2

HTTP/1.1 401 Unauthorized
Date: Mon, 09 Dec 2019 16:33:51 GMT
Expires: Mon, 09 Dec 2019 16:34:51 GMT
Cache-Control: private,max-age=60
WWW-Authenticate: Digest realm="WebSocket Group@myapp", domain="", nonce="f9beaf5521a1cdf078362b68a4332df5", algorithm=MD5
Server: MyServer/
X-Frame-Options: DENY
X-XSS-Protection: 1; mode=block
X-Content-Type-Options: nosniff
Strict-Transport-Security: max-age=31536000
Content-Length: 0

ЗАПРОС 2

GET /myserver/my_line/84620 HTTP/1.1
Connection: Upgrade
Authorization: Digest username="84620", realm="WebSocket Group@myapp", nonce="f9beaf5521a1cdf078362b68a4332df5", uri="/myserver/my_line/84620", response="5d8bb7c396724bb840da698c06f19629", algorithm=MD5, nc=00000056
User-Agent: MyApp/WebSocketClient/
Host: x.x.x.x
Upgrade: websocket
Sec-WebSocket-Key: DhaIyjupEbTHXQvX3asVeA==
Sec-WebSocket-Protocol: Web_Proxy
Sec-WebSocket-Version: 13
Sec-WebSocket-Extensions: mux

Проблема -> Второй запрос не отражается в логах доступа nginx, В логах ошибок ничего нет.

Nginx поддерживается для проксирования запроса на проксируемый сервер и не делает ничего другого. TCP-соединение между клиентом и прокси-сервером, прокси-сервером и прокси-сервером было неповрежденным, когда REQUEST2 был запущен клиентом. Я подозреваю, что конфигурация в nginx имеет проблемы с заголовками Connection и Upgrade. Я захватил весь wireshark на nginx, и в нем четко указано, что TCP-соединение было на месте, а запрос 2 был подтвержден nginx. Просто nginx его не обрабатывает - он как бы уходит в черную дыру и не выходит из нее.

Обратитесь за помощью к специалисту. Спасибо.


person Nitb    schedule 13.12.2019    source источник
comment
Здесь следует отметить разницу в способе использования прокси-сервера веб-сокета — nginx.com /блог/вебсокет-nginx. Здесь есть несколько HTTP-запросов, протекающих по одному и тому же соединению tcp, а затем предполагается, что оно должно быть обновлено до ws.   -  person Nitb    schedule 13.12.2019
comment
Почему в запросе 2 другой заголовок авторизации и пользовательский агент, можете ли вы объяснить, почему?   -  person Prabhjot Singh Kainth    schedule 22.12.2019
comment
Это была своего рода опечатка для пользовательского агента. Я исправил это, и они имеют одинаковое значение. Что касается заголовка авторизации, значения полностью передаются прокси-серверу, и это механизм вызова ответа, разработанный между клиентом и сервером.   -  person Nitb    schedule 23.12.2019


Ответы (1)


Если вы посмотрите на свой запрос 1, тела нет, но вы получаете ответ 100 continue от прокси-сервера, что, как я полагаю, связано с заголовком запроса Expect «100-continue», добавленным Nginx (вероятно, из-за записи конфигурации proxy_set_header Ожидайте $http_expect;), но это неправильно согласно спецификации,

https://www.w3.org/Protocols/rfc2616/rfc2616-sec8.html

Клиент НЕ ДОЛЖЕН отправлять поле заголовка запроса Expect (раздел 14.20) с ожиданием «100-continue», если он не намерен отправлять тело запроса.

Это может быть причиной зависания, поскольку сервер может ожидать тело (для запроса 1), которое никогда не будет получено.

person Tom A    schedule 23.12.2019
comment
Клиент в REQUEST 1 передает Expect: 100-continue и, следовательно, прокси-сервер (а также nginx) отправляет ответ 100 Continue, как и ожидалось. Проблема заключается в шаге 3, когда запрос попадает в nginx и далее передается на прокси-сервер, базовое TCP-соединение является новым и не таким, как созданное при первом выполнении запроса 1. - person Nitb; 23.12.2019
comment
Итак, если я правильно понял, второй запрос принимается прокси-сервером Nginx и перенаправляется на проксируемый Nginx по отдельному TCP-соединению, но вы не видите второго запроса в логах проксируемого Nginx, верно? - person Tom A; 23.12.2019
comment
Да, второй запрос получен прокси-сервером nginx, но нет никакой дополнительной информации о том, что с ним произошло. Согласно трассировкам wireshark, ACK был отправлен запрашивающему клиенту. TCP-соединение с проксируемым сервером было разорвано nginx. Итак, похоже, что nginx сожрал Request 2 без каких-либо следов. - person Nitb; 26.12.2019