<rmcreative>

RSS

Опасность слепой проверки заголовка X-Forwarded-For

15 апреля 2012

Сегодня пришёл pull-request в Yii на эту тему. В классе CHttpRequest есть метод getUserHostAddress, который отдаёт нам IP пользователя. Предложение было перед возвратом $_SERVER['REMOTE_ADDR'] проверить, а нет ли чего в $_SERVER['HTTP_X_FORWARDED_FOR'], и, если есть — вернуть. Мотивация — будут видны IP пользователей за прокси.

Так как такое заблуждение встречается ну очень часто, я даже не сразу вспомнил, откуда берётся $_SERVER['HTTP_X_FORWARDED_FOR']. А берётся он из заголовка HTTP запроса X-Forwarded-For и означает это то, что придти нам может что угодно.

А теперь представим, что разработчик воспользовался изменённым методом getUserHostAddress, проверяющим X-Forwarded-For:

if(in_array(Yii::app()->request->getUserHostAddress(), $allowedAddresses))
{
  // даём доступ к админке
}

Тем, кто пишет на Zend Framework, кстати, стоит проверить свой код потому как Zend_Controller_Request_Http::getClientIp() без переданного аргументом false как раз проверяет X-Forwarded-For:

/**
  * Get the client's IP addres
  *
  * @param  boolean $checkProxy
  * @return string
  */
  public function getClientIp($checkProxy = true)
  {
    if ($checkProxy && $this->getServer('HTTP_CLIENT_IP') != null) {
      $ip = $this->getServer('HTTP_CLIENT_IP');
    } else if ($checkProxy && $this->getServer('HTTP_X_FORWARDED_FOR') != null) {
      $ip = $this->getServer('HTTP_X_FORWARDED_FOR');
    } else {
      $ip = $this->getServer('REMOTE_ADDR');
    }
    return $ip;
  }

Заслал репорт в трекер Zend Framework на всякий случай.

Комментарии RSS

  1. №6127
    Дмитрий
    Дмитрий 15 апр. 2012 г., 4:04:03

    Согласен. Меня вообще удвиляет почему это поведение сделано по-умолчанию.

  2. №6128
    Дмитрий
    Дмитрий 15 апр. 2012 г., 4:06:15

    Кстати у вас небольше баг. Если сначала нажать на "Предварительный просмотр", значение чекбокса "Подписаться на комментарии" берется дефолтное (отлкючен), а не из POST'а.

    Ну, и вы уверены, что капчу нужно вводить дважды?

  3. №6129
    Sam
    Sam 15 апр. 2012 г., 13:20:34

    Для предпросмотра можно не вводить. Дефолт исправил.

  4. №6130
    Ncs
    Ncs 15 апр. 2012 г., 16:57:07

    Но в самом yii можно и было сделать обертку для HTTP_X_FORWARDED_FOR в Yii::app()->request

  5. №6131
    Дмитрий
    Дмитрий 15 апр. 2012 г., 19:49:36

    Для предпросмотра можно не вводить. Дефолт исправил.

    Пишу сообщение, имя, почту, считаю капчу, о, есть предварительный просмотр. Кликаю, удоставеряюсь, что все ок, хочу оправить. Опять нужно считать капчу :(

  6. №6132
    Максим
    Максим 15 апр. 2012 г., 21:28:05

    Я эти оба адреса через пробел конкатенировал и все нормально было. Нечего опасаться. Может и в Yii так организовать ?

  7. №6133
    Bethrezen
    Bethrezen 15 апр. 2012 г., 22:25:28

    Максим, заголовок приходит сырой и не обработанный. Там может быть не только IP или IP-через-запятую, но и всякая другая муть типа <SCRIPT> или '; DROP TABLE Students

  8. №6134
    Максим
    Максим 16 апр. 2012 г., 1:39:11

    Я понял из поста, ну это уже на совести программера должно быть. Можно и сам IP адрес подделать и реферер и много всяких других полей, но, защита от xss и sql injection остается на совести программиста.

  9. №6135
    Дмитрий
    Дмитрий 16 апр. 2012 г., 1:44:12

    Можно и сам IP адрес подделать

    Расскажите как?

  10. №6136
    Sam
    Sam 16 апр. 2012 г., 8:56:39

    Дмитрий, капчу для предпросмотра можно просто не вводить.

    Максим, IP подделать в общем случае нельзя, можно его только скрыть за прокси.

  11. №6137
    Bethrezen
    Bethrezen 16 апр. 2012 г., 9:15:34

    IP подделать нельзя, а вот в X-Forwarded-For можно записать всё, что душе угодно

  12. №6138
    Sam
    Sam 16 апр. 2012 г., 12:14:32

    Верно. Собственно, поэтому и использовать его в приведённом выше методе по умолчанию опасно.

  13. №6139
    Максим
    Максим 16 апр. 2012 г., 13:09:06

    2Sam, IP подделать таки можно, но крайне сложно + только в ограниченной, валидной форме.

  14. №6140
    Sam
    Sam 16 апр. 2012 г., 16:16:29

    Максим, полноценным запросом это назвать будет нельзя. Толку с него будет не много.

  15. №6141
    Дмитрий
    Дмитрий 16 апр. 2012 г., 20:38:24

    2 Максим

    только в ограниченной, валидной форме.

    Что это значит? Не говорите загадками!

  16. №6142
    Максим
    Максим 16 апр. 2012 г., 21:00:44

    2Дмитрий, То есть, можно использовать атаку man in the middle и "сырые" сокеты чтобы выдать свой IP за чужой.. Но опять же, адрес все равно останется вида число.число.число.число . На практике это конечно труднореализуемо. Но, в сети полно туториалов по применению. 2Sam, бывают случаи когда авторизация привязана к IP адресу админу.

  17. №6143
    Дмитрий
    Дмитрий 16 апр. 2012 г., 22:37:48

    2Максим Спасибо. Стал читать про man in the middle и сырые сокеты, зацепился за SUID, SGID and the Sticky Bits - и стало стыдно, что я этого не знал раньше, хотя юзаю линукс повседневно уже 2-й год!

  18. №6144
    Дмитрий
    Дмитрий 16 апр. 2012 г., 22:40:44

    2 Максим

    Но опять же, адрес все равно останется вида число.число.число.число . Не совсем понял, что вы имеете ввиду, ведь IPv4 именно такого формата!

    И почему "На практике это конечно труднореализуемо."?

  19. №6145
    Максим
    Максим 17 апр. 2012 г., 0:53:52

    То есть, XSS так не сделать как и sql-inj. Разве что специфическую защиту обойти и приватные данные получить. А труднореализуемо потому что есть файрвол от провайдера и arp таблицы, а также куча всяких других тонкостей. Поэтому такой тип атаки используется крайне редко. Но это уже не тема для обсуждения в этом блоге....

  20. №6146
    Дмитрий
    Дмитрий 17 апр. 2012 г., 1:01:59

    Ммм, давайт еще раз по порядку.

    Но опять же, адрес все равно останется вида число.число.число.число .

    Не совсем понял, что вы имеете ввиду, ведь IPv4 именно такого формата!

    А труднореализуемо потому что есть файрвол от провайдера и arp таблицы, а также куча всяких других тонкостей.

    ARP таблицы используются для преобразования ip в Ethernet-адрес. Не понимаю как это связано?!

  21. №6147
    Alexander
    Alexander 17 апр. 2012 г., 1:27:34

    if(in_array(Yii::app()->request->getUserHostAddress(), $allowedAddresses)) { // даём доступ к админке } Ужас. Просто ужас!

  22. №6148
    Bethrezen
    Bethrezen 17 апр. 2012 г., 9:36:50

    Максим, если XSS запихать в X-Forwarded-For, и этот IP где-то будет выводиться в голом виде(например в какой-нибудь статистике), то очень даже возможно. ARP, фаерволлы тут ни при чем. ОЛСО, они ни при чем только потому что, IP какбэ не в виде число.число.число.число передается, а в виде 4х байт и всё это происходит на уровне протокола,ядра и прочего, а не приложения. Не путайте людей, пожалуйста.

    Итак, поясню, что тут пытались донести: 1. REMOTE_ADDR - IP сокета, который всегда IP, ибо его подставляет веб-сервер при соединении. Его не подделать никак, кроме man in the middle и иже с ним, т.е. не уровень приложения. 2. X-Forwarded-For - самый обычный заголовок. Его используют всякие proxy и балансировщики для того, чтобы показать, что за внешним IP, что по соединению, сидят другие люди, нежели gateway. Если веб-сервер(apache,nginx) сам не проверяет валидность заголовка(а валидный это ip или несколько ip через запятую), то проверять это надо на уровне приложения, ибо этот заголовок может быть специально сформирован клиентом. 3. Если на уровне веб-сервера не дай бог меняют REMOTE_ADDR на X-Forwarded-For - проверять надо и REMOTE_ADDR. Итог: проверяйте заголовки тоже!

  23. №6149
    Дмитрий
    Дмитрий 17 апр. 2012 г., 9:45:36

    Его не подделать никак, кроме man in the middle и иже с ним, т.е. не уровень приложения.

    Т.е. пормируя запрос используя сырые сокеты я не смогу подменить IP, я правильно понял?

  24. №6150
    Bethrezen
    Bethrezen 17 апр. 2012 г., 11:06:43

    Дмитрий, IP-спуфинг в основном действует только в локальной сети, где можно послать пакет напрямую получателю в обход роутера. В реальной жизни все современные роутеры исправляют пакет на лету и ставят там реальный адрес.

    Если бы всё было так просто, то не было бы смысла во всех allow from ... в apache и т.д.

  25. №6151
    Bethrezen
    Bethrezen 17 апр. 2012 г., 11:08:26

    В догонку - неплохая статья, про один из методов, блокирующий ip-спуфинг suvan.ru/page/ip-spufing.html

  26. №6152
    Максим
    Максим 17 апр. 2012 г., 14:15:34

    2Bethrezen, А я разве где-то писал что файрвол фильтрует X-Forwarded-For(хотя на некоторых прокси и шлюзах он таки не передается) ? Я такого не писал. Так же как и я не писал что IP адрес в TCP-протоколе не в виде 4-х байт(или 6 в перспективе) передается, вы можете поспорить, но текстовое представление IP адреса стандартизировано: байт(число).байт.байт.байт. Я лишь писал про REMOTE_ADDR и как на некоторых сайтах, с помощью его подделки можно попасть в админку(встречал в одном проекте на cakephp).

    Я понял о чем статья, и даже написал свое мнение - что это должно быть на совести разработчика. Я не ожидал что вы запутаетесь, потому как старался в своем комментарии использовать поменьше терминологии, так как это должно было упростить его понимание.

  27. №6153
    Bethrezen
    Bethrezen 17 апр. 2012 г., 16:00:50

    Максим, я то не запутался. Просто не надо тут приплетать MITM и спуфинг.

  28. №6155
    Максим
    Максим 17 апр. 2012 г., 16:30:26

    Bethrezen, Думаю Alexander правильно прокомментировал мой комментарий. На практике меня провайдер от сети отключал ненадолго за такие проделки. Благо заявления не написали. Но все же, я не мог не упомянуть что в своих скриптах нельзя слепо полагаться не только на X-Forwarded-For, но и на REMOTE_ADDR.

    P.S.: Мы пишем об одном и том же, к чему нам спорить ? Вы хотите добавить что-то к моему комментарию - это ваше право.

  29. №6182
    Валентин
    Валентин 30 апр. 2012 г., 16:32:56

    IP адрес подделать нельзя , никак , это физически не возможно.

    Можно скрыть его через vpn/socks proxy которые спалят свой физический адрес, но это другой вопрос, потому как тут прокси палит свой адрес

    2Максим, 2Bethrezen

    Вы вообще представляете как на физическом уровне происходит соединение ? Какой спуффиг вообще ? вы о чем ? Сами то статью свою читали ? Ну поменяете вы поле отправителя , ну пошлете [SYN] пакет, хост ответит [SYN,ACK] хосту чей адрес вы маскируете , ну а дальше как ? Может вы думаете угадать seq , при том, до того как поддельный хост отправит [RST] пакет ? То что роутеры пакеты исправляют полная чушь, они могут их либо сбрасывать либо пропускать ,без изменения, исправлять они не будут , потому как не "телепаты" чтоб угадать реальный адрес отправителя.

    По поводу смены адреса при ARP cache poisoning, когда один узел притворяется шлюзом и для других узлов в сети проксирует запросы , то тут вообще атака не на уровне IP и работает исключительно в одноранговой сети где, узлы можно связать на физическом уровне, без роутинга да и то , далеко не всегда, особенно на современных ОС

    Резюме - подделать IP адрес узла через который установлено соединение НЕВОЗМОЖНО

  30. №6183
    Елена
    Елена 30 апр. 2012 г., 20:57:43

    Шаря по интернету в поисках решения своей проблемы, наткнулась на эту статью. Я вижу, вы вполне понимаете, о чем говорите) Может, поможете мне решить мою проблему?

    Три дня назад у меня отказал чат в одной он-лайн игре. Что только я ни делала, чтобы выяснить, в чем причина. Сначала грешила на браузер. Но смена браузера, вернее две смены, результата не дали. Чистка компа десятком различных антивирусников тоже не принесла плодов. Пробовала менять настройки соединения - безрезультатно.

    В конце концов случайно залезла во вкладку "Визиты" в той браузерке, где фиксируются ip-адреса пользователей, и там обнаружила, что именно с 27 апреля эта игра определяет мой ip не как (83.149..), как это было ранее, а как (83.149..) forwarded for: (10.211..). То есть, насколько я понимаю, теперь я попадаю в игру через прокси.

    Как такое могло произойти, если никакими проксями я не пользовалась? Может ли такое действие производить какой-нибудь вирус? И наконец, как от этого избавиться?

  31. №6184
    Валентин
    Валентин 30 апр. 2012 г., 21:13:20

    Такое легко могло произойти по вине провайдера. Не редко они ставят "прозрачные" прокси для снижения нагрузок, или садят пользователей за NAT. Решается звонком провайдеру и выяснением отношений, по какому они поводу начали модифицировать ваш траффик. Желательно почитать предварительно договор , чтоб убедиться, на что они имеют право а на что нет.

  32. №6185
    Елена
    Елена 30 апр. 2012 г., 21:56:53

    Спасибо за совет) Как раз хотела им позвонить.

  33. №6186
    Елена
    Елена 30 апр. 2012 г., 23:10:43

    Позвонила. Они признались, что это их идея, но при этом сообщили, что прокси отключать нельзя, ибо от этого интернет вообще отключится. На закономерный вопрос, почему же раньше без прокси обходились и ничего не отрубалось, невразумительно молчат.

  34. №6187
    Валентин
    Валентин 30 апр. 2012 г., 23:52:48

    Читайте договор, там должен быть пункт относительно модификации траффика, вообще они не имеют на это право , если не оговорено обратное. Отключить всегда можно, было бы желание - не будет желания , меняйте провайдера

  35. №6355
    Дмитрий
    Дмитрий 18 июня 2012 г., 21:47:36

    В MediaWiki данная проблема решена давным-давно. Просто есть список адресов, для которых разрешен x-forwarder-for, доверительные прокси, так сказать. Правда его правильная настройка уже на совести администратора конкретного сайта.

  36. №7707
    zedget
    zedget 18 марта 2013 г., 20:04:38

    Во многих разработках пользователи просят дописать такую возможность и в половине случаев не сразу вспоминаешь что заголовок этот не безопасен.

  1. Почта опубликована не будет.

  2. Можно использовать синтаксис Markdown или HTML.

  3. Введите ответ в поле. Щёлкните, чтобы получить другую задачу.