Что такое csrf значение. Уязвимость CSRF. Введение. Защита со стороны пользователя

Статья эвакуирована с DrupalDance.com

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

Итак, подделка межсайтовых запросов (анг. Сross Site Request Forgery, или, сокращенно, CSRF): что это такое и с чем его едят.

CSRF - это вид атак на посетителей веб-сайтов, использующий недостатки протокола HTTP. Если жертва заходит на сайт, созданный злоумышленником, от её лица тайно отправляется запрос на другой сервер (например, на сервер платёжной системы), осуществляющий некую вредоносную операцию (например, перевод денег на счёт злоумышленника). Для осуществления данной атаки, жертва должна быть авторизована на том сервере, на который отправляется запрос, и этот запрос не должен требовать какого-либо подтверждения со стороны пользователя.

Данный тип атак, вопреки распространённому заблуждению, появился достаточно давно: первые теоретические рассуждения появились в 1988 году, а первые уязвимости были обнаружены в 2000 году.

Одно из применений СSRF - эксплуатация пассивных XSS, обнаруженных на другом сервере. Так же возможны отправка спама от лица жертвы и изменение каких-либо настроек учётных записей на других сайтах(например, секретного вопроса для восстановления пароля).

Живой пример

Например, нам нужно сделать небольшой модуль, который должен аяксом удалять ноды. Это можно реализовать служебной ссылкой ноды, при нажатии которой, отправляется аякс запрос на друпаловский путь. К этому пути прицеплен обработчик, который и удаляет ноду. Вот примерно таким модулем все и делается:

node_destroy.module /** * Реализация hook_menu(). Регистрирует наш коллбек в системе меню. */ function node_destroy_menu() { $menu["node/%node/destroy"] = array("page_callback" => "node_destroy", "page_arguments" => array(1), "access_arguments" => array("administer nodes"), "type" => MENU_CALLBACK,); return $menu; } /** * Реализация коллбека. */ function node_destroy($node) { if ($node->nid) { node_delete($node->nid); print("SUCCESS"); } // в коллбеках для аякса почти всегда надо принудительно завершать скрипт, // чтобы не выводить оформление сайта вместе с вашими данными exit(); } /** * Реализация hook_link(). Добавляем свою ссылку в служебные ссылки ноды. */ function node_destroy_link($type, $node = NULL, $teaser = FALSE) { switch ($type) { case "node": // если эта функция вызывается, значит мы выводим ссылки ноды, // а это значит, что нам и скрипты нужны $path = drupal_get_path("module", "node_destroy"); drupal_add_js($path ."/node_destroy.js"); // собственно, добавление ссылки $links["node_destroy"] = array("title" => t("Destroy node"), "href" => "node/$node->nid/destroy", "attributes" => array("class" => "node_destroy_link"),); break; } return $links; } node_destroy.js // Таким нехитрым путем правильно инициализировать некие действия // вместо обычного $(document).ready(function() { ... }) Drupal.behaviors.node_destroy = function(context) { // Мы перебираем все наши ссылочки и навешиваем на них аякс запросы. // Заметьте необычный селектор. Он предотвратит двойное навешивание обработчиков. $(".node_destroy_link:not(.processed)", context).addClass("processed").click(function(){ href = $(this).attr("href"); $.ajax({ type: "GET", url: href, success: function(result){ // SUCCESS нам возвращает наш коллбек меню, если все замечательно if (result != "SUCCESS") { alert("Error"); } } }); }); }

И все бы хорошо, но в один солнечный день, на сайт приходит злой тролль... Или более жизненная ситуация - озлобленный бывший сотрудник приходит на сайт и пытается его поломать. Помня старый опыт, он пробует зайти по адресу http://site.ru/node/123/destroy , но получает от ворот поворот, так как уже не имеет прав на удаление материалов.

И тут, в порыве деструктивного креатива, он создает ноду с таким контетом:

Что происходит в этот момент? Никакая картинка, естественно, не подгрузится, но браузер тролля выполнит запрос на этот путь с прежним результатом.

Смирившись с неудачей, тролль уходит с сайта. Через день, администратор сайта замечает эту мусорную ноду, заходит в нее и удаляет. А вернувшись в список материалов, не находит в нем ноды с айдишником 123. Атака удалась. Занавес.

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

Как избежать CSRF уязвимостей?

Ответ - использовать уникальные ссылки для действий по изменению данных. Как это возможно? В друпале используется метод токенизации ссылок. Это означает, что к ссылке активного действия, прибавляется уникальный параметр, который проверяется при осуществлении самого действия. В друпале сгенерировать такой параметр можно функцией drupal_get_token() . Проверить -drupal_valid_token() . Токен генерируется на основе подаваемого значения, сессии пользователя, а также приватного ключа сайта, что практически сводит на ноль вероятность генерации вредителем правильного токена.

Внесем изменения в наш модуль. Начнем с выставления правильной ссылки:

Function node_destroy_link($type, $node = NULL, $teaser = FALSE) { switch ($type) { case "node": $path = drupal_get_path("module", "node_destroy"); drupal_add_js($path ."/node_destroy.js"); $links["node_destroy"] = array("title" => t("Destroy node"), "href" => "node/$node->nid/destroy", "attributes" => array("class" => "node_destroy_link"), // query - это все GET параметры, т.е. все что в ссылке находится после знака вопроса // мы добавляем параметр token "query" => "token=". drupal_get_token("node_destroy_". $node->nid)); break; } return $links; }

Как вы помните, мы шлем аякс запрос по адресу, который зашит в ссылке, поэтому в коллбеке нам остается только проверить $_GET стандартным способом.

Function node_destroy($node) { if ($node->nid && isset($_GET["token"]) && drupal_valid_token($_GET["token"], "node_destroy_". $node->nid)) { node_delete($node->nid); print("SUCCESS"); } exit(); }

Cross Site Request Forgery, или CSRF, является атакой, которая осуществляется в тот момент, когда вредоносный сайт, письмо, сообщение, приложение или что-либо иное заставляет браузер пользователя выполнить некоторые действия на другом сайте, где этот пользователь уже аутентифицирован. Зачастую это происходит без ведома пользователя.

Вред от CSRF-атаки зависит от сайта, принимающего действие. Вот пример:

  • Бобвходитвсвойличныйкабинетвбанковскомонлайнклиенте, выполняет какие-то операции, но не разлогинивается.
  • Бобпроверяетсвоюпочтуикликаетнассылку,ведущую на незнакомый сайт.
  • Незнакомыйсайтделаетзапросконлайн-клиентубанка Боба на перевод денег, передавая информацию в cookie Боба, сохранившуюся с предыдущей его сессии.
  • СайтбанкаБобапринимаетзапросотнезнакомого(вредоносного) сайта без использования CSRF-токена и выполняет перевод.
  • Еще более интересна ситуация, когда ссылка на вредоносный
    сайт может содержаться в валидном HTML, благодаря чему Бо-
    бу даже не придется нажимать на ссылку: . Если устройство Боба (например, браузер) отрису-
    ет это изображение, оно сделает запрос к malicious_site.com и потенциально совершит CSRF-атаку.

    Теперь, зная об опасностях, которые несут CSRF-атаки, вы можете защититься от них множеством способов, самым популярным из которых, возможно, является использование CSRFтокена, который должен отправляться с любым запросом, который потенциально может изменять данные (например, с POST-запросами). Веб-приложение (такое, как онлайн-банк Боба) должно будет сгенерировать токен, состоящий из двух частей, одну из которых получит Боб, а вторая будет сохранена в приложении.

    Когда Боб попытается совершить запрос на перевод денег, он должен будет отправить токен, который будет проверен банком на валидность при помощи токена, хранящегося в приложении.

    Теперь, когда мы знаем о CSRF и CSRF-токенах, Cross Origin Resource Sharing (CORS) становится более понятным, хотя возможно, я просто заметил это по мере исследования новых целей. В общем, CORS ограничивает список ресурсов, которые могут получать доступ к данным. Другими словами, когда CORS используется для защиты сайта, вы можете написать Javascript для вызова целевого приложения, прочитать ответ и сделать другой вызов, если целевой сайт вам это позволяет.

    Если это кажется непонятным, то попробуйте с помощью Javascript сделать вызов к HackerOne.com/activity.json, прочитать ответ и сделать второй вызов. Вы также увидите важность этого и потенциальные способы обхода в примере #3 ниже.

    Наконец, важно заметить (спасибо Джоберту Абме за указание на этот момент), что не каждый запрос без CSRF-токена является невалидным. Некоторые сайты могут выполнять дополнительные проверки, такие, как сравнение заголовка исходящей стороны (хотя это не является гарантией безопасности и есть известные случаи обхода). Это поле, которое идентифицирует адрес страницы, которая ссылается на запрашиваемый ресурс. Другими словами, если исходящая сторона (реферер)

    выполняет POST-вызов не с того же сайта, который получил HTTP-запрос, сайт может не позволить вызову достигнуть того же эффекта, что достигается с использованием CSRFтокена. Кроме того, не каждый сайт использует терми csrf при создании или определении токена. Например, на Badoo это параметр rt, как описано ниже.

    Прочтите руководство по тестированию на OWASP Testing for CSRF

    Примеры 1. Экспорт установленных пользователей Shopify

    Сложность: Низкая
    Url: https://app.shopify.com/services/partners/api_clients/XXXX/export_installed_users


    Описание:

    API Shopify предоставляет эндпоинт для экспорта списка установленных пользователей через URL, показанный выше. Уязвимость заключалась в том, что сайт мог сделать запрос к этому эндпоинту и получить в ответ информацию, поскольку

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

    1 2 csrf 3 4 7 8 9

    В этом примере при простом посещении страницы Javascript отправляет форму, которая включает GET-запрос к API Shopify, используя cookie Shopify, установленные в браузере жертвы.

    Выводы

    Увеличивайте масштаб ваших атак и ищите баги не только на сайте, но и в API. Эндпоинты API также являются потенциальной площадкой для использования уязвимостей, так что стоит помнить об этом, особенно, если вы знаете, что API мог быть разработан или стать доступным после того, как был создан веб-интерфейс.

    2. Отключение Shopify от Twitter

    Сложность: Низкая
    Url: https://twitter-commerce.shopifyapps.com/auth/twitter/disconnect

    Shopify предоставляет интеграцию с Twitter, что позволяет владельцам магазинов постить твиты о своих продуктах. Подобным образом сервис позволяет и отключить аккаунт Twitter от связанного магазина.

    URL для отключения аккаунта Twitter от магазина указан выше. При совершении запроса Shopify не валидировал CSRFтокен, что позволило злоумышленнику создать фальшивую ссылку, клик на которую приведет ничего не подозревающего владельца магазина к отключению его магазина от Twitter.

    Описывая уязвимость, WeSecureApp предоставил следующий пример уязвимого запроса обратите внимание, что использование тега img делает вызов к уязвимому URL:

    1 GET /auth/twitter/disconnect HTTP/1.1 2 Host: twitter-commerce.shopifyapps.com 3 User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.1 4 1; rv:43.0) Gecko/20100101 Firefox/43.0 5 Accept: text/html, application/xhtml+xml, application/x 6 ml 7 Accept-Language: en-US,en;q=0.5 8 Accept-Encoding: gzip, deflate 9 Referer: https://twitter-commerce.shopifyapps.com/accou 10 nt 11 Cookie: _twitter-commerce_session=REDACTED 12 >Connection: keep-alive

    Поскольку браузер выполняет GET-запрос для получения изображения по переданному URL и CSRF-токен не валидируется, пользовательский магазин теперь отключен:

    1 2 3 5 6

    Выводы

    В этой ситуации, описанная уязвимость могла быть найдена при использовании проксисервера, такого, как Burp или Firefox Tamper Data, достаточно было взглянуть на запрос, отправляемый к Shopify и увидеть, что этот запрос был осуществлен с помощью GET-запроса. Поскольку это было разрушительное действие и GETзапросы не должны изменять данные на сервер, это стоит исследовать.

    3. Полный захват аккаунта на Badoo

    Сложность: Средняя
    Url: https://badoo.com
    Ссылка на отчет: https://hackerone.com/reports/12770312
    Дата отчета: 1 апреля 2016
    Выплаченное вознаграждение: $852

    Описание:

    Если вы взглянете на Badoo, выпоймете, что они защищаются от CSRF включением в URL параметра rt, который имеет длину всего в 5 символов (по крайней мере, на момент написания). Хотя я заметил это, когда Badoo запустил кампанию на HackerOne, я не нашел способа это использовать. Однако, Махмуд Джамал (zombiehelp54) нашел.

    Поняв значение параметра rt, он также заметил, что параметр возвращался в почти всех json-ответах. К сожалению, это не принесло пользы, поскольку CORS защищает Badoo от атак, читая эти ответы. Махмуд продолжил искать.

    Оказалось, что файл https://eu1.badoo.com/worker-scope/chrome-ser содержит значение rt. Еще лучше было то, что этот файл
    мог быть произвольно прочитан атакующим и не требовал от
    жертвы никаких действий кроме посещения вредоносной веб-страницы. Вот код, который он предоставил:

    1 2 3 Badoo account take over 4 6 7 8 9 function getCSRFcode(str) { 10 return str.split(’=’); 11 } 12 window.onload = function(){ 13 var csrf_code = getCSRFcode(url_stats); 14 csrf_url = ’https://eu1.badoo.com/google/verify.phtml?c 15 ode=4/nprfspM3yfn2SFUBear08KQaXo609JkArgoju1gZ6Pc&authu 16 ser=3&session_state=7cb17 4b560..a810&prompt=none&rt=’+ csrf_code; 18 window.location = csrf_url; 19 }; 20

    В общем, когда жертва загружала страницу, она делала запрос к скрипту Badoo, забирала параметр rt для этого пользователя и затем делала запрос от имени жертвы. В этом случае, это было связывание аккаунта Махмуда с аккаунтом жертвы, что позволяло полностью захватить аккаунт.

    Выводы

    Где дым, там и огонь, Здесь Махмуд заметил, что параметр rt возвращался в разных местах, в конкретных json-ответах. Поэтому он правильно предположил, что он может быть показан где-то, где его можно будет использовать в этом случае в js файле.

    Итоги

    CSRF-атаки представляют другой опасный вектор для атак и могут быть быть выполнены без активных действий со стороны жертвы или вообще без её уведомления. Обнаружение CSRF-уязвимостей требует некоторой изобретательности и, опять же, желания тестировать все подряд.

    Как правило, формы стандартно защищены фреймворками вроде Rails если сайт выполняет POST-запрос, но API могут

    быть отдельной историей. Например, Shopify написан в основном на основе фреймворка Ruby on Rails, который предоставляет защиту от CSRF-атак для всех форм по умолчанию (хотя её и можно отключить). Однако, очевидно, что это не обязательно так для API, созданных с помощью этого фреймворка. Наконец, обращайте внимание на вызовы, которые изменяют данные на сервере (такие, как действие удаления) и выполняются с помощью GET-запроса.

    Я попытался описать что именно представляет из себя данная уязвимость и, что не маловажно, выполнение каких условий необходимо для проведения атаки типа CSRF.

    В данной статье я попытаюсь рассказать о защите от атак данного типа со сторон:

    • Со стороны клиента — основные способы защитить себя самому
    • Со стороны сервера — правильное проектирование приложения

    Если вам интересно как защититься от CSRF то добро пожаловать под кат.

    Общая информация

    В общем то хочу напомнить, CSRF — это НЕ уязвимость, это вид атаки. И данная атака проводится на конечного пользователя веб приложения с помощью уязвимости в данном приложении, которую можно назвать как «Отсутствие надлежащей проверки источника запроса» (название я придумал сам, не судите строго, но это так). Но здесь и далее я буду называть CSRF уязвимостью и атакой в одном лице так, как это проще, да и именно так принято =)

    И раз атака проводится на пользователя, то и пользователю защищаться… шутка =) Дело в том что любой пользователь может снизить возможность проведения данной атаки на любом сайте, которым он пользуется (даже если на этих сайтах нет встроенной защиты от CSRF). Но помимо пользователей, сами разработчики сайтов могут спроектировать свое приложение так, чтобы недопустить возможность проведения данной атаки на своих пользователей.

    Рассмотрим защиту с обоих сторон.

    Защита со стороны пользователя

    Вообщем тут все очень банально:

    • Не переходить на ссылки предложенные вам третьими лицами. Это самый банальный совет, я думаю это все и так знают, но решил лишний раз сказать об этом.
    • Деавторизовываться по окончанию работы с конкретным сайтом. Даже при наличии уязвимости, злоумшленник не сможет выполнить действия на целевом сайте от вашего имени.
    • Использовать отдельный браузер или «приватные или анонимные режимы» для работы с важными сайтами (в идеале использовать по одному браузеру на каждый сайт ^_^ а еще лучше отдельный компьютер:D).

    На этом все. Теперь перейдем к главному.

    Защита со стороны разработчиков

    Как уже было сказанно, уязвимость заключается в отсутствии надлежащей проверки источника запроса. То есть при разработке приложения нам нужно встроить функционал проверки этого источника. И чтоже первым делом нам приходит в голову? Правильно! Проверка Referer.

    Проверка Referer

    Сразу скажу, для тех кто читает статьи по диагонали. Основывать свою защиту только на проверке этого заголовка — плохо(!). Почему — см. далее.

    Для начала разберемся, в чем заключается этот способ.

    С сайтами мы работаем по HTTP протоколу. Каждый пакет этого протокола представляет собой набор заголовков + содержимое пакета. Одним из этих заголовков является Referer. Он содержит адрес источника перехода. Банальный пример: у вас открыт сайт A , на данном сайте вы кликаете на ссылку на сайт B , в этот момент при запросе в заголовке Referer будет содержатся адрес сайта A . То есть казалось бы это идеальный механизм для отслеживания откуда пришел пользователь.

    А вот хрен. И дело здесь не в том что можно подделать реферер (какой здравомыслящий взломщик будет просить жертву о том, чтобы она подменила реферер и перешла по указанной ссылке). А в том что по моей статистике у около 5% пользователей передача Referer отключенна. То есть либо эти пять процентов не смогут работать с сайтом вообще, либо они будут уязвимы к этой атаке (зависит от политики вашего приложения).

    Да, да, да, я знаю о чем вы подумали… Ну и фиг с этими 5%? Пусть будут уязвимы, зато остальные 95% защищены и при этом вы обошлись малой кровью. То есть если реферер содержит адрес нашего приложения либо пуст, то считаем источник подтвержденным? А вот снова хрен! Существуют варианты заставить браузер жертвы выполнить запрос без указания реферера (об этом я написал )! И вуаля! Оказывается все пользователи по-прежнему уязвимы.

    Воощем как самостоятельный способ данный метод бессмыслен.

    Подтверждение действия

    Можно к каждой форме отправке прикрутить капчу, и показывать ее даже для зарегестрированных пользователей, чтобы спасти их от CSRF… Хотя пожалуй, я бы предпочел отдать свой аккаунт хакеру, чем работать в такой системе…

    Токены

    Ну и теперь единственный правильный и надежный способ.

    Смысл данного способа заключается в добавлении параметра содержащего некоторый «токенов» к каждой ссылке, форме отправки и проч. А при получении запроса сервер должен проверять наличие данного токена в принятых параметрах. Естественно каждый токен для каждого пользователя должен быть уникальным, а еще лучше если каждый токен будет уникальным.

    Один из самых простых и надежных примеров реализации — токен генерируется при каждом запросе новый и устанавливается в cookies пользователя а также добавляется в параметры форм и ссылок на странице:

    И затем при получении каждого запроса сравнивается токен из куков и токен указанный в параметрах формы. И если они одинаковы, то источник запроса легален. Затем токен генерируется снова, и снова устанавливается в куки, и т.д. по кругу.

    Вообще реализация может быть другая, но проблема в том что переход на токены это довольно сложно так как приходится учитывать каждую ссылку, каждую форму, каждую страницу… Можно защищать только важные страницы/формы/ссылки, но тогда есть шанс какие то из них упустить.

    Я лично защищаю только POST формы и очень важные ссылки. То есть POST в моих приложениях не работает без наличия правильного токена. Это избавляет от шанса забыть защитить какую то форму, так как она просто не будет работать и я сразу это замечу.

    Вывод

    Надеюсь из данной статьи вы поняли каким образом следует защищаться от CSRF атак.

    Cross-Site Request Forgery – много шума из-за ничего

    Alexander Antipov

    В последнее время в сообществе специалистов по безопасности Web-приложений широко обсуждается «новый» тип уязвимостей, получивший название Cross-Site Request Forgery (CSRF или XSRF). Предлагаемая вниманию читателя статья содержит описание этого типа уязвимостей, методов его использования и основные походы к защите.


    Сергей Гордейчик

    Gоrdey @ ptsеcurity com

    В последнее время в сообществе специалистов по безопасности Web-приложений широко обсуждается «новый» тип уязвимостей, получивший название Cross-Site Request Forgery (CSRF или XSRF). Предлагаемая вниманию читателя статья содержит описание этого типа уязвимостей, методов его использования и основные походы к защите. Общепринятый русский термин для обозначения Cross-Site Request Forgery ещё не устоялся, в связи с чем автор предлагает использовать вариант «Подделка HTTP-запросов».

    Лирическое отступление

    Прежде всего, хотелось бы остановиться на основных заблуждениях связанных с CSRF:

    1. Подделка HTTP-запросов – новый тип уязвимостей.

    Это далеко не так. Теоретические размышления на тему подделки источника сообщений датированы 1988 годом (http://www.cis.upenn.edu/~KeyKOS/ConfusedDeputy.html), а практические примеры уязвимостей обсуждаются в Bugtraq как минимум с 2000 года (http://www.zope.org/Members/jim/ZopeSecurity/ClientSideTrojan). Сам термин введен Peter Watkins (http://www.securiteam.com/securitynews/5FP0C204KE.html) в 2001 году.

    2. CSRF – это вариант Межсайтового выполнения сценариев (XSS).

    Единственное сходство между CSRF и XSS, это использование в качестве вектора атаки клиентов Web-приложений (Client-Side Attack в терминологии WASC http://www.webappsec.org/projects/threat/). Уязвимости типа CSRF могут эксплуатироваться совместно с XSS или «редиректорами» (http://www..php), но представляют собой отдельный класс уязвимостей.

    3. Уязвимость CSRF мало распространена и достаточно сложна в использовании.

    Данные, полученные компанией Positive Technologies в ходе работ по тестированию на проникновение и оценки защищенности Web-приложений показывают, что этой уязвимости подвержена большая часть Web-приложений. В отличие от других уязвимостей CSRF возникает не в результате ошибок программирования, а является нормальным поведением Web-сервера и браузера. Т.е. большинство сайтов, использующих стандартную архитектуру уязвимы «по умолчанию».

    Пример использования

    Давайте рассмотрим использование CSRF на примере. Предположим, существует некое Web-приложение, отправляющее сообщения электронной почты. Пользователь указывает адрес электронной почты и текст сообщения, нажимает кнопку Submit и сообщение от его адреса передается получателю.

    Рис. 1. Отправка сообщения

    Схема знакома по множеству сайтов и не вызывает никаких возражений. Однако указанное приложение с большой вероятности уязвимо для атак «Подделка HTTP-запроса». Для эксплуатации уязвимости злоумышленник может создать на своем сайте страницу содержащую ссылку на «изображение», после чего заставить пользователя перейти по ссылке на свой сайт (например, http://bh.ptsecurity.ru/xcheck/csrf.htm).

    При обращении к странице браузер пользователя пытается загрузить изображение, для чего обращается к уязвимому приложению, т.е. оправляет сообщение электронной почты адресату, указанному в поле «to» запроса.

    Рис. 2. Атака CSRF

    Обратите внимание, что браузер пользователя отправит сайту значение Cookie, т.е. запрос будет воспринят как исходящий от аутентифицированного пользователя. Для того чтобы заставить пользователя загрузить страницу, отправляющую запрос к уязвимому серверу, злоумышленник может использовать методы социальной инженерии, а также технические уязвимости, такие как XSS и ошибки в реализации функции перенаправления.

    Рис. 3. Логика работы CSRF

    Таким образом, атака с использованием CSRF заключается в использовании браузера пользователя для передачи HTTP-запросов произвольным сайтам, а уязвимость – в отсутствии проверки источника HTTP-запроса. Приведенное в примере приложение использует HTTP-метод GET для передачи параметров, что упрощает жизнь злоумышленнику. Однако не стоит думать, что использование метода POST автоматически устраняет возможность проведения атак с подделкой HTTP-запроса. Страница на сервере злоумышленника может содержать готовую HTML-форму, автоматически отправляемую при просмотре страницы.

    Для эксплуатации CSRF злоумышленнику совсем не обязательно иметь свой Web-сервер. Страница, инициирующая запрос может быть передана по электронной почте или другим способом.

    В обзоре Billy Hoffman приведены различные методы сетевого взаимодействия с помощью Javascript. Все они, включая XmlHttxmpquest (в некоторых ситуациях), могут быть задействованы для реализации атак CSRF.

    Надеюсь, что сейчас читателю уже понятно основное отличие CSRF от XSS. В случае с XSS злоумышленник получает возможность доступа к DOM (Document Object Model) уязвимой страницы, как на чтение, так и на запись. При выполнении CSRF атакущий имеет возможность передать запрос серверу с помощью браузера пользователя, но получить и проанализировать ответ сервера, а тем более его заголовок (например, Cookie) уже не сможет. Соответственно, «Подделка HTTP-запросов» позволяет работать с приложением в режиме «только на запись», чего впрочем, вполне достаточно для выполнения реальных атак.

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

    Рис. 4. Пример эксплуатации CSRF в форуме

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

    Пробиваем периметр

    В декабре прошлого года компания Symantec опубликовала отчет о «новой» атаке, под называнием «Drive-By Pharming», которая, по сути, является вариантом эксплуатации CSRF. Злоумышленник выполняет в браузере пользователя некий «волшебный» JavaScript, изменяющий настройки маршрутизатора, например устанавливающего новое значение DNS-сервера. Для выполнения этой атаки необходимо решить следующие задачи:

    Сканирование портов с помощью JavaScript;

    Определение типа Web-приложения (fingerprint);

    Подбор пароля и аутентификация с помощью CSRF;

    Изменение настроек узла с помощью атаки CSRF.

    Техника сканирования определения доступности Web-сервера и его типа по с помощью JavaScript проработана достаточно хорошо и сводится к динамическому созданию HTML-объектов (например, img src=), указывающие на различные внутренние URL (например, http://192.168.0.1/pageerror.gif). Если «картинка» была успешно загружена, то по тестируемому адресу расположен Web-сервер на базе Microsoft IIS. Если в ответ было получена ошибка 404, то порт открыт и на нем работает Web-сервер. В случае если был превышен таймаут – сервер отсутствует в сети или порт заблокирован на межсетевом экране. Ну и в остальных ситуациях – порт закрыт, но хост доступен (сервер вернул RST-пакет и браузер вернул ошибку до истечения таймаута). В некоторых ситуациях подобное сканирование портов из браузера пользователя может проводиться без использования JavaScript (http://jeremiahgrossman.blogspot.com/2006/11/browser-port-scanning-without.html).

    После определения типа устройства злоумышленник может попробовать заставить браузер пользователя сразу послать запрос на изменение настроек. Но такой запрос будет успешен только в случае, если браузер пользователя уже имеет активную аутентифицированную сессию с устройства. Иметь под рукой открытую страницу управления маршрутизатором - дурная привычка многих «продвинутых» пользователей.

    Если же активной сессии с интерфейсом управления нет, злоумышленнику необходимо пройти аутентификацию. В случае если в устройстве реализована аутентификация на основе форм, никаких проблем не возникает. Используя CSRF в POST, серверу отправляются запрос на авторизацию, после чего с него загружается изображение (или страница) доступная только аутентифицированным пользователям. Если изображение было получено, то аутентификация прошла успешно, и можно приступать к дальнейшим действиям, в обратном случае – пробуем другой пароль.

    В случае если в атакуемом устройстве реализована аутентификация по методу Basic, задача усложняется. Браузер Internet Explorer не поддерживает возможность указать имя пользователя и пароль в URL (например, http://user:[email protected]). В связи с этим для выполнения Basic-аутентификации может использоваться метод с добавлением HTTP-заголовков с помощью Flash, описанный в статье . Однако этот метод подходит только для старых версий Flash, которые встречаются все реже и реже.

    Но другие брузеры, например Firefox дают возможность указать имя пользователя и пароль в URL, и могут быть использованы для аутентификации на любом сервере, причем это можно сделать без генерации сообщения об ошибке в случае выбора неверного пароля.

    Пример сценария для «тихой» аутентификации по методу Basic, из блога Stefan Esser приведен ниже.

    Firefox HTTP Auth Bruteforcing

    Рис. 5. Аутентификация Basic в Firefox

    В корпоративной среде, где зачастую используются механизмы SSO, например, на базе домена Active Directory и протоколов Kerberos и NTLM эксплуатация CSRF не требует дополнительных усилий. Браузер автоматически пройдет аутентификацию в контексте безопасности текущего пользователя.

    После того как аутентификация была пройдена, злоумышленник с помощью JavaScript передать запрос, изменяющий произвольные настройки маршрутизатора, например адрес DNS-сервера.

    Методы защиты

    Первое, что приходит на ум, когда речь заходит о защите от CSRF – это проверка значения заголовка Referer. И действительно, поскольку подделка HTTP-запросов заключается в передаче запроса с третьего сайта, контроль исходной страницы, чей адрес автоматически добавляется браузером в заголовки запроса, может решить проблему.

    Однако этот механизм имеет ряд недостатков. Во-первых – перед разработчиком встает вопрос об обработке запросов, не имеющих заголовка Referer как такового. Многие из персональных межсетевых экранов и анонимизирующих proxy-серверов вырезают Referer, как потенциально небезопасный заголовок. Соответственно, если сервер будет игнорировать подобные запросы, группа наиболее «параноидально» настроенных граждан не смогут с ним работать.

    Во-вторых, в некоторых ситуациях заголовок Referer может быть подделан, например, с помощью уже упоминавшегося трюка с Flash. Если пользователь применяет IE 6.0, то содержимое заголовка запроса может быть модифицировано c использованием ошибки в реализации XmlHttxmpquest. Уязвимость заключается в возможности использования символов перевода строки в имени HTTP-метода, что позволяет изменять заголовки и даже внедрять дополнительный запрос. Эта уязвимость была обнаружена Amit Clein () в 2005 году и снова открыта в 2007. Ограничением этого метода является то, что он работает только в случае наличия между пользователем и сервером HTTP-Proxy или размещения серверов на одном IP-адресе, но с разными доменными именами.

    Другой распространенный метод – добавление уникального параметра к каждому запросу, который затем проверяется сервером. Параметр может добавляться к URL при использовании GET запроса как например, в или в виде спрятанного параметра формы, при использовании POST. Значение параметра может быть произвольным, главное, чтобы злоумышленник не мог его предсказать, например – значение сессии пользователя.

    Рис. 6. Защита от CSRF в Bitrix

    Для быстрого добавления функции проверки CSRF в свое приложение можно воспользоваться следующим подходом:

    1. Добавлять в каждую генерируемую страницу небольшой JavaScript, дописывающий во все формы дополнительный скрытый параметр, которому присваивается значение Cookie.

    2. Проверять на сервере, что переданные клиентом с помощью метода POST данные содержат значение, равное текущему значению Cookie.

    Пример подобного клиентского сценария приведен ниже:

    Дальнейшим развитием этого подхода является сохранение идентификатора сессии не в Cookie, а в качестве скрытого параметра формы (например, VIEWSTATE).

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

    Рис. 7. Защита от CSRF в mail.ru

    Таким образом, Cross-Site Request Forgery являются атакой, направленной на клиента Web-приложения и использующей недостаточную проверку источника HTTP-запроса. Для защиты от подобных атак может использоваться дополнительный контроль источника запроса на основе заголовка Referer или дополнительного «случайного» параметра.

    Сергей Гордейчик работает системным архитектором компании Positive Technologies, где он специализируется в вопросах безопасности приложений, безопасности беспроводных и мобильных технологий. Автор также является ведущим разработчиком курсов «Безопасность беспроводных сетей», «Анализ и оценка защищенности Web-приложений» учебного центра «Информзащита» . Опубликовал несколько десятков статей в “Windows IT Pro/RE”, SecurityLab и других изданиях. Является участником проектов Web Application Security Consortium (WASC).