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
  • Sanitizer API
  • Trusted Types
  • Заключение
  1. Глава 2 - Защита и Обход для XSS

Последние методы защиты от XSS - Trusted Types и встроенный Sanitizer API

Обсуждая защиту от XSS, я упоминал необходимость обрабатывать пользовательский ввод. Если разрешен HTML, необходимо найти надежный пакет для его обработки.

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

Создание новой функции с нуля обычно занимает долгое время, от предложения и спецификации до реализации, что может занять несколько лет. Темы Trusted Types и Sanitizer API, обсуждаемые в этой статье, в настоящее время поддерживаются только браузерами на основе Chromium. Они еще не официально поддерживаются в последних версиях Firefox (119) и Safari (17). Поэтому содержание этой статьи можно рассматривать как справочник для будущего использования в производстве, когда придет подходящее время.

Sanitizer API

Sanitizer API - это встроенный санитайзер, предоставляемый браузерами. Он довольно похож на ранее упомянутый DOMPurify с точки зрения использования. Вот пример:

<!DOCTYPE html>
<html>
<body>
    <div id="content"></div>
    <script>
        const html = `
            Hello,
            <script>alert(1)<\/script>
            <img src="x" onerror="alert(1)">
            <a href="javascript:alert(1)">click me</a>
            <h1 onclick="alert(1)" id="a">title</h1>
            <iframe></iframe>
        `;

        const sanitizer = new Sanitizer();
        document
            .querySelector("#content")
            .setHTML(html, { sanitizer });
    </script>
</body>
</html>

Чтобы работать с Sanitizer API, был добавлен новый метод setHTML. Передавая исходный HTML и санитайзер, Sanitizer API может выполнять фильтрацию.

Отфильтрованный результат приведенного выше HTML:

Hello,<img src=x><a>click me</a><h1 id=a>title</h1>

Все опасные элементы удалены. Цель Sanitizer API - гарантировать, что "независимо от того, как вы его используете или настраиваете, XSS не произойдет". Это является как преимуществом, так и недостатком. Позвольте мне привести еще один пример, чтобы пояснить:

<!DOCTYPE html>
<html>
<body>
    <div id="content"></div>
    <script>
        const html = `
            Hello, this is my channel:
            <iframe src="https://www.youtube.com/watch?v=123"></iframe>
        `;

        const sanitizer = new Sanitizer({
            allowElements: ['iframe'],
            allowAttributes: {
                'iframe': ['src']
            }
        });

        document
            .querySelector("#content")
            .setHTML(html, { sanitizer });

        /*
            result: Hello, this is my channel:
        */
    </script>
</body>
</html>

Файл конфигурации указывает, что разрешены iframes, включая атрибут src. Однако в итоговом результате iframe все равно удален. Это происходит потому что, как я упоминал ранее, Sanitizer API гарантирует, что вы никогда не сможете использовать опасные теги. Так что, независимо от конфигурации, iframes не разрешены.

Например, если применяется фильтрация к атрибуту src, следует ли фильтровать URL-ы внутри него? Следует ли удалить URL-ы data:? Что насчет srcdoc? Должен ли он также быть заново отфильтрован? Этот вопрос все еще открыт и неактивен уже более года.

Это можно считать как преимуществом, так и недостатком Sanitizer API. Хотя возможно ему недостаточно гибкости, его преимущество состоит в том, что, независимо от того, как он используется, проблем не будет. В отличие от сторонних пакетов, которые мы ранее представили, существует возможность проблем, если конфигурация не настроена должным образом.

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

Хотя я все еще рекомендую использовать DOMPurify для очистки, хорошо иметь представление о Sanitizer API.

Trusted Types

Trusted Types, как и Sanitizer API, тоже очень новый и в настоящее время поддерживается только браузерами на основе Chromium. Так что, на данный момент стоит просто ознакомиться с ним, поскольку он еще не дошел до зрелости.

При отображении пользовательских данных на фронтенде, мы должны постоянно контролировать, что пользовательский ввод правильно обрабатывается, чтобы предотвратить уязвимости XSS. Однако, во многих местах можно допустить ошибки, такие как innerHTML, <iframe srcdoc> или document.write и т.д. Если мы напрямую передаем необработанный ввод в них, это создает уязвимость XSS.

Помимо того, что разработчики должны быть осторожны при написании кода, есть ли другие методы для предотвращения проблем в этих местах? Например, предположим, я выполняю div.innerHTML = str, и если str - необработанная строка, он выдает ошибку и останавливает выполнение. Таким образом, можно уменьшить вероятность XSS.

Да, это то, что делает Trusted Types.

После добавления Trusted Types в CSP, можно включить Trusted Types для защиты этих DOM API, заставляя браузер пройти через обработку Trusted Types перед вставкой HTML:

Content-Security-Policy: require-trusted-types-for 'script';

Вот пример:

<!DOCTYPE html>
<html>
<head>
    <meta http-equiv="Content-Security-Policy" content="require-trusted-types-for 'script'">
</head>
<body>
    <div id="content"></div>
    <script>
        document.querySelector("#content").innerHTML = '<h1>hello</h1>';
    </script>
</body>
</html>t

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

> This document requires 'TrustedHTML' assignment. Uncaught TypeError: Failed to set the 'innerHTML' property on 'Element': This document requires 'TrustedHTML' assignment.

После принудительной активации Trusted Types вы больше не сможете напрямую передавать строку в innerHTML. Вместо этого вам потребуется создать новую политику Trusted Types для обработки опасного HTML. Вот как это делается:

<!DOCTYPE html>
<html>
<head>
    <meta http-equiv="Content-Security-Policy" content="require-trusted-types-for 'script'">
</head>
<body>
    <div id="content"></div>
    <script>
        // create a new policy
        const sanitizePolicy = trustedTypes.createPolicy('sanitizePolicy', {
            // add sanitize/escape
            createHTML: (string) => string
                .replace(/</g, "&lt;")
                .replace(/>/g, '&gt;')
        });

        // The type of safeHtml is TrustedHTML, not String
        const safeHtml = sanitizePolicy.createHTML('<h1>hello</h1>');
        document.querySelector("#content").innerHTML = safeHtml;
    </script>
</body>
</html>

Цель Trusted Types - не "гарантировать, что ваш HTML не имеет проблем", а скорее "заставить использовать Trusted Types на потенциально проблемных DOM API и запретить использование строк". Это значительно снижает многие риски. Когда вы случайно забываете обработать пользовательский ввод, браузер выдает ошибку, а не обрабатывает необработанную строку как HTML.

Поэтому, после включения Trusted Types, вам нужно только сосредоточиться на реализации createHTML и убедиться, что эти реализации безопасны. Кроме того, из приведенного выше примера видно, что содержимое createHTML определяется нами, поэтому оно также может быть объединено с DOMPurify.

> Могу ли я использовать Sanitizer API вместе с Trusted Types?

> Да, пожалуйста. Мы видим в этих API решение разных аспектов одной и той же проблемы. Они отдельны, но должны хорошо работать вместе. Детали интеграции Santizer API/Trusted Types все еще вырабатываются.

Заключение

В этой статье мы рассмотрели два новых API: Sanitizer и Trusted Types. Эти API очень важны для безопасности фронтенда, поскольку они представляют собой активную поддержку браузеров для санитизации, позволяя разработчикам, иметь больше обороны против атак.

PreviousТретья линия обороны против XSS - сокращение области воздействияNextОбход защитных мер - Обычные способы обхода CSP

Last updated 8 months ago

Этот вопрос также поднимался в . Самая большая проблема заключается в том, что, как только разрешены iframes и соблюдается предположение о "безопасности независимо от чего бы то ни было", есть много вещей, которые нужно принять во внимание.

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

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

Что насчет объединения его с Sanitizer API? Это возможно, и это также рекомендуется в :

Хотя эти два API еще не достигли зрелости, в не очень далеком будущем мы, возможно, увидим их постепенное становление основными. Некоторые фронтенд-фреймворки уже поспели за ними, такие как и , которые либо обсуждают, либо уже поддерживают Trusted Types.

Если вы хотите заранее попробовать Trusted Types в деле, вы можете использовать этот полифилл, предоставленный

Allow Embedding #124
Спецификация Sanitizer API
безопасной манипуляции с DOM с помощью Sanitizer API
официальной документации
Angular
Next.js
W3C