nginx real_ip_header i X-Forwarded-For wydają się błędne

59

Opis nagłówka HTTP w Wikipedii X-Forwarded-Forto:

X-Forwarded-For: klient1, proxy1, proxy2, ...

Dokumentacja nginx dla tej dyrektywy real_ip_headerbrzmi częściowo:

Niniejsza dyrektywa określa nazwę nagłówka używanego do przesyłania zastępczego adresu IP.
W przypadku X-Forwarded-For, ten moduł używa ostatniego adresu IP w nagłówku X-Forwarded-For do wymiany. [Moje podkreślenie]

Te dwa opisy wydają się ze sobą sprzeczne. W naszym scenariuszu X-Forwarded-Fornagłówek jest dokładnie taki, jak opisano - „rzeczywisty” adres IP klienta jest pozycją najbardziej po lewej stronie. Podobnie zachowanie nginx polega na użyciu najwyższej wartości z prawej strony - która oczywiście jest tylko jednym z naszych serwerów proxy.

Rozumiem X-Real-IP, że powinien on służyć do określania rzeczywistego adresu IP klienta - nie proxy. Czy coś pomijam, czy jest to błąd w Nginx?

A poza tym, czy ktoś ma jakieś sugestie, jak ustawić X-Real-IPwyświetlanie nagłówka na skrajnej lewej wartości, jak wskazuje definicja X-Forwarded-For?

Kirk Woll
źródło

Odpowiedzi:

97

Uważam, że kluczem do rozwiązania problemów X-Forwarded-For w przypadku połączenia wielu adresów IP jest ostatnio wprowadzona opcja konfiguracji real_ip_recursive(dodana w nginx 1.2.1 i 1.3.0). Z dokumentów Nginx Realip :

Jeśli włączone jest wyszukiwanie rekurencyjne, oryginalny adres klienta pasujący do jednego z zaufanych adresów jest zastępowany ostatnim niezaufanym adresem wysłanym w polu nagłówka żądania.

nginx domyślnie pobierał ostatni adres IP w łańcuchu, ponieważ był to jedyny, który był uważany za zaufany. Ale dzięki nowej real_ip_recursivewłączonej i wielu set_real_ip_fromopcjom możesz zdefiniować wiele zaufanych serwerów proxy, a ona pobierze ostatni niezaufany adres IP.

Na przykład przy tej konfiguracji:

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;

I nagłówek X-Forwarded-For, w wyniku czego:

X-Forwarded-For: 123.123.123.123, 192.168.2.1, 127.0.0.1

nginx wybierze teraz 123.123.123.123 jako adres IP klienta.

Jeśli chodzi o to, dlaczego nginx nie wybiera tylko adresu IP znajdującego się najbardziej z lewej strony i wymaga jawnego zdefiniowania zaufanych serwerów proxy, ma to na celu zapobieganie łatwemu fałszowaniu adresów IP.

Powiedzmy, że prawdziwy adres IP klienta to 123.123.123.123. Powiedzmy też, że klient nie ma nic dobrego, a oni próbują sfałszować swój adres IP 11.11.11.11. Wysyłają żądanie do serwera z tym nagłówkiem już na miejscu:

X-Forwarded-For: 11.11.11.11

Ponieważ odwrotne serwery proxy po prostu dodają adresy IP do tego łańcucha X-Forwarded-For, powiedzmy, że wygląda to tak, gdy nginx do niego dojdzie:

X-Forwarded-For: 11.11.11.11, 123.123.123.123, 192.168.2.1, 127.0.0.1

Jeśli po prostu złapiesz adres znajdujący się najbardziej po lewej stronie, pozwoli to klientowi łatwo sfałszować swój adres IP. Ale w powyższej przykładowej konfiguracji nginx, nginx będzie ufał tylko dwóm ostatnim adresom jako proxy. Oznacza to, że nginx poprawnie wybierze 123.123.123.123jako adres IP, mimo że sfałszowany adres IP jest w rzeczywistości najbardziej lewy.

Nick M.
źródło
2
Dziękuję bardzo za to, naprawdę mi pomogło. To powinna być zaakceptowana odpowiedź.
José F. Romaniello,
1
Domyślnie real_ip_header wydaje się być X-Real-IP zgodnie z nginx.org/en/docs/http/ngx_http_realip_module.html Czy to oznacza, że ​​złośliwy użytkownik może po prostu wysłać żądanie z losowym X-Real-IP i będzie ono użyte jako $ remote_addr w nginx (a także prawdopodobnie przekazany do aplikacji)?
gansbrest
@gansbrest Nie, ponieważ set_real_ip_from ogranicza zaufanych hostów.
El Yobo,
9

Analiza X-Forwarded-Fornagłówka jest rzeczywiście wadliwa w module 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;
  }
}

Zaczyna się po prawej stronie łańcucha nagłówka i gdy tylko zobaczy spację lub przecinek, przestaje szukać i umieszcza część po prawej stronie spacji lub przecinka w zmiennej IP. Tak więc traktuje najnowszy adres proxy jako oryginalny adres klienta .

Zgodnie ze specyfikacją nie gra się dobrze; istnieje niebezpieczeństwo, że nie zostanie to określone w bolesny sposób w RFC.

Poza tym: trudno jest znaleźć dobre podstawowe źródło formatu, który pierwotnie zdefiniował Squid - przegląd ich dokumentacji potwierdza zamówienie; leftmost jest oryginalnym klientem, najbardziej na prawo jest najnowszym dodatkiem. Kusi mnie, aby dodać [potrzebne źródło] do tej strony wikipedii. Jedna anonimowa edycja wydaje się być autorytetem Internetu w tej dziedzinie.

Jeśli to możliwe, czy Twoje pośredniczące serwery proxy mogą przestać dodawać się na końcu nagłówka, pozostawiając tylko prawdziwy adres klienta?

Shane Madden
źródło
Dzięki za odpowiedź, @Shane. W rzeczywistości po osiągnięciu nginx X-Forwarded-Forjuż istnieje. (jest to poprawny adres IP klienta) sam nginx następnie dołącza adres IP naszego modułu równoważenia obciążenia (poprzedniego przeskoku) do X-Forwarded-Fornagłówka. (przypuszczalnie dołączając to, co postrzega jako „zdalny adres”) Gdyby tego po prostu nie zrobił, byłbym w stanie po prostu użyć X-Forwarded-Fornagłówka jak poprzednio. (niedawno przeprowadziliśmy migrację do nginx)
Kirk Woll
@Kirk Więc kiedy nginx dostaje nagłówek, jest to tylko adres oryginalnego klienta? Ale kiedy go przetwarza, jest dodawany do nagłówka łączącego się serwera proxy? To się nie sumuje - jedyny raz powinien dotknąć tego nagłówka, gdy wysyła połączenie z innym serwerem proxy za pośrednictwem proxy_pass- i nawet wtedy, gdy jest proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;na miejscu.
Shane Madden
Nawet W3C robi to źle : ich dokumentacja stwierdza, że ​​„serwery proxy powinny dodać adres IP inicjatora żądania na końcu listy rozdzielanej przecinkami w polu nagłówka HTTP X-Forwarded-For”, powinno to oznaczać początek .
Ian Kemp,
3
@IanKemp, nie, koniec jest poprawny. Po stronie serwera proxy inicjator żądania (tj. Żądanie TCP ) jest poprzednim serwerem proxy (jeśli taki istnieje). Ten poprzedni serwer proxy prawdopodobnie już wysyła X-Forwarded-Fornagłówek z prawdopodobnie pierwotnym adresem klienta po lewej stronie i ewentualnie wszelkie wcześniejsze serwery proxy do niego dołączone. Tak więc obecnie serwujący serwer proxy dodałby poprzedni serwer proxy (= inicjator) na końcu tej listy i służyłby w ten sposób powiększony X-Forwarded-Fornagłówek do następnego przeskoku w górę. To prawda, że ​​mogli wybrać bardziej oczywiste sformułowanie.
blubberdiblub
5

X-Real-IP to adres IP rzeczywistego klienta, z którym rozmawia serwer („prawdziwy” klient serwera), który w przypadku połączenia proxy jest serwerem proxy. Właśnie dlatego X-Real-IP będzie zawierać ostatni adres IP w nagłówku X-Forwarded-For.

użytkownik558061
źródło
1
OK, ale dla mnie to po prostu nigdy nie jest przydatna informacja. Chcę uzyskać oryginalny adres IP klienta - jest to kluczowe i zgodnie ze wszystkim, co przeczytałem, celem tych nagłówków. Dlaczego miałbym chcieć znać adres IP naszych serwerów proxy?
Kirk Woll,
Jeśli to nie jest dla ciebie przydatne, to nie jest dla ciebie. Nikt nie zmusza Cię do korzystania z X-Real-IP. Jeśli potrzebujesz adresu IP użytkownika w swojej aplikacji, poproś o przeanalizowanie X-Forwarded-For (co nie zawsze jest niezawodne, ponieważ istnieją proxy (urządzenie zabezpieczające / zapory internetowe), które nie ustawiają X-Forwarded- Dla). W kontekście nginx X-Forwarded-For nie jest ważny, ponieważ i tak nie rozmawia z tymi klientami, oprócz ostatniego wpisu (X-Real-IP), który jest klientem nginx. Jeśli go nie potrzebujesz, nie ustawiaj go, nie
rozbieraj
2
Nie, chodzi mi o to, dlaczego X-Real-IPzwracanie adresu IP mojego własnego serwera proxy byłoby kiedykolwiek przydatne?
Kirk Woll,
Świetnie .. odpowiedz człowieku. Szukałem tych dokładnych informacji. Muszę porozmawiać z serwerem ncat na moim serwerze proxy, więc potrzebuję tego w locie.
Yugal Jindle