Я использую Nginx в качестве прокси для веб-службы Java.
Моя конфигурация выглядит так:
location /webservice {
proxy_read_timeout 240;
proxy_connect_timeout 240;
proxy_pass http://127.0.0.1:8080/;
}
В своих журналах я вижу много таких записей:
xx.xx.xx.xx - - [18/Oct/2011:02:44:23 +0000] "GET http://l04.member.in2.yahoo.com/config/login?login=email@example.com&passwd=password HTTP/1.0" 200 9 "-" "Mozilla/4.0 (compatible; MSIE 5.0; Series60/2.8 Nokia6630/4.06.0 Profile/MIDP-2.0 Configuration/CLDC-1.1)"
Я провел некоторое тестирование, насколько я могу видеть свой прокси не пересылка запросов на внешние сайты, но Я хотел бы заблокировать все эти запросы и / или вернуть код статуса, отличный от 200.
Я сделал это:
if ($request_method !~ ^(GET|HEAD|POST)$ ) { return 444; }
который блокирует попытки CONNECT. Любые идеи (помимо блокировки IP) будут оценены.
Nginx будет принимать соединения и обрабатывать их на основе соответствия server_name (которое проверяется на соответствие заголовку Host). Nginx поставляется с серверным блоком по умолчанию, настроенным для соответствия всем хостам. Это позволяет обрабатывать любой запрос, поступающий на сервер.
Мне нравится настраивать проверку блока сервера для пустого заголовка Host, а также настраивать сервер по умолчанию для возврата ошибки 403 (например, если вы пытаетесь получить доступ к моему серверу через его IP-адрес). Затем каждый виртуальный хост получает свою собственную конфигурацию (т.е. любой допустимый хост соответствует конфигурации, все остальные либо попадают в блок сервера по умолчанию, либо в пустой блок хоста).
Сервер для проверки пустого хоста:
server {
listen 80;
server_name "";
return 444;
}
Сервер для перебрасывания 403 на все ненастроенные хосты:
server {
listen 80;
server_name _;
root /path/to/error/files;
error_page 403 /403.html;
location /403.html {
allow all;
}
deny all;
}
Следует отметить, что указанная выше директива listen необязательна (nginx по умолчанию прослушивает порт 80), но мой nginx работает за varnish, поэтому фактически не прослушивает порт 80.
В вашем случае вы добавите третий сервер, который будет обрабатывать ваши запросы обратного прокси:
server {
server_name mydomain.com;
...your other blocks...
}
Вы можете протестировать свою конфигурацию различными способами (я уверен, что их больше, но в данный момент они приходят на ум):
(Я использую google.com в качестве тестового домена ниже, измените его на ваш сайт по выбору):
Укажите весь запрос за один раз:
telnet mydomain.com 80
GET http://google.com
Укажите отдельно заголовок запроса и хоста:
telnet mydomain.com 80
GET / HTTP/1.1
Host: google.com
Установите запись в вашем файле hosts (на вашем сервере):
127.0.0.1 google.com
Используйте curl, чтобы попытаться получить страницу:
curl google.com
(В этом случае файл hosts сообщает вашему серверу, что на вашем компьютере можно найти google.com - который получает запрос к nginx - удалите запись после завершения тестирования.)
Редактировать: Похоже, что непреднамеренным следствием вышеизложенного является то, что недопустимые запросы приводят к ошибке 400. Вы можете определить основную причину этого, если хотите, добавив параметр info в свою директиву error_log. В моем случае с 400 ошибками, которые я видел, были связаны следующие причины:
Использование telnet с однострочным запросом GET (без заголовка хоста):
client sent invalid request while reading client request line
Произведены случайные (нестандартные) запросы:
client sent invalid method while reading client request line
Используя telnet, ждал слишком долго:
client timed out (110: Connection timed out) while reading client request headers
Другими частыми причинами были:
client sent invalid host header while reading client request headers
recv() failed (104: Connection reset by peer) while reading client request line
client closed prematurely connection while reading client request line
Использование curl привело к ожидаемой ошибке 444. Я полагаю, что у действительного запроса есть дополнительный синтаксис. Во всяком случае, насколько я понимаю, 400 ошибок обрабатываются раньше, чем 444, поэтому вполне вероятно, что они не исчезнут для действительно недействительных запросов.
Я смог успешно получить ошибку 444 с помощью telnet, хотя для этого потребовалось немного изменить мою конфигурацию:
server {
listen 80 default;
server_name _ "";
return 444;
}
Обратите внимание, что в приведенном выше «неуказанном имени сервера» (подчеркивание) и пустой хост (двойные кавычки) явно не определяется сервер по умолчанию, поэтому вы должны добавить «по умолчанию» в строку прослушивания.
Выход Telnet:
telnet localhost 80
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
GET / HTTP/1.1
Host: google.com
Вывод журнала доступа:
127.0.0.1 - - [19/Oct/2011:00:51:16 -0400] "GET / HTTP/1.1" 444 0 "-" "-" "-"
Я бы порекомендовал вам уменьшить размер отправленных заголовков (длина URL).
Пожалуйста, взгляните на client_header_buffer_size и large_client_header_buffers
Ограничение URI клиента - распространенный способ предотвратить отправку сканером или неисправным клиентом больших запросов, которые могут вызвать переполнение буфера.
Итак, если вы настроите large_client_header_buffers 1 1k
ваша служба nginx не будет принимать URI, размер которых превышает (1x1K = 1K) 1 килобайт данных (включая файлы cookie).
Дополнительно вы можете настроить ignore_invalid_headers off
если вы не ожидаете получить какие-либо нестандартные заголовки.