x forwarded for что это
Русские Блоги
X-Forwarded-For, X-Real-IP в заголовке HTTP-запроса
X-Forwarded-For
При использовании nginx в качестве обратного прокси мыЗапишите весь процесс агентства, Мы часто делаем следующую конфигурацию в файле конфигурации:
Красная часть предназначена для записи конфигурации процесса прокси. Чтобы добавить информацию о прокси в заголовок http, мы можем рассматривать X-Forwarded-For как заголовок расширения http, и его формат обычно:
X-Forwarded-For:192.168.247.1, 192.168.247.131, 192.168.247.132
Сделай тест
1. Проверим ситуацию, когда запрос проходит через трехуровневый прокси, тестируем выделение оборудования:
2. Конфигурация тестовой среды:
3. файл конфигурацииnginx
4. В соответствии с приведенной выше конфигурацией введите в браузере win10: «http://test.proxy.com», чтобы просмотреть журнал облачного сервера. Результат печати будет следующим:
Резюме:
5. ХотяX-Forwarded-ForЕго можно подделать, но он по-прежнему полезен для нас.Например, мы можем перехватить с прокси-сервера proxy01, чтобы мы могли напрямую игнорировать поддельный IP-адрес.
X-Real-IP
Давайте посмотрим, как получить реальный IP-адрес клиента при наличии многоуровневых агентов.
1. Если мы установим только X-Real-IP в proxy01
2. Если мы установим только X-Real-IP в proxy02
3. Если мы установим только X-Real-IP в proxy03
4. Установите X-Real-IP для всех агентов.
5. Приближается обсессивно-компульсивное расстройство, попробуйте другое, используя только proxy01 и proxy02.
Если кто-то выдает себя за другое лицоX-Real-IPКакой?
X-Forwarded-For и его маскировка
X-Forwarded-For (XFF) — HTTP заголовок, ставший де-факто стандартом для выявления происхождения IP-адреса клиента. Прокси-сервера обычно передают этот заголовок на Web-сервер для идентификации конкретного пользователя, чтобы облегчить выявление злоупотреблений. [1]
Содержание
[править] Чекюзинг
Это поле видят чекъюзеры, что позволяет им идентифицировать истинный IP-адрес клиента при использовании им прокси.
[править] Анонимные прокси-серверы и анонимайзеры
[править] Маскировка X-Forwarded-For (XFF)
Для маскировки XFF можно использовать расширение для FireFox X-Forwarded-For Spoofer (Firefox 1.5 — 3.0).
Для использования с более поздними версиями FireFox (3.5) некто Angstorm рекомендует [5] переименовать в zip, распаковать, изменить 3.0 на 3.5 в файле «install.rdf», упаковать, переименовать назад в xpi и установить в FF 3.5 (проверено, работает — сам файлик x-forwarded-for_spoofer-1.0.2-fx.xpi пришлось однако выкачивать через IE).
В меню «Инструменты» FireFox появляется пункт «X-Forwarded-For Spoofer». Там можно выставить какое-нибудь значение (например, zzz). Полное сокрытие адреса при этом не получается:
Как можно заметить, цепочка значений наращивается через запятую, но старые значения при этом не замещаются. Однако, программное обеспечение, которое не анализирует всю цепочку, а использует самое первое значение в списке, это может ввести в заблуждение.
На сайтах с MediaWiki применять этот метод для хождения через транспарентные прокси не особо осмыслено, так как если прокси не входит в вайт-лист, его X-Forwarded-For просто игнорируется (смотри XFF project).
С актуальными версиями Firefox работает расширение Dolus (проверено с Firefox 51).
[править] Как посмотреть свой XFF
Используйте специализированный сайт, например: http://foxtools.ru/Http
REMOTE_ADDR vs HTTP_X_FORWARDED_FOR
Давеча был свидетелем одного интересного спора о том как же действительно нужно определять IP адрес конечного пользователя из скриптов PHP.
Собственно, каждое слово сабжа отображает действительную ситуацию. Это был религиозный спор, обострённый весенней замечательной погодой, в котором, я считаю, не оказалось правых и не правых, но который побудил меня к мини-исследованию и, к моему счастью, поставил точку в понимании этого конфессионального но по факту очень простого вопроса.
Для тех, кто как и я сомневался был уверен, что во всём разобрался, но боялся спросить лень было разбираться в мелочах — под кат.
Предыстория
Занимаясь разработкой VOD сервиса для Samsung SmartTV платформы нам непременно нужно знать страну пользователя, чтобы вдруг нечаянно не показать счастливому пользователю фильм там, где запрещает правообладатель… А ведь за нарушение данного условия договора идут не детские штрафы в тысячах долларов (при чем за каждый факт такой оплошности).
[Вопрос, как заметили в комментариях, Юридический, и мошенничество возможно, но статья даже не о том как постараться предотвратить такие мошенничества, а о том как правильно подружить php и nginx]
На сервере имеем следующее: php-fpm+nginx
И всё работало! Почти год… пока не случилось кое-что неожиданное. Естественно неожиданное для этого кода…
Как запутать php или цепочка прокси(всё ещё часть предыстории)
Всё сломалось! А случилось это когда нам пришлось прикручивать одну из платёжных систем и весь этот код рухнул от того, что в HTTP_X_FORWARDED_FOR пришёл не один адрес, а список адресов через запятую (что строго говоря законно, допустимо, и даже не регламентировано в доке по php )
И никто бы ничего не заметил, если бы HTTP_X_REAL_IP или HTTP_CLIENT_IP(которые тоже не регламентирован докой) содержали искомый IP, но увы они были пусты 🙁
«Ну ладно» — подумали мы(теперь я был уже не один) перепишем всё и попросим админов запихивать пользовательский IP в переменную REMOTE_ADDR:
И всё работало! Почти месяц… пока не случилось кое-что неожиданное. Естественно неожиданное для этого кода…
Весенний спор крутых мужиков(это не ирония — они крутые)
Всё сломалось! А случилось это потому, что нам нужно было обновить nginx. И мы обратились к профессионалам в этом деле — к нашим админам.
А те в свою очередь решили обновить и конфиг избавившись от нашего «костыля/не костыля» (пока мы этого не поняли) с пробросом в REMOTE_ADDR.
REMOTE_ADDR оставили без изменения т.е. там теперь светилось что-то типа «127.0.0.1»
в HTTP_X_FORWARDED_FOR прокинули IP пользователя (который между делом с лёгкостью удалось переопределить отправкой из браузера заголовка `x-forwarded-for: 999.999.999.999`)
И тут понеслось — Р=Разраб, А=Админ:
А: у вас всё сломалось, и поскольку мы имеем nginx-прокси то нужный вам адрес лежит в HTTP_X_FORWARDED_FOR а в REMOTE_ADDR будет лежать реальный IP сдресс клиента к php-fpm (т.е. 127.0.0.1)
Р: но мы не можем верить HTTP_X_FORWARDED_FOR, ведь это переменная, которую с лёгкостью можно переопределить через заголовок к серверу, ссылаясь на давольно интересную статью
А: нет, мы сделаем так что в ней будет лежать реальный IP конечного пользователя, а в REMOTE_ADDR реальный адрес клиента к php
Р: тогда мы не проследим последовательность проксей, и всё равно для универсализации на другом сервере (скажем без прокси) эти конфиги могут быть не правдивыми пихайте всё в REMOTE_ADDR который в любом случае будет работать.
… это кратко и без матов…
По итогу то конечно всё завелось… и остановились на прозрачном проксировании, когда php думает, что к нему подключаются напрямую клиенты безо всяких проксей и все переменные(точнее одна на которую мы обращаем внимание) в нужном нам состоянии.
Однако не хватает фэншуя в этом деле и по факту у нас ведь есть прокся а может и не одна.
Кто виноват из них кто прав
Судить не нам, но никто!
Если мы имеем действительно кучу клиентов напрямую к php, или прозрачное проксирование то всё просто — юзай REMOTE_ADDR на здоровье и наслаждайся.
Но как быть с фэншуем и где что должно лежать, если мы используем нормальное проксирование и хотим чтобы об этом знал PHP?
Рецепт… но не панацея:
Казалось бы ну в чем проблема парсить эту переменную и доставать оттуда последнийэлемент. Но в нашем случае настройки не были до конца корректными и весьHTTP_X_FORWARDED_FOR заменялся заголовком от браузера x-forwarded-for, а должен был приклеивать к нему реальный IP непосредственного пользователя.
Для удобства можно использовать специальный модуль для nginx который нивелирует проблемы определения каскадного и не каскадного проксирования, но он по умолчанию «в стандартных сборках центоса, дебика и федоры nginx идет, почему-то без параметра —with-http_realip_module»(с)Админ, а так же для него должен быть корректно сформированна цепочка в HTTP_X_FORWARDED_FOR и настроены адреса доверенных прокси серверов от которых мы можем брать последний элемент из HTTP_X_FORWARDED_FOR
В заключении
Есть несколько вариантов проксирования для php+nginx
PS
Позже мы наведём фэншуй в настройках и избавимся от прозрачного проксирования, а так же напишем универсальную функцию определения IP для обоих случаев проксирования.
PPS
Ради фана кому интересно: если кто-то в комментариях напишет эту функцию и конфиг nginx за нас и мы её будем использовать, то под честное слово, тот получит 100р на телефон.
Но эта функция и конфиг должны быть во истину православными и учитывать всё 🙂 все зацепки есть в статье.
Главное — дзен: не торопитесь — вдруг первые напишут с ошибками и вы их учтёте, торопитесь — вдруг первый правильный ответ будет до Вас.
UDP:
Своя реализация:
Читайте также
Настройка HTTP/2 в Nginx может показаться тривиальной задачей, однако есть ряд потенциальных проблем, с которыми вы можете столкнуться. В данной…
Все больше и больше компаний начинают использовать HTTP/2 для повышения производительности своих сайтов. Настроить HTTP/2 довольно просто, но что делать,…
Будучи студентом третьего курса, я выбрал тему для курсовой роботы: «Графовые базы данных на примере Neo4j». Так как до того…
Такие разные заголовки! Изучаем HTTP-взаимодействие
Содержание статьи
Большинство из нас многократно слышали про способность сайтов узнавать информацию о посетителе (и всевозможные предупреждения по этому поводу), которую невозможно узнать из IP-адреса. Это такие «личные» данные, как операционная система, используемый браузер, язык системы. Кто же так жестоко палит нас? И как можно это использовать в своих благих намерениях? Об этом и многом другом ты узнаешь, прочитав статью до конца.
Для начала приведу немного теории о том, чем мы пользуемся довольно давно. HTTP (HyperText Transfer Protocol – «протокол передачи гипертекста») – клиент-серверный протокол передачи данных, который служит для получения информации с веб-сайтов. Был предложен создателем всея WWW Тимом Бернерсом-Ли. Структура его проста: тип сообщения, заголовки, тело сообщения. Существуют RFC, стандартизирующие HTTP (последняя версия – 1.1), согласно которым клиент должен посылать серверу заголовки, содержащие ту самую специфическую информацию о системе и браузере. Обычному пользователю это полезно: сайт в зависимости от клиента может выдать специфическую верстку (пример – google.com) или показать информацию на нужном языке. Однако для хакера раскрытие такой информации может быть вредно или даже опасно.
Представим ситуацию: некий Иван зашел на сайт, посмотрел на него и решил взломать. Загрузил проверенные соксы, поставил красивый дефейс и через несколько часов/дней сидел в участке. Ведь несложно сопоставить данные взломщика с данными остальных посетителей и найти настоящий IP (очень редко встретишь сайт без логирования). Да, некоторые факторы не учтены, однако, вариант возможный.
Техническая реализация
Итак, нам необходимо подделывать заголовки, которые браузер шлет серверу. Как кросс-браузерное решение я бы предложил старый быстрый Proxomitron. Изначально он предназначен для удаления рекламы и полного управления содержимым страницы, так что замечательно подходит для наших целей. Работает как HTTP-прокси. С первого взгляда интерфейс Proxomitron’а не очень дружелюбен, однако разобраться в нем – дело нехитрое. Если нужно использовать только подделку заголовков – слева убираем все галки кроме второй. Жмем на «Headers» и редактируем правила подмены: сразу после установки – в списке куча правил, добавить свое можно, нажав на кнопку New. Чтобы задействовать фильтр, нужна галка в поле «out». Обязательно прочитай русский хелп к программе – там отлично все расписано.
Я пользуюсь Mozilla Firefox и предпочитаю вместо внешних программ использовать плагины. Tamper Data позволяет перехватывать запросы и редактировать заголовки в реальном времени – незаменимая вещь при ручной проверке. Все просто: в окне плагина жмем «Запустить перехват» и вмешиваемся, когда необходимо. Имеются пресеты и богатые возможности по изменению значений заголовков.
Для постоянной же подмены заголовков лучше использовать плагин Modify Headers. Сразу после установки необходимо открыть настройки и поставить галку на «Always on», дабы подмена происходила всегда. Настройка элементарная – открыть главное окно плагина и добавить правил. Первое поле – выбор действия («Add» – добавить, «Modify» – изменить, «Filter» – исключить из запроса), второе – название заголовка, третье – значение; в четвертом поле можно оставить записку. Правила можно двигать, включать и выключать.
Вектор поиска
Немного отвлечемся от темы и поразмыслим над тем, из чего будут состоять значения подделываемых заголовков. Все достаточно очевидно при использовании подмены только ради сокрытия своих данных: тут либо фильтрация, либо замена на аналогичные из других браузеров/систем. Совсем другое дело при поиске уязвимостей. Прежде всего, нужно определиться, какой тип брешей мы будем искать.
PHP-include не подходят, ибо файлы никогда не подключают в зависимости от заголовков. Хотя и есть возможные исключения, к примеру, инклуд файла в зависимости от языка. На практике не встречал.
Пассивные XSS основаны на том, что запрос будет делать непосредственно пользователь. Заставить жертву подменить заголовок едва ли удастся, именно поэтому этот тип нам не подходит. Единственная возможность использовать найденные подменой заголовков пассивные XSS – это если на страницу пишется Referer (ссылающаяся страница), да не простой, а дополнительно декодированный (избавленный от %xx). Тогда можно скриптом перенаправить жертву на себя с нужным параметром и после – на уязвимую страницу, так что параметр запишется в месте Referer’а. Сработает в идеальных условиях, на практике также не встречал.
Активные XSS подходят. Смысл в том, чтобы веб-приложение занесло в базу наш заголовок, а после показало администратору, естественно, не обработав.
SQL-инъекции подходят. Это самый простой тип, достаточно, как и обычно, подставлять кавычку.
PHP-исполнение кода очень редко встречается вообще, а с участием заголовков – еще реже. Однако бывает. Тут преимущество нашего метода в том, что GET и POST данным менее доверяют.
Итак, теперь необходимо составить строку, которая позволяла бы определить наличие уязвимости. Кавычка обязательна. Далее необходимо выйти из возможных тегов: простейший способ сделать это символами «>. И последнее – алерт, дабы не проспать. В итоге у меня вышло ‘»>. Ставить на обнаружение исполнения кода я не стал; если желаешь, добавь, например, чтобы вызвать ошибку и заметить уязвимость. Также можно добавить в конец обратный слеш (пытаясь экранировать закрывающую кавычку), бывают случаи с фильтрацией кавычек, бывают без нее. Считаешь, что строка слишком длинная и может обрезаться? Замени “document.cookie” на «1». Тут главное – приложить фантазию и создать свой идеальной вектор поиска уязвимостей.
Интересные заголовки
Расскажу о наиболее интересных заголовках, с которыми обязательно нужно поиграться при пентесте сайта.
User-Agent
Главный враг шпиона. Больше всех выдает информации о посетителе: браузер, его версию и язык, движок браузера, версию движка, операционную систему. Данные могут быть написаны как угодно, однако примерный формат есть:
Браузер/Версия (Платформа; Шифрование; Система, Язык[; Что-нибудь еще]) [Дополнения].
В качестве платформы чаще всего можно увидеть X11 или Windows, иногда туда прямиком помещают систему, убирая соответствующий заголовок после. «Шифрование» может принимать три значения: “N” (None) – отсутствует, “I” (International) – слабое шифрование ключом до 40 бит, “U” (USA) – сильное шифрование с ключом 128 бит. Сейчас все браузеры используют только сильное шифрование. После скобки добавляется различная информация вроде движка, плагинов, дополнений.
В качестве браузера для совместимости очень часто указывают Mozilla, а уже после информации дописывают реальное название. Это связано с тем, что издавна девелоперы должны были (или просто любили) делать сайты не в соответствии с принятыми стандартами Консорциума Всемирной паутины (World Wide Web Consortium, W3C), а под наиболее распространенные в данное время браузеры, что приводило к еще большему доминированию последних. И сейчас такая практика существует, однако с тем отличием, что популярным браузерам даны дополнительные возможности, связанные с использованием JavaScript’а (например, на распространенном форуме Invision Power Board, в ветке 2.3.x, посмотрите профиль участника с отфильтрованным заголовком и без). Поэтому советую в строку User-Agent’а в любом случае включать определение распространенного браузера.
Referer
Сообщает о странице, с которой пришел пользователь. Заголовок, сильно полезный веб-мастерам для отслеживания путей попадания на их сайты. Написание – ошибка от английского «Referrer» («перенаправляющий»). Большинство браузеров позволяет отключать передачу этого заголовка, однако при этом обычно возникают проблемы с файлообменниками и сайтами-архивами, которым очень жалко отдавать контент без показа рекламы, так что они позволяют скачивать только при наличии их сайта в реферере. Можно подменять ради просмотра отдельных элементов сайта – например, картинок – без загрузки страниц, где они размещены (при условии, что без подделки это сделать не удастся). При пентесте стоит учитывать, что часто в базу записывают URL не полностью, а лишь нужную его часть, поэтому стоит пробовать «http://evil», «http://example.com/evil» и т.д.
X-Forwarded-For
Accept-Language
Сообщает допустимые языки содержания и их приоритет, именно от него зависит язык отображения сайта. Обычно полностью регулируется настройками браузера. Как я уже говорил, теоретически возможен дырявый скрипт с подключением файла, где имя его – предпочитаемый язык. Подменять и тестировать в любом случае стоит. Обязательно напиши, если найдешь уязвимость, связанную с этим заголовком.
Accept-Charset
Сообщает допустимые кодировки и их приоритет. Не самый интересный заголовок, но стоит обратить на него внимание, ибо он может выдать твою систему простым «windows-1251».
X-Requested-With
Нестандартный заголовок, сообщает средство запроса. Используется при запросах из JavaScript без перезагрузки страницы. Соответственно полезен для имитации AJAX (Asynchronous Javascript and XML) запросов, для этого необходимо установить его в значение «XMLHttpRequest».
Authorization
Если серверу необходима авторизация пользователя, он об этом прямо сообщает, а браузер предлагает ввести логин и пароль. Именно в заголовке Authorization они передаются в виде «Basic base64(user:pass)». Такую авторизацию намного удобней брутить, чем те, которые располагаются непосредственно на странице (POST).
Cookie
Собственно, в этом заголовке посылаются (внезапно) куки. Для танкистов поясню: это информация, которую сайт сохраняет на компьютере клиента. Подмена данного заголовка полезна тогда, когда изменение кукисов невозможно другим образом.
Применение
Итак, практика. Я проводил исследование, в ходе которого некоторое время использовал «пассивное обнаружение уязвимостей». Суть в том, что достаточно однажды выставить замену заголовков, а после – лишь ловить алерты и исследовать бреши.
ЗаголовокЗначениеВключен
User-Agent Opera/10.60 Да
Referer Да
X-Forwarded-For Да
Accept-Language en,en-US;q=0.9 Нет
AuthorizationBasic MScyMzo0JzU2 Нет
X-Requested-WithXMLHttpRequest Нет
CookiePHPSESSID=!Нет
С первыми тремя, думаю, понятно. Если в ладах с английским, включи на постоянную подмену Accept-Language, дабы принимали за англичанина. Authorization уместно включать только при проверке конкретного сайта, ибо рискуете не понять, если где-нибудь действительно понадобится авторизация. Про применение заголовков X-Requested-With и Cookie я уже писал, однако поясню последний. В PHP довольно удобно хранить данные в сессиях: собственно данные – на сервере, у клиента – только идентификатор в куке «PHPSESSID» (название можно менять, но делают это, естественно, редко). Так вот, иногда этот идентификатор может состоять только из символов a-z, A-Z, 0-9 и ‘-,’, и при передаче чего-то иного вызывается ошибка, раскрывающая абсолютный путь:
Warning: session_start() [function.session-start]: The session id contains illegal characters, valid characters are a-z, A-Z, 0-9 and ‘-,’ in /var/www/data/www/login.php on line 2
Первое, на что я наткнулся – это поплывшая разметка. Да, действительно на многих сайтах происходил выход из какого-нибудь тега (бесполезный), и дальше образовывалась каша. Если ты решишь провести собственно исследование – будь готов. Еще одно: если чувствуешь, что что-то идет не так (например, не дают скачать файл, не показывают картинку во всю ширину, не работает перенаправление), выключай подмену Referer’а.
Никто не знает и не узнает, сколько алертов выловили админы, сколько они их увидели у себя в логах, сколько осталось незамеченными. Однако один случай обнаружения интересной активной XSS есть точно – гугловский сервис FeedBurner, который умеет обрабатывать RSS-фиды и логировать трафик сайта. Но последнее делал он не слишком качественно – не фильтровался Referer. Подробнее об этой уязвимости читай на raz0r.name/vulnerabilities/aktivnaya-xss-na-feedburner/ (wp.me/pft5J-4a) (не удивляйся, увидев алерт из-за XFF :)).
Довольно весело было заходить на всякие сайты с DLE (DataLife Engine), ибо популярный модуль DLE Referer Module не дружил (и не дружит) с экранированием плохих символов. Для убедительности советую пройтись по сайтам продавцов ICQ UIN’ов и увидеть много MySQL-ошибок, хотя картина уже не будет слишком печальной – я разослал владельцам сообщения об уязвимости, ведь неприятно, когда твои платежные данные и ссылки на оплату можно подменить.
Некоторое время назад на php.ru можно было наблюдать ошибки нефильтрации Referer’а и XFF. На данный момент уязвимость закрыта. Из ошибки с реферером:
MySQL Error = You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ‘»‘)’ at line 1
SQL = INSERT INTO oops_sessions (ID,UID,START,LAST,IPS,PAGES,PAGE,DATA,REFFER) VALUES (‘dpdu7rh90ehfsc62′,’0′,1238958331,1238958331,’xxx.xxx.xxx.xxx’,1,’/’,’a:1:
Еще один пример – cx75planet.ru. Уязвимы User-Agent и XFF. IPB показывает весь запрос. Кроме этих брешей, была замечена еще туча SQL-ошибок на сайтах всех мастей, большинство из которых просто имели самописные модули обработки информации о браузерах, рефах и т.д. Предоставляю тебе возможность найти их все :).
Подмена заголовков в PHP
Естественно, после ручного анализа SQL-уязвимости наступает работа автоматики. Подбор столбцов, полей, вынимание логинов, паролей и хешей – все уже давно делают скрипты. Однако большинство из них направлено на GET, POST или Cookie. Покажу, как можно получить страницу, посылая нужные заголовки. Предположим, у нас есть массив с такими заголовками и вызов функции request, которая должна возвращать страницу:
Есть несколько основных видов получения страницы из PHP (полные версии функций ищи на диске ][):
Сокет
Заголовки напишешь в любом случае. Генерация пакета:
Воспользуемся контекстом для задания нужных параметров:
Заключение
Хотелось бы обратить внимание, что подмена заголовков – не панацея от сливания информации. Не стоит забывать о JavaScript’е, Flash’е и интерактивных элементах, которые тоже вправе много чего разболтать. Используй NoScript и прочие AdBlock’и. Всегда экспериментируй и прикладывай выдумку, ищи там, где не ищет никто. Удачи!