Рейтинг:0

NGINX направляет неправильный виртуальный хост, если заголовок хоста содержит символ двоеточия.

флаг cn

В моем nginx.conf есть несколько разделов «сервер» и общий раздел сервера. Вот пример nginx.conf, чтобы дать вам представление:

www-данные пользователя;
рабочие_процессы авто;
worker_cpu_affinity авто;
pid /run/nginx.pid;

События {
    worker_connections 4000;
    использовать эполл;
    accept_mutex выключен;
}

http {
    включить /etc/nginx/mime.types;
    default_type application/octet-stream;
    журнал_ошибок /var/log/nginx/error.log;

    сервер {
        слушать 80;

        имя_сервера foo.com;

        место расположения / {
            default_type текстовый/обычный;
            вернуть 200 "привет от foo.com";
        }

        error_page 500 502 503 504 /500.html;
    }

    сервер {
        слушать 80 default_server;
        имя сервера _;

        место расположения / {
            вернуть 403 "извините";
        }
    }

}

Я ожидаю, что сервер вернет 403, если заголовок «Host» не является «foo.com».

Кто-то явно запускает Burp Suite на моем сервере, и я заметил интересное поведение, когда они отправляют заголовок «Host: foo.com:more-stuff-here»: NGINX направляет запрос в первый раздел «сервер». Похоже, что он игнорирует двоеточие и все после него в значении заголовка.

Я могу воспроизвести его локально с помощью приведенного выше nginx.conf:

$ curl -H "Хост: foo.com" http://127.0.0.1
привет с foo.com

$ curl -H "Хост: foo.com:unexpected-content" http://127.0.0.1
привет с foo.com

$ curl -H "Хост: bar.com" http://127.0.0.1
Извините

Почему NGINX это делает? Это ожидаемое поведение? Что нужно изменить в nginx.conf, чтобы запросы с заголовком «Host: foo.com:more-stuff-here» попадали в блок по умолчанию?

Обновлять: Для тех, кто исследует ту же проблему, я также создал тикет в системе отслеживания проблем NGINX.

djdomi avatar
флаг za
подчеркивание аннулирует имя хоста и делает его именем по умолчанию
Pēteris Caune avatar
флаг cn
@djdomi — в документах nginx говорится, что подчеркивание не имеет особого значения, это просто недопустимое имя хоста. Важным битом является «default_server» в директиве listen. Я не понимаю, почему nginx рассматривает значение хоста «foo.com: unexpected-content» как прямое совпадение с именем сервера «foo.com».
Рейтинг:3
флаг in

Определение заголовка хоста в HTTP RFC указывает, что заголовок Host должен иметь форму хост:порт, с : порт быть необязательным.

nginx видит все после двоеточия как порт для хоста, но это не имеет значения в вашем контексте, поскольку вы не указали блок сервера таким образом. Таким образом, он использует самое близкое совпадение, которое может найти, хост без «порта».

Pēteris Caune avatar
флаг cn
Ах я вижу. Что я могу сделать, чтобы исправить это? Можно ли заставить nginx игнорировать запросы с недопустимыми значениями порта?
флаг in
Это ваша проблема, что приложение, которое отправляет недопустимые запросы, не работает должным образом? Если да, я бы исправил приложение, если нет, я бы просто проигнорировал его.
флаг in
Единственный вариант, который я могу придумать, это попытаться добавить `foo.com:*` в качестве псевдонима server_alias к хосту по умолчанию и надеяться, что nginx достаточно умен, чтобы отличить его.
Pēteris Caune avatar
флаг cn
Мое приложение генерирует предупреждение о недопустимом заголовке узла. Я могу отключить предупреждение, но я бы предпочел, чтобы NGINX мог перехватывать недопустимые запросы до того, как они будут отправлены в приложение.
Pēteris Caune avatar
флаг cn
Я проверил `foo.com:*`, NGINX не запускается и выдает ошибку: `недопустимое имя сервера или подстановочный знак "foo.com:*"`
флаг in
Столько думал. Ну, тогда я не думаю, что вы можете что-то сделать на стороне nginx. Это должно быть исправлено в приложении, которое делает недопустимые запросы.
Рейтинг:0
флаг tl

Единственная альтернативная мысль, о которой я мог подумать, - это закодировать что-то на уровне приложения на стороне сервера, чтобы проверить значение хоста и вернуть ответ 403 в коде.

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

например, взяв из этот ТАК ответ учитывая приложение PHP, вы можете легко изменить эту логику для достижения желаемого эффекта, особенно обратите внимание на проверку SERVER_PORT согласно ответ Джеральда

$allowed_hosts = array('foo.example.com', 'bar.example.com');
$allowed_ports = массив (80 443);
if (!isset($_SERVER['HTTP_HOST']) || !in_array($_SERVER['HTTP_HOST'], $allowed_hosts) || !in_array($_SERVER['SERVER_PORT'], $allowed_ports )) {
    header($_SERVER['SERVER_PROTOCOL'].' 400 Неверный запрос');
    выход;
}
Pēteris Caune avatar
флаг cn
Спасибо за ответ. Вот как это работает сейчас для меня здесь (бэкэнд-приложение использует веб-фреймворк Django, который проверяет заголовок хоста на соответствие списку разрешений. Это нормально, но я надеялся, что NGINX будет действовать как «щит» перед бэкэнд-приложением. , гарантируя, что только действительные, правильно сформированные запросы проходят к серверному приложению)
Рейтинг:0
флаг us

Следующее может работать для default_server:

сервер {
    слушать 80 default_server;

    имя_сервера _ ~пример\.com:;

    место расположения / {
        вернуть 403 "извините";
    }
}

Важная часть - тильда ~, что указывает на соответствие регулярному выражению.

Pēteris Caune avatar
флаг cn
Хорошая идея, но мне кажется, что она не работает — запрос по-прежнему перенаправляется в другой раздел сервера.

Ответить или комментировать

Большинство людей не понимают, что склонность к познанию нового открывает путь к обучению и улучшает межличностные связи. В исследованиях Элисон, например, хотя люди могли точно вспомнить, сколько вопросов было задано в их разговорах, они не чувствовали интуитивно связи между вопросами и симпатиями. В четырех исследованиях, в которых участники сами участвовали в разговорах или читали стенограммы чужих разговоров, люди, как правило, не осознавали, что задаваемый вопрос повлияет — или повлиял — на уровень дружбы между собеседниками.