Я считаю, что ключом к решению проблем X-Forwarded-For, когда несколько IP-адресов объединены в цепочку, является недавно представленная опция конфигурации real_ip_recursive
(добавлена в nginx 1.2.1 и 1.3 .0). Из nginx realip docs :
Если включен рекурсивный поиск, исходный адрес клиента, соответствующий одному из доверенных адресов, заменяется последним недоверенным адресом, отправленным в поле заголовка запроса.
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-Real-IP is the IP address of the actual client the server is talking to (the "real" client of the server), which, in the case of a proxied connection, is the proxy server. That's why X-Real-IP will contain the last IP in the X-Forwarded-For header.
Анализ заголовка 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 - просмотр их документации подтверждает заказ; крайний левый - исходный клиент, крайний правый - самое последнее добавление. Мне очень хочется добавить [необходима цитата] на эту страницу википедии. Одно анонимное редактирование , кажется, является авторитетом в Интернете по этому вопросу.
Если возможно, можете ли вы, чтобы ваши промежуточные прокси перестали добавлять себя в конец заголовка, просто оставив его только с реальным адресом клиента ?
Больше похоже на предупреждение, чем на ответ ...
Я попытался добавить несколько серверов кеширования Nginx в нескольких местах на карте, не осознавая, что мой основной сервер (источник данных) уже находится за сервером кеша Nginx, который работает локально , иногда локальный сервер настраивается для запуска Apache, а Nginx помещается перед ним в качестве кеша.
Добавление второго отдельного сервера кеширования Nginx приведет к созданию двух серверов кеширования, поэтому ваш HTTP_X_REAL_IP
или HTTP_X_FORWARDED_FOR
выглядит неверно, показывая IP, равный единице, если серверы вместо IP посетителя.
В моем случае я исправил, что, установив новый сервер кеширования, он будет получать данные непосредственно из порта Apache (в моем случае это порт 7080), минуя локальный кеш Nginx на исходном / основном сервере.
Другим решением было бы удалить HTTP_X_REAL_IP
на локальном кэш-сервере.
Кстати, я использовал панель Plesk.