Довірені проксі
Коли OxPHP працює за зворотним проксі (Kubernetes Ingress, Cloudflare, AWS ALB, nginx), кожен запит надходить з IP-адреси проксі. Без налаштування довірених проксі обмеження частоти запитів, журнал доступу та $_SERVER['REMOTE_ADDR'] бачать IP-адресу проксі замість справжнього клієнта.
Налаштування
# 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"Кожен елемент списку, розділеного комами, — це CIDR, окрема IP-адреса (один хост) або одне з ключових слів private і cloudflare у будь-якому регістрі. Елемент, що не є жодним із них, спричиняє помилку під час запуску.
Якщо змінну не задано, OxPHP ігнорує всі заголовки переадресації. Це безпечне типове значення.
Як це працює
Коли запит надходить із довіреної IP-адреси, OxPHP перевіряє заголовки переадресації в порядку пріоритету:
Forwarded(RFC 7239) — стандартизований заголовокX-Forwarded-For/X-Forwarded-Proto/X-Forwarded-Host/X-Forwarded-Port— фактичний стандарт як запасний варіант
Якщо присутній заголовок Forwarded, заголовки X-Forwarded-* ігноруються.
Визначення IP-адреси клієнта
OxPHP використовує алгоритм «крайня права недовірена адреса» — той самий підхід, що й nginx (real_ip_recursive on), Caddy, Traefik та Apache:
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Це запобігає підробці через значення, додані на початок. Зловмисник може дописати ліворуч фальшиві IP-адреси, але крайню праву недовірену адресу встановив останній довірений проксі в ланцюжку.
Елемент може містити порт: 203.0.113.50:4711 або [2001:db8::1]:4711 — у такій формі деякі балансувальники навантаження (зокрема Azure Application Gateway) записують адреси в X-Forwarded-For. Коли адреса клієнта береться з такого елемента, його порт стає REMOTE_PORT.
Обхід зупиняється на елементі без адреси або з адресою, яку не вдається розібрати як IP-адресу (порожній елемент, unknown, обфускований ідентифікатор RFC 7239), а також на рядку заголовка, який OxPHP не може прочитати як текст (наприклад, з байтом поза ASCII). Нічого ліворуч від цієї точки не використовується, бо ця частина ланцюжка може бути лише тим, що надіслав клієнт. Адреса клієнта — це крайня права недовірена адреса праворуч від цієї точки. Якщо всі елементи там довірені, нею стає крайній лівий із них; якщо там немає жодного елемента, адреса не переписується й лишається адресою вузла, що встановив з’єднання, разом із портом.
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)З ключовим словом cloudflare запит, чий ланцюжок переадресації показує, що він надійшов із периферійного вузла Cloudflare, натомість отримує адресу клієнта із заголовка CF-Connecting-IP. Див. За CDN і балансувальником навантаження платформи.
Що змінюється
Коли TRUSTED_PROXIES налаштовано, а IP-адреса, з якої встановлено з’єднання, є довіреною:
| Компонент | Без довірених проксі | З довіреними проксі |
|---|---|---|
$_SERVER['REMOTE_ADDR'] |
IP-адреса проксі | Справжня IP-адреса клієнта; IP-адреса проксі, якщо заголовки переадресації не дають адреси |
$_SERVER['REMOTE_PORT'] |
Вихідний порт проксі | Порт клієнта з елемента ip:port у Forwarded або X-Forwarded-For, інакше 0; порт вузла, що встановив з’єднання, якщо адреса не переписується |
$_SERVER['HTTPS'] |
Залежно від налаштувань TLS в OxPHP | З Forwarded: proto= або X-Forwarded-Proto |
$_SERVER['REQUEST_SCHEME'] |
http або https залежно від TLS |
З переданого протоколу |
$_SERVER['SERVER_NAME'] |
Із заголовка Host |
З Forwarded: host= або X-Forwarded-Host |
$_SERVER['SERVER_PORT'] |
Із заголовка Host |
З X-Forwarded-Port, інакше порт із X-Forwarded-Host / Forwarded: host=, інакше 443/80 |
| Обмеження частоти запитів | За IP-адресою проксі | За IP-адресою клієнта |
| Журнал доступу | IP-адреса проксі | Справжня IP-адреса клієнта |
Коли адресу клієнта переписано, REMOTE_PORT — це вихідний порт клієнта, якщо елемент, з якого взято адресу, його містить (вузол RFC 7239 Forwarded: for="ip:port" або елемент ip:port у X-Forwarded-For), і 0 в іншому разі. Відновити порт неможливо, тож замість того, щоб його вгадувати, його обнуляють. Адреса, взята з CF-Connecting-IP, теж не має порту, тож і тоді REMOTE_PORT дорівнює 0. Коли заголовки не дають адреси клієнта й адреса не переписується, як описано в розділі Визначення IP-адреси клієнта, REMOTE_PORT лишається портом вузла, що встановив з’єднання.
Мережі private
Скорочення private охоплює:
| Мережа | Опис |
|---|---|
10.0.0.0/8 |
Приватна мережа класу A |
172.16.0.0/12 |
Приватна мережа класу B |
192.168.0.0/16 |
Приватна мережа класу C |
127.0.0.0/8 |
Loopback |
169.254.0.0/16 |
Link-local |
::1/128 |
Loopback IPv6 |
fc00::/7 |
Унікальні локальні адреси IPv6 |
fe80::/10 |
Link-local IPv6 |
Спільний адресний простір (100.64.0.0/10, RFC 6598) не входить до private. Якщо ваш балансувальник навантаження підключається з нього, додайте його до списку поруч із ключовим словом: TRUSTED_PROXIES="private,100.64.0.0/10".
Мережі cloudflare
Ключове слово cloudflare додає периферійні діапазони, які Cloudflare публікує на cloudflare.com/ips: 15 діапазонів IPv4 і 7 діапазонів IPv6 станом на публікацію 2026-10-05. Список вкомпільовано в OxPHP, і він змінюється лише з релізом OxPHP. Коли список Cloudflare змінюється раніше:
- Новий діапазон. Додайте його до списку поруч із ключовим словом:
TRUSTED_PROXIES="private,cloudflare,<new range>". Доданий так діапазон вважається одним із ваших власних проксі, а не периферійним вузлом Cloudflare, тож запити через нього отримують адресу за правилом крайньої правої недовіреної адреси, а не зCF-Connecting-IP, доки реліз не додасть цей діапазон до ключового слова. - Відкликаний діапазон. Його неможливо відняти від ключового слова. Щоб прибрати його раніше, ніж це зробить реліз OxPHP, перелічіть діапазони, яким ви й далі довіряєте, як CIDR замість ключового слова. Так ви також відмовляєтеся від читання
CF-Connecting-IP, яке прив’язане до ключового слова.
За CDN і балансувальником навантаження платформи
Поширене розгортання ставить CDN перед балансувальником навантаження хостинг-платформи:
client → Cloudflare → load balancer → OxPHPЗ TRUSTED_PROXIES=private довіреним є лише балансувальник навантаження. Крайньою правою недовіреною адресою в X-Forwarded-For тоді стає периферійний вузол Cloudflare, який підключився до балансувальника, і кожен запит виглядає так, ніби надходить від Cloudflare, — у REMOTE_ADDR, журналі доступу, обмеженні частоти запитів і атрибуті спану client.address. Довіряйте обом переходам:
TRUSTED_PROXIES="private,cloudflare"Якщо балансувальник навантаження підключається з адреси поза діапазонами private, додайте до списку і його діапазон: TRUSTED_PROXIES="private,100.64.0.0/10,cloudflare".
З ключовим словом cloudflare OxPHP визначає адресу клієнта у три кроки:
- 1Пройти повз власні проксі. Починаючи з вузла, що встановив з’єднання, OxPHP іде ліворуч ланцюжком переадресації (
Forwarded, якщо він є, інакшеX-Forwarded-For) повз ваші власні проксі: діапазониprivateі перелічені вами CIDR. Адреса в діапазонах Cloudflare вважається адресою Cloudflare, навіть якщо ви її перелічили. - 2Знайти перехід через Cloudflare. Якщо перший перехід, що не є одним із ваших власних проксі, — це адреса Cloudflare, запит пройшов через Cloudflare, і адресою клієнта є заголовок
CF-Connecting-IP. Заголовок має бути присутній рівно один раз і містити коректну IP-адресу. - 3Інакше — крайня права недовірена адреса. Якщо запит не проходив через Cloudflare або
CF-Connecting-IPвідсутній, повторюється чи некоректний, застосовується правило крайньої правої недовіреної адреси, а діапазони Cloudflare вважаються довіреними.
Перехід, на якому зупиняється обхід, — це вузол, що встановив з’єднання, або адреса, яку записав один із ваших власних проксі. Тому клієнт, що звертається до балансувальника навантаження напряму, не може змусити OxPHP прочитати CF-Connecting-IP, який він надіслав сам: балансувальник записує туди власну адресу клієнта, а до адреси Cloudflare, яку клієнт дописав лівіше, обхід ніколи не доходить. Як і правило крайньої правої недовіреної адреси, це спирається на те, що ваші проксі підтримують заголовок, який читає OxPHP, — дописують адресу, що до них підключилася, а не передають значення клієнта без змін.
Ваші проксі мають підтримувати й Forwarded. OxPHP читає його в пріоритеті перед X-Forwarded-For, а Cloudflare передає його далі в тому вигляді, в якому його надіслав відвідувач, бо це не один із заголовків, які встановлює Cloudflare. Тому балансувальник навантаження, що підтримує лише X-Forwarded-For, має видаляти Forwarded із запиту. Якщо він пропускає цей заголовок, будь-який клієнт — через Cloudflare чи ні — сам обирає адресу, яку бачить OxPHP, з ключовим словом cloudflare чи без нього.
CF-Connecting-IP також не читається, коли обхід зупиняється, не дійшовши до адреси Cloudflare, — на елементі без адреси або з адресою, яку не вдається розібрати, чи на рядку, який OxPHP не може прочитати як текст, як описано в розділі Визначення IP-адреси клієнта. На запис, який один із ваших проксі додає окремим рядком, не впливає нечитабельний рядок, що його клієнт надіслав раніше. Запис, який проксі дописує в той самий рядок, що й текст, надісланий клієнтом, втрачається разом із цим рядком: обхід зупиняється там, і адреса береться з того, що ваші проксі записали праворуч від цього рядка, або лишається адресою вузла, що встановив з’єднання, — але ніколи з того, що надіслав клієнт.
Cloudflare дописує в X-Forwarded-For адресу того, хто до нього підключився, тож для звичайного відвідувача обидва заголовки називають того самого клієнта. Вони можуть розходитися для запитів, які Cloudflare Workers надсилають до вашого origin-сервера: такі запити теж виходять з адрес Cloudflare, хоч би який обліковий запис володів Worker. Довідник HTTP-заголовків Cloudflare не уточнює, що такий запит може містити в X-Forwarded-For. Щодо CF-Connecting-IP уточнює: Worker може обрати значення лише для запиту до імені хоста у власній зоні; для імені хоста в іншій зоні Cloudflare заголовок містить фіксовану адресу 2a06:98c0:3600::103, а для імені хоста поза Cloudflare — адресу клієнта, яку Worker змінити не може.
Довіра до діапазонів Cloudflare все одно означає довіру до всього, що виходить із мережі Cloudflare, а не лише з вашої зони. Якщо адреса клієнта впливає на рішення щодо безпеки, налаштуйте origin-сервер так, щоб він приймав трафік лише з вашої зони, у будь-який спосіб, який пропонує ваша платформа.
Безпека
- Безпечне типове значення — без
TRUSTED_PROXIESжоден заголовок переадресації не обробляється - Перевірка CIDR — некоректні значення в
TRUSTED_PROXIESспричиняють помилку під час запуску - Стійкість до підробки — алгоритм «крайня права недовірена адреса» ігнорує значення, додані зловмисником на початок
- Заголовки переадресації в запитах із недовірених IP-адрес повністю ігноруються
Промпти для вашого агента
Ці промпти розраховані на агента з підключеним MCP-сервером документації OxPHP — потрібні сторінки він прочитає сам.
Налаштуй довірені проксі для мого розгортання OxPHP. Прочитай сторінку `security/trusted-proxies` через MCP-сервер документації OxPHP.
З моїх файлів інфраструктури визнач, що стоїть перед застосунком, потім дай мені точну конфігурацію й поясни, що допускає кожне значення і що воно дозволило б клієнтові підробити, якщо я помилюся.Див. також
- Обмеження частоти запитів — обмеження за IP-адресою використовує визначену IP-адресу клієнта
- Журнал доступу — поле
remote_ipпоказує визначену IP-адресу клієнта - Довідник із налаштувань — усі змінні середовища