Назад | Перейти на главную страницу

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?

Я считаю, что ключом к решению проблем 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-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.