nginx real_ip_header і X-Forwarded-For здається неправильним


59

Опис вікіпедії заголовка 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?

Відповіді:


97

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


2
Дякую вам за це, мені це дуже допомогло. Це має бути прийнятою відповіддю.
Хосе Ф. Романьєлло

1
За замовчуванням 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 обмежує надійних хостів.
Ель Йобо

9

Розбір 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 - копання їх документації підтверджує замовлення; leftmost є оригінальним клієнтом, правий край - останнім додатком. Я дуже спокусився додати [цитування потрібне] до цієї сторінки вікіпедії. Здається, одна анонімна редакція є повноваженням Інтернету з цього приводу.

Якщо можливо, чи можете ви проміжні проксі-сервери перестати додавати себе до кінця заголовка, залишаючи лише реальну адресу клієнта?


Дякую за відповідь, @Shane. Насправді, коли ви досягаєте nginx, це X-Forwarded-Forвже існує. (це правильна IP-адреса клієнта) nginx сам потім переходить до додавання до X-Forwarded-Forзаголовка IP-адреси нашого балансира навантаження (попереднього переходу) . (імовірно, додаючи те, що він вважає "віддаленою адресою"). Якщо цього просто не зробив, я міг би просто використовувати X-Forwarded-Forзаголовок, як раніше. (нещодавно ми переходили на nginx)
Кірк Уолл

@Kirk Отже, коли nginx отримує заголовок, це лише оригінальна адреса клієнта? Але коли він обробляє його, він додається до заголовка підключення проксі-сервера? Це не додається - єдиний раз, коли він повинен торкатися цього заголовка, це коли він надсилає з'єднання до іншого проксі через proxy_pass- і навіть тоді, лише з proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;місцем.
Шейн Мадден

Навіть W3C помиляється : у їхній документації зазначено, що "проксі-сервіси повинні додати IP-адресу ініціатора запиту до кінця списку, розділеного комами, у полі заголовка X-Forwarded-For HTTP", він повинен зазначати початок .
Ян Кемп

3
@IanKemp, ні, кінець правильний. На стороні сервера проксі, ініціатором запиту (тобто запитом TCP ) є попередній проксі (якщо такий є). Цей попередній проксі, можливо, вже надсилає X-Forwarded-Forзаголовок з можливо оригінальною адресою клієнта зліва та, можливо, будь-якими попередніми проксі, доданими до цього. Таким чином, поточний проксі-сервер додав би попередній проксі (= ініціатор) до кінця цього списку і подасть таким чином доповнений X-Forwarded-Forзаголовок наступному стрибку вгору. Зрозуміло, вони могли обрати більш очевидне формулювання.
blubberdiblub

5

X-Real-IP - це IP-адреса фактичного клієнта, з яким розмовляє сервер ("реальний" клієнт сервера), який у випадку проксі-з'єднання є проксі-сервером. Ось чому X-Real-IP міститиме останній IP в заголовку X-Forwarded-For.


1
Гаразд, але, для мене, це просто ніколи корисна інформація. Я хочу отримати оригінальну IP-адресу клієнта - це дуже важливо, і відповідно до всього, що я прочитав, мета цих заголовків. Чому я хочу знати IP-адресу наших проксі-серверів?
Кірк Волл

Якщо це не корисно для вас, то це не для вас. Ніхто не змушує вас використовувати X-Real-IP. Якщо вам потрібен IP-адресу користувача у вашій програмі, тоді проаналізуйте програму X-Forwarded-For (що не завжди є надійним, оскільки є деякі проксі-сервери (пристрій безпеки / брандмауери), які не встановлюють X-Forwarded- Для). У контексті nginx, X-Forwarded-For не важливий, оскільки він так чи інакше не спілкується з цими клієнтами, окрім останнього запису (X-Real-IP), який є клієнтом nginx. Якщо він вам не потрібен, тоді не встановлюйте його, не зніміть його або просто проігноруйте: /
user558061

2
Ні, я маю в виду, чому б X-Real-IPповернення IP - адреса мого власного проксі - сервера коли - або бути корисним?
Кірк Волл

Чудово .. відповідь людина. Я шукав цю точну інформацію. Мені потрібно поговорити з ncat-сервером на моєму проксі-сервері, тому мені це потрібно на льоту.
Югал Джіндл
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.