Opened 3 years ago

Closed 3 years ago

Last modified 3 years ago

#1387 closed defect (worksforme)

large_client_header_buffers, SSL, 400 Bad Request

Reported by: iHeadRu@… Owned by:
Priority: minor Milestone:
Component: nginx-core Version: 1.12.x
Keywords: Cc:
uname -a: FreeBSD 11.0-RELEASE-p8
nginx -V: nginx version: nginx/1.12.1
built by clang 3.8.0 (tags/RELEASE_380/final 262564) (based on LLVM 3.8.0)
built with OpenSSL 1.0.2l 25 May 2017
TLS SNI support enabled
configure arguments: --with-http_stub_status_module --with-http_flv_module --without-http_empty_gif_module --without-http_memcached_module --without-http_upstream_ip_hash_module --without-http_browser_module --with-http_ssl_module --without-http_uwsgi_module --without-http_scgi_module --with-openssl=../openssl-1.0.2l --with-http_v2_module --with-pcre-jit --with-http_auth_request_module --with-file-aio

Description

В документации large_client_header_buffers http://nginx.org/en/docs/http/ngx_http_core_module.html#large_client_header_buffers сказано, что если заголовок не умещается в один буфер large_client_header_buffers, то должен возвращаться "400 Bad Request".

Я моделирую ситуацию, отправляю заголовок Cookie, который больше буфера large_client_header_buffers и вижу разный результат при http и https запросах.

В случае с http получаю
400 Bad Request
Request Header Or Cookie Too Large
Так и должно быть.

В случае с https (http1.1 или http2) запрос обрабатывается, т.е. если это статика, то она отдается, если это проксирование, то запрос передается к бэкенду.

Change History (5)

comment:1 by Maxim Dounin, 3 years ago

Resolution: worksforme
Status: newclosed

Простой тест:

    server {
        listen 8080;
        listen 8443 ssl;

        ssl_certificate mdounin.ru.crt;
        ssl_certificate_key mdounin.ru.key;

        client_header_buffer_size 256;
        large_client_header_buffers 8 256;

        return 200 ok\n;
    }

Тестируем с помощью curl, заголовок ~200 байт:

$ curl -I -H 'Cookie: 12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890' http://127.0.0.1:8080/
HTTP/1.1 200 OK
Server: nginx/1.13.6
Date: Wed, 27 Sep 2017 17:22:14 GMT
Content-Type: text/plain
Content-Length: 3
Connection: keep-alive

То же, но заголовок 300 байт:

$ curl -I -H 'Cookie: 123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890' http://127.0.0.1:8080/
HTTP/1.1 400 Bad Request
Server: nginx/1.13.6
Date: Wed, 27 Sep 2017 17:23:05 GMT
Content-Type: text/html
Content-Length: 249
Connection: close

То есть для http всё работает, как и должно - 400 Bad Request при превышении размера large_client_header_buffers.

То же самое для https, 200 байт:

$ curl -k -I -H 'Cookie: 12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890' https://127.0.0.1:8443/
HTTP/1.1 200 OK
Server: nginx/1.13.6
Date: Wed, 27 Sep 2017 17:25:23 GMT
Content-Type: text/plain
Content-Length: 3
Connection: keep-alive

И 300 байт:

$ curl -k -I -H 'Cookie: 123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890' https://127.0.0.1:8443/
HTTP/1.1 400 Bad Request
Server: nginx/1.13.6
Date: Wed, 27 Sep 2017 17:24:39 GMT
Content-Type: text/html
Content-Length: 249
Connection: close

Поведение ровно то же, что и для http, и именно такое, как должно быть.

Отмечу в скобках, что в случае HTTP/2 чтение заголовков запроса происходит по другому, и соответствующие буфера не используются. Вместо этого применяется явное ограничение на размер заголовка, http2_max_field_size

comment:2 by iHeadRu@…, 3 years ago

Получается, в nginx разные лимиты длины заголовка на http 1 и http 2. Более того, в случае с http2 лимит на сжатые данные вообще не позволяет добиться одинаковых лимитов.

Как может быть такое, что Google Chrome и Mozilla Firefox отправляют запрос HTTP 2.0 на server, в котором в директиве listen http2 не активирован?

in reply to:  2 comment:3 by Valentin V. Bartenev, 3 years ago

Replying to iHeadRu@…:

Получается, в nginx разные лимиты длины заголовка на http 1 и http 2. Более того, в случае с http2 лимит на сжатые данные вообще не позволяет добиться одинаковых лимитов.

Разные протоколы требуют разной обработки для заголовков, отсюда и методы ограничения разные.

Как может быть такое, что Google Chrome и Mozilla Firefox отправляют запрос HTTP 2.0 на server, в котором в директиве listen http2 не активирован?

HTTP/2 включается для всего порта, а не для конкретного виртуального сервера.
http://nginx.org/ru/docs/http/ngx_http_core_module.html#listen

Last edited 3 years ago by Valentin V. Bartenev (previous) (diff)

comment:4 by iHeadRu@…, 3 years ago

Понятно.
Работающий http2 для всего порта выглядит странно.
Получается, что если активировать его в одном виртуальном сервере, то он будет активирован неявно во всех виртуальных хостах с этим IP:порт?

in reply to:  4 comment:5 by Valentin V. Bartenev, 3 years ago

Replying to iHeadRu@…:

Понятно.
Работающий http2 для всего порта выглядит странно.
Получается, что если активировать его в одном виртуальном сервере, то он будет активирован неявно во всех виртуальных хостах с этим IP:порт?

Верно. Так же как и SSL, так же как и большинство параметров директивы listen. И это во многом обусловлено самим протоколом HTTP/2.

Note: See TracTickets for help on using tickets.