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.

Другие вопросы по тегам