Вопрос: 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 заключается в использовании правильно-most value - что, очевидно, является лишь одним из наших прокси-серверов.

Мое понимание X-Real-IP заключается в том, что это предполагаемый для использования для определения фактический IP-адрес клиента - не прокси. Я что-то пропустил, или это ошибка в nginx?

И кроме того, есть ли у кого-нибудь какие-либо предложения о том, как сделать X-Real-IP заголовок отображает оставилкак это указано в определении X-Forwarded-For?


46
2017-09-22 20:41


Источник




Ответы:


Я считаю, что ключом к решению проблем с 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 options, вы можете определить несколько доверенных прокси, и он получит последний ненадежный 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 config nginx будет доверять только двум последним адресам в качестве прокси. Это означает, что nginx будет правильно выбирать 123.123.123.123 как IP-адрес, несмотря на то, что поддельный IP фактически является самым левым.


73
2017-08-03 22:45



Большое вам спасибо за это, это действительно помогло мне. Это должен быть принятый ответ. - José F. Romaniello
По умолчанию real_ip_header выглядит как X-Real-IP согласно nginx.org/en/docs/http/ngx_http_realip_module.html Означает ли это, что злоумышленник может просто отправить запрос со случайным X-Real-IP и который будет использоваться как $ remote_addr в nginx (а также, возможно, передан в приложение)? - gansbrest
@gansbrest Нет, потому что set_real_ip_from ограничивает доверенные хосты. - El Yobo


Анализ синтаксического анализа X-Forwarded-Forзаголовок действительно испорчен в модуле real_ip nginx.

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 - прорыть их документация подтверждает заказ; leftmost - оригинальный клиент, самый правый - последний. У меня очень соблазн добавить [нужна цитата] на эту страницу в Википедии. Один анонимное редактирование кажется, является авторитетом Интернета по этому вопросу.

Если возможно, можете ли вы, чтобы промежуточные прокси перестали добавлять себя в конец заголовка, просто оставив его только с реальным адресом клиента?


9
2017-09-22 22:08



Спасибо за ответ, @Shane. Фактически, при достижении nginx, X-Forwarded-For уже существует. (это правильный IP-адрес клиента) Nginx сам затем переходит к добавлению IP-адреса нашего балансировщика нагрузки (предыдущего перехода) к X-Forwarded-For заголовок. (предположительно добавляя то, что он видит как «удаленный адрес»). Если бы это просто не делалось, я мог бы просто использовать X-Forwarded-For как и раньше. (мы недавно перешли на nginx) - Kirk Woll
@Kirk Итак, когда nginx получает заголовок, это только адрес исходного клиента? Но когда он обрабатывает его, он добавляется в заголовок соединительного прокси-сервера? Это не складывается - единственный раз, когда он должен касаться этого заголовка, когда он отправляет соединение другому прокси через proxy_pass - и даже тогда, только с proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; на месте. - Shane Madden♦
Даже W3C ошибается: в их документации указано, что «прокси должны добавить IP-адрес инициатора запроса к конец списка разделенных запятыми в поле заголовка X-Forwarded-For HTTP ", он должен указывать начало, - Ian Kemp
@IanKemp, нет, конец верно. На стороне сервера прокси-сервера инициатор запроса (т.е. TCP запрос) является предыдущим прокси (если таковой имеется). Этот предыдущий прокси-сервер, возможно, уже отправляет X-Forwarded-For заголовок, возможно, с исходным адресом клиента слева и, возможно, с любыми предыдущими прокси-серверами, добавленными к нему. Таким образом, текущий обслуживающий прокси добавит предыдущий прокси (= инициатор) в конец этого списка и будет обслуживать, таким образом, расширенный X-Forwarded-For заголовок к следующему ходу вверх. Конечно, они могли выбрать более очевидную формулировку. - blubberdiblub


X-Real-IP - это IP-адрес фактического клиента, с которым разговаривает сервер («реальный» клиент сервера), который в прокси-соединении является прокси-сервером. Вот почему X-Real-IP будет содержать последний IP-адрес в заголовке X-Forwarded-For.


4
2017-09-22 21:07



Хорошо, но для меня это просто никогда не бывает полезной информацией. Я хочу получить исходный IP-адрес клиента - это очень важно, и в соответствии со всем, что я прочитал, целью этих заголовков. Почему я хочу знать IP-адрес наших прокси-серверов? - Kirk Woll
Если вам это не полезно, то это не для вас. Никто не заставляет вас использовать X-Real-IP. Если вам нужен IP-адрес пользователя в вашем приложении, попробуйте выполнить его синтаксический анализ X-Forwarded-For (который не всегда надежный, поскольку существуют некоторые прокси-серверы (интернет-устройства безопасности / брандмауэры), которые не устанавливают X-Forwarded- Для). В контексте nginx X-Forwarded-For не имеет значения, поскольку он не разговаривает с этими клиентами в любом случае, кроме последней записи (X-Real-IP), которая является клиентом nginx. Если вам это не нужно, не устанавливайте его, не устанавливайте и не игнорируйте: / - user558061
Нет, я имею в виду, почему X-Real-IP возврат моего собственного IP-адреса прокси-сервера Когда-либо быть полезным? - Kirk Woll
Great .. ответ мужчина. Я искал эту точную информацию. Мне нужно поговорить с сервером ncat на моем прокси-сервере, поэтому мне нужно это на лету. - Yugal Jindle