nginx real_ip_header и X-Forwarded-For кажутся неправильными
Описание википедии заголовка HTTP X-Forwarded-For
является:
X-Forwarded-For: client1, proxy1, proxy2,...
Документация nginx для директивы real_ip_header
читает, частично:
Эта директива устанавливает имя заголовка, используемого для передачи замещающего IP-адреса.
В случае X-Forwarded-For этот модуль использует последний ip в заголовке X-Forwarded-For для замены. [Акцент мой]
Эти два описания противоречат друг другу. В нашем сценарии X-Forwarded-For
заголовок в точности соответствует описанию - "реальный" IP-адрес клиента является самой левой записью. Аналогично, поведение nginx состоит в том, чтобы использовать самое правильное значение, которое, очевидно, является лишь одним из наших прокси-серверов.
Мое понимание X-Real-IP
это то, что он должен использоваться для определения фактического IP-адреса клиента, а не прокси. Я что-то упустил, или это ошибка в nginx?
И, кроме того, есть ли у кого-нибудь предложения о том, как сделать X-Real-IP
заголовок отображает крайнее левое значение, как указано в определении X-Forwarded-For
?
3 ответа
Я считаю, что ключ к решению проблем X-Forwarded-For, когда несколько IP соединены в цепочку, является недавно представленной опцией конфигурации, real_ip_recursive
(добавлено в nginx 1.2.1 и 1.3.0). Из документов nginx realip:
Если рекурсивный поиск включен, исходный адрес клиента, который соответствует одному из доверенных адресов, заменяется последним ненадежным адресом, отправленным в поле заголовка запроса.
nginx по умолчанию захватывал последний IP-адрес в цепочке, поскольку предполагалось, что он является единственным доверенным. Но с новым real_ip_recursive
включен и с несколькими set_real_ip_from
Параметры, вы можете определить несколько доверенных прокси, и он будет выбирать последний ненадежный IP.
Например, с этим конфигом:
set_real_ip_from 127.0.0.1;
set_real_ip_from 192.168.2.1;
real_ip_header X-Forwarded-For;
real_ip_recursive on;
И заголовок X-Forwarded-For, в результате чего:
X-Forwarded-For: 123.123.123.123, 192.168.2.1, 127.0.0.1
Теперь nginx выберет 123.123.123.123 в качестве IP-адреса клиента.
Что касается того, почему nginx не просто выбирает крайний левый IP-адрес и требует от вас явного определения доверенных прокси-серверов, это предотвращает простую подмену IP-адреса.
Допустим, реальный IP-адрес клиента 123.123.123.123
, Давайте также скажем, что клиент не работает, и они пытаются подделать свой IP-адрес, чтобы 11.11.11.11
, Они отправляют запрос на сервер с таким заголовком:
X-Forwarded-For: 11.11.11.11
Поскольку обратные прокси-серверы просто добавляют IP-адреса в эту цепочку X-Forwarded-For, допустим, что в итоге это выглядит так, когда nginx доберется до него:
X-Forwarded-For: 11.11.11.11, 123.123.123.123, 192.168.2.1, 127.0.0.1
Если вы просто захватите крайний левый адрес, это позволит клиенту легко подделать свой IP-адрес. Но в приведенном выше примере конфигурации nginx nginx будет доверять только двум последним адресам в качестве прокси. Это означает, что nginx будет правильно выбирать 123.123.123.123
в качестве IP-адреса, несмотря на то, что этот поддельный IP-адрес фактически является самым левым.
Разбор из X-Forwarded-For
заголовок действительно содержит ошибки в модуле nginx real_ip.
len = r->headers_in.x_forwarded_for->value.len;
ip = r->headers_in.x_forwarded_for->value.data;
for (p = ip + len - 1; p > ip; p--) {
if (*p == ' ' || *p == ',') {
p++;
len -= p - ip;
ip = p;
break;
}
}
Он начинается в крайнем правом углу строки заголовка и, как только он видит пробел или запятую, он перестает смотреть и вставляет часть справа от пробела или запятой в переменной IP. Таким образом, последний адрес прокси обрабатывается как исходный адрес клиента.
Это не играет хорошо в соответствии со спецификацией; это опасность того, что это не будет изложено в болезненно очевидных терминах в RFC.
В стороне: Трудно даже найти хороший первоисточник в формате, который был первоначально определен Squid - копание их документации подтверждает порядок; крайний левый - оригинальный клиент, самый правый - самый последний. Мне очень хочется добавить [нужную цитату] на эту страницу википедии. Одно анонимное редактирование, кажется, авторитет интернета по этому вопросу.
Если возможно, можете ли вы, чтобы промежуточные прокси перестали добавлять себя в конец заголовка, оставив только реальный адрес клиента?
X-Real-IP - это IP-адрес фактического клиента, с которым общается сервер ("настоящий" клиент сервера), который в случае прокси-соединения является прокси-сервером. Вот почему X-Real-IP будет содержать последний IP-адрес в заголовке X-Forwarded-For.
Больше предупреждение, чем ответ...
Я попытался добавить несколько серверов кеширования Nginx в нескольких местах карты, не осознавая, что мой основной сервер (источник данных) уже находится за сервером кеша Nginx, который работает локально, иногда локальный сервер настроен для запуска Apache, а Nginx помещается перед ним, чтобы действовать как кеш.
Добавление второго отдельного сервера кеширования Nginx приведет к созданию двух серверов кеширования, поэтому ваш
HTTP_X_REAL_IP
или же
HTTP_X_FORWARDED_FOR
отображается неправильно, показывая IP одного, если серверы вместо IP посетителя.
В моем случае я исправил, что, установив новый сервер кеширования, он будет получать данные непосредственно из порта Apache (в моем случае это порт 7080), минуя локальный кеш Nginx на исходном / основном сервере.
Другим решением было бы удалить
HTTP_X_REAL_IP
на локальном кеш-сервере.
Кстати, я запускал панель Plesk.