Zaufane proxy

Gdy OxPHP działa za reverse proxy (Kubernetes Ingress, Cloudflare, AWS ALB, nginx), każde żądanie przychodzi z adresu IP proxy. Bez konfiguracji zaufanych proxy ograniczanie liczby żądań, rejestrowanie dostępu oraz $_SERVER['REMOTE_ADDR'] widzą adres IP proxy zamiast rzeczywistego klienta.

Konfiguracja

bash
# Comma-separated CIDR list TRUSTED_PROXIES="10.0.0.0/8,172.16.0.0/12,192.168.0.0/16" # Shorthand: all RFC-1918 + loopback + link-local (IPv4 and IPv6) TRUSTED_PROXIES="private" # Keywords and CIDRs combine in one list TRUSTED_PROXIES="private,cloudflare,100.64.0.0/10"

Każdy wpis rozdzielony przecinkami to CIDR, pojedynczy adres IP (jeden host) albo jedno ze słów kluczowych private i cloudflare, zapisane dowolną wielkością liter. Wpis, który nie jest żadnym z nich, powoduje błąd przy starcie.

Note

Gdy zmienna nie jest ustawiona, OxPHP ignoruje wszystkie nagłówki przekierowania. To bezpieczne ustawienie domyślne.

Jak to działa

Gdy żądanie przychodzi z zaufanego adresu IP, OxPHP analizuje nagłówki przekierowania w kolejności priorytetów:

  1. Forwarded (RFC 7239) — ustandaryzowany nagłówek
  2. X-Forwarded-For / X-Forwarded-Proto / X-Forwarded-Host / X-Forwarded-Port — faktyczny fallback

Jeśli obecny jest nagłówek Forwarded, nagłówki X-Forwarded-* są ignorowane.

Wydobywanie adresu IP klienta

OxPHP stosuje algorytm rightmost-non-trusted (skrajnie prawy niezaufany) — to samo podejście, którego używają nginx (real_ip_recursive on), Caddy, Traefik i Apache:

text
X-Forwarded-For: 203.0.113.50, 172.16.1.1, 10.0.0.5 TCP peer: 10.0.0.1 (trusted) Walk right-to-left: 10.0.0.5 → trusted → skip 172.16.1.1 → trusted → skip 203.0.113.50 → NOT trusted → client IP

Zapobiega to podszywaniu się przez doklejanie wartości z lewej strony. Atakujący może dodać fałszywe adresy IP po lewej stronie, ale skrajnie prawy niezaufany adres IP został ustawiony przez ostatnie zaufane proxy w łańcuchu.

Wpis może zawierać port: 203.0.113.50:4711 lub [2001:db8::1]:4711 — w tej postaci niektóre load balancery zapisują go w X-Forwarded-For (między innymi Azure Application Gateway). Gdy adres klienta pochodzi z takiego wpisu, jego port staje się REMOTE_PORT.

Przejście zatrzymuje się na wpisie bez adresu lub takim, którego nie da się sparsować jako adresu IP (pusty element, unknown, zaciemniony identyfikator RFC 7239), oraz na linii nagłówka, której OxPHP nie potrafi odczytać jako tekstu (na przykład zawierającej bajt spoza ASCII). Nic na lewo od tego punktu nie jest używane, bo ta część łańcucha może pochodzić wyłącznie od klienta. Adresem klienta jest skrajnie prawy niezaufany wpis na prawo od tego punktu. Jeśli wszystkie wpisy tam są zaufane, jest nim skrajnie lewy z nich; jeśli nie ma tam żadnego wpisu, adres nie jest przepisywany i pozostaje adresem łączącego się peera, łącznie z portem.

text
X-Forwarded-For: 198.51.100.9, unknown, 10.0.0.5 TCP peer: 10.0.0.1 (trusted) Walk right-to-left: 10.0.0.5 → trusted → skip unknown → does not parse → stop 198.51.100.9 → never reached Client IP: 10.0.0.5 (every entry right of the stop is trusted → the leftmost of them)

Ze słowem kluczowym cloudflare żądanie, którego łańcuch przekazywania pokazuje, że przyszło z węzła brzegowego Cloudflare, bierze zamiast tego adres klienta z nagłówka CF-Connecting-IP. Zobacz Za CDN i load balancerem platformy.

Co się zmienia

Gdy TRUSTED_PROXIES jest skonfigurowane, a łączący się adres IP jest zaufany:

Komponent Bez zaufanych proxy Z zaufanymi proxy
$_SERVER['REMOTE_ADDR'] IP proxy Rzeczywisty IP klienta; IP proxy, gdy nagłówki przekierowania nie dają żadnego adresu
$_SERVER['REMOTE_PORT'] Port źródłowy proxy Port klienta z wpisu ip:port w Forwarded lub X-Forwarded-For, w przeciwnym razie 0; port peera, gdy adres nie jest przepisywany
$_SERVER['HTTPS'] Na podstawie konfiguracji TLS OxPHP Z Forwarded: proto= lub X-Forwarded-Proto
$_SERVER['REQUEST_SCHEME'] http lub https z TLS Z przekazanego protokołu
$_SERVER['SERVER_NAME'] Z nagłówka Host Z Forwarded: host= lub X-Forwarded-Host
$_SERVER['SERVER_PORT'] Z nagłówka Host Z X-Forwarded-Port, w przeciwnym razie port z X-Forwarded-Host / Forwarded: host=, w przeciwnym razie 443/80
Ograniczanie liczby żądań Na IP proxy Na IP klienta
Dziennik dostępu IP proxy Rzeczywisty IP klienta

Gdy adres klienta jest przepisywany, REMOTE_PORT jest portem źródłowym klienta, jeśli wpis, z którego pochodzi adres, go zawiera — węzeł Forwarded: for="ip:port" zgodny z RFC 7239 albo wpis ip:port w X-Forwarded-For — a w przeciwnym razie 0. Portu nie da się zrekonstruować, więc jest zerowany zamiast zgadywany. Adres wzięty z CF-Connecting-IP również nie ma portu, więc REMOTE_PORT wynosi wtedy także 0. Gdy nagłówki nie dają adresu klienta i adres nie jest przepisywany, jak opisano w sekcji Wydobywanie adresu IP klienta, REMOTE_PORT pozostaje portem łączącego się peera.

Sieci private

Skrót private obejmuje:

Sieć Opis
10.0.0.0/8 Prywatna klasy A
172.16.0.0/12 Prywatna klasy B
192.168.0.0/16 Prywatna klasy C
127.0.0.0/8 Loopback
169.254.0.0/16 Link-local
::1/128 IPv6 loopback
fc00::/7 IPv6 unique local
fe80::/10 IPv6 link-local

Współdzielona przestrzeń adresowa (100.64.0.0/10, RFC 6598) nie należy do private. Jeśli Twój load balancer łączy się z tego zakresu, wpisz go obok słowa kluczowego: TRUSTED_PROXIES="private,100.64.0.0/10".

Sieci cloudflare

Słowo kluczowe cloudflare dodaje zakresy węzłów brzegowych, które Cloudflare publikuje pod adresem cloudflare.com/ips: 15 zakresów IPv4 i 7 zakresów IPv6, według stanu opublikowanego 2026-10-05. Lista jest wkompilowana w OxPHP i zmienia się tylko wraz z wydaniem OxPHP. Gdy lista Cloudflare zmieni się wcześniej:

  • Nowy zakres. Wpisz go obok słowa kluczowego: TRUSTED_PROXIES="private,cloudflare,<new range>". Wpisany zakres liczy się jako jedno z Twoich własnych proxy, a nie jako węzeł brzegowy Cloudflare, więc żądania przechodzące przez niego biorą adres według reguły rightmost-non-trusted, a nie z CF-Connecting-IP, dopóki któreś wydanie nie doda tego zakresu do słowa kluczowego.
  • Wycofany zakres. Nie da się go odjąć od słowa kluczowego. Aby pozbyć się go, zanim zrobi to wydanie OxPHP, wpisz zakresy, którym nadal ufasz, jako CIDR-y zamiast używać słowa kluczowego. Oznacza to też rezygnację z odczytywania CF-Connecting-IP, które jest powiązane ze słowem kluczowym.

Za CDN i load balancerem platformy

Typowe wdrożenie umieszcza CDN przed load balancerem platformy hostingowej:

text
client → Cloudflare → load balancer → OxPHP

Przy TRUSTED_PROXIES=private zaufany jest tylko load balancer. Skrajnie prawym niezaufanym adresem w X-Forwarded-For jest wtedy węzeł brzegowy Cloudflare, który połączył się z load balancerem, i każde żądanie wygląda na pochodzące z Cloudflare — w REMOTE_ADDR, w dzienniku dostępu, w ograniczaniu liczby żądań i w atrybucie spana client.address. Zaufaj obu przeskokom:

bash
TRUSTED_PROXIES="private,cloudflare"

Jeśli load balancer łączy się z adresu spoza zakresów private, wpisz również jego zakres: TRUSTED_PROXIES="private,100.64.0.0/10,cloudflare".

Ze słowem kluczowym cloudflare OxPHP ustala adres klienta w trzech krokach:

  1. 1
    Przejście przez własne proxy. Zaczynając od łączącego się peera, OxPHP przechodzi w lewo przez łańcuch przekazywania (Forwarded, jeśli jest obecny, w przeciwnym razie X-Forwarded-For), mijając Twoje własne proxy: zakresy private i wpisane przez Ciebie CIDR-y. Adres należący do zakresów Cloudflare liczy się jako Cloudflare, nawet jeśli go wpisałeś.
  2. 2
    Szukanie przeskoku przez Cloudflare. Jeśli pierwszy przeskok, który nie jest jednym z Twoich własnych proxy, jest adresem Cloudflare, żądanie przyszło przez Cloudflare, a adresem klienta jest nagłówek CF-Connecting-IP. Nagłówek musi wystąpić dokładnie raz i zawierać poprawny adres IP.
  3. 3
    W przeciwnym razie rightmost-non-trusted. Jeśli żądanie nie przyszło przez Cloudflare albo CF-Connecting-IP jest nieobecny, powtórzony lub błędny, stosowana jest reguła rightmost-non-trusted, przy czym zakresy Cloudflare liczą się jako zaufane.

Przeskok, na którym przejście się zatrzymuje, to łączący się peer albo adres zapisany przez jedno z Twoich własnych proxy. Klient, który łączy się z load balancerem bezpośrednio, nie może więc sprawić, by OxPHP odczytał CF-Connecting-IP wysłany przez niego samego: load balancer zapisuje w tym miejscu własny adres klienta, a adres Cloudflare, który klient wpisał dalej w lewo, nigdy nie zostanie osiągnięty. Podobnie jak reguła rightmost-non-trusted, opiera się to na tym, że Twoje proxy utrzymują nagłówek, który czyta OxPHP — dopisują adres, który się z nimi połączył, zamiast przepuszczać wartość klienta bez zmian.

Usuń nagłówek Forwarded wysłany przez klienta

Twoje proxy muszą utrzymywać także Forwarded. OxPHP czyta go w pierwszej kolejności, przed X-Forwarded-For, a Cloudflare przekazuje go dalej w takiej postaci, w jakiej wysłał go odwiedzający, bo nie jest to jeden z nagłówków ustawianych przez Cloudflare. Load balancer, który utrzymuje tylko X-Forwarded-For, musi więc usuwać Forwarded z żądania. Jeśli przepuszcza ten nagłówek, każdy klient — przez Cloudflare czy nie — wybiera adres, który widzi OxPHP, ze słowem kluczowym cloudflare lub bez niego.

CF-Connecting-IP nie jest odczytywany także wtedy, gdy przejście zatrzyma się, zanim dotrze do adresu Cloudflare — na wpisie bez adresu lub takim, którego nie da się sparsować, albo na linii, której OxPHP nie potrafi odczytać jako tekstu, jak opisano w sekcji Wydobywanie adresu IP klienta. Na wpis, który jedno z Twoich proxy umieszcza w osobnej linii, nie wpływa nieczytelna linia wysłana wcześniej przez klienta. Wpis, który proxy zapisuje w tej samej linii co tekst wysłany przez klienta, przepada razem z tą linią: przejście zatrzymuje się tam, a adres pochodzi z tego, co Twoje proxy zapisały na prawo od tej linii, albo pozostaje adresem łączącego się peera — nigdy z niczego, co wysłał klient.

Cloudflare Workers

Cloudflare dopisuje do X-Forwarded-For adres tego, kto się z nim połączył, więc dla zwykłego odwiedzającego oba nagłówki wskazują tego samego klienta. Mogą się jednak różnić dla żądań, które Cloudflare Workers wysyłają do Twojego serwera źródłowego (origin), bo one również wychodzą z adresów Cloudflare, niezależnie od tego, które konto jest właścicielem Workera. Dokumentacja nagłówków HTTP Cloudflare nie mówi, co takie żądanie może nieść w X-Forwarded-For. O CF-Connecting-IP mówi: Worker może wybrać jego wartość tylko dla żądania do nazwy hosta we własnej strefie; dla nazwy hosta w innej strefie Cloudflare nagłówek zawiera stały adres 2a06:98c0:3600::103, a dla nazwy hosta spoza Cloudflare jest to adres klienta, którego Worker nie może zmienić.

Zaufanie zakresom Cloudflare nadal oznacza zaufanie wszystkiemu, co wychodzi z sieci Cloudflare, a nie tylko Twojej strefie. Jeśli adres klienta wpływa na decyzję dotyczącą bezpieczeństwa, spraw, by serwer źródłowy przyjmował ruch wyłącznie z Twojej strefy, za pomocą środków, jakie oferuje Twoja platforma.

Bezpieczeństwo

  • Bezpieczne ustawienie domyślne — bez TRUSTED_PROXIES żadne nagłówki przekierowania nie są przetwarzane
  • Walidacja CIDR — nieprawidłowe wartości w TRUSTED_PROXIES powodują błąd przy starcie
  • Odporność na podszywanie — algorytm rightmost-non-trusted ignoruje wartości doklejone przez atakującego
  • Żądania z niezaufanych adresów IP mają swoje nagłówki przekierowania całkowicie ignorowane

Prompty dla Twojego agenta

Te prompty zakładają agenta z podłączonym serwerem MCP dokumentacji OxPHP — sam przeczyta strony, których potrzebuje.

prompt
Skonfiguruj zaufane proxy dla mojego wdrożenia OxPHP. Przeczytaj stronę `security/trusted-proxies` przez serwer MCP dokumentacji OxPHP. Ustal na podstawie moich plików infrastrukturalnych, co stoi przed aplikacją, a potem podaj mi dokładną konfigurację i powiedz mi, co każda wartość dopuszcza oraz co pozwoliłaby klientowi podrobić, gdyby była ustawiona źle.

Zobacz też

Znalazłeś błąd? Zgłoś go →