Вы когда-нибудь слышали об XSS-атаках, связанных с внедрением (инъекцией) вредоносного кода в DOM (далее — DOM XSS)? Если не слышали, то


DOM XSS — это тип атаки на веб-приложение, когда хакер использует полезную нагрузку (payload), которая выполняется как результат модификации DOM в браузере.

Это может привести к тому, что на стороне клиента будет выполнен посторонний код. Таким образом, на стороне клиента появляется уязвимость безопасности. Злоумышленники используют объекты, позволяющие внедрять вредоносную полезную нагрузку. Вот почему такие атаки называются инъекциями.


Инъекции могут происходить разными способами, например:


  • через сеттеры для атрибутов Element, которые принимают URL со ссылкой на код для загрузки, например, HTMLScriptElement.src
  • через сеттеры для атрибутов Element, которые принимают код для выполнения, например, HTMLScriptElement.text
  • через функции, выполняющие код напрямую, такие как eval
  • через URL вида javascript:

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


Интерфейс доверенных типов


Команда Google Chrome представила Trusted Types API (далее — TTA) для решения данной проблемы. Основной причиной разработки названного интерфейса является увеличение количества XSS-уязвимостей, основанных на DOM, в сравнении с числом аналогичных уязвимостей на стороне сервера.


Это объясняется легкостью реализации и сложностью обнаружения `DOM XSS`.

Как доверенные типы предотвращают DOM XSS-атаки?


TTA позволяет устранить саму причину возникновения проблем, связанных с XSS.


По умолчанию DOM API не является безопасным. Вот несколько примеров:


eval('foo()');
document.createElement('div').innerHTML = '<foo>';
document.createElement('a').setAttribute('onclick'', 'foo()');

Во все эти сниппеты легко внедрить вредоносный скрипт или HTML.


Во избежание этого TTA позволяет установить HTTP-заголовок ответа Content-Security-Policy в значение trusted-types * для допуска только доверенных типов. Это делает веб-приложение безопасным по умолчанию посредством блокировки опасных инъекций.


Включить TTA можно одним из следующих способов:


Content-Security-Policy: trusted-types;
Content-Security-Policy: trusted-types 'none';
Content-Security-Policy: trusted-types <policyName>;
Content-Security-Policy: trusted-types <policyName> <policyName> 'allow-duplicates';

Директива trusted-types предписывает браузеру создавать неподдающиеся подделке типизированные значения для передачи в приемники данных (sink) DOM вместо строк.


Основная идея заключается в передаче специальных объектов вместо строк. DOM поддерживает такую передачу.


elem.innerHTML = { toString: function() { return "Привет, народ" }};
elem.innerHTML // возвращается "Привет, народ"

`TTA` рекомендует передавать типизированные объекты вместо обычных `JS-объектов`.

Это позволяет приемникам DOM отклонять строки и принимать только совпадающие (matching) типы.


Использование доверенных типов


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


Проверка уязвимостей


Для выполнения такой проверки добавьте следующий заголовок ответа:


Content-Security-Policy-Report-Only: require-trusted-types-for 'script'; report-uri //mysite.com/cspViolations

После этого все нарушения будут отправлены на //mysite.com/cspViolations. Это не повлияет на функциональность приложения.


Отчет о нарушениях


При обнаружении нарушения доверенных типов, будет отправлен отчет, настроенный с помощью report-uri. Например, если в нашем коде имеется innerHTML, отчет будет выглядеть примерно так:


{
  "csp-report": {
    "document-uri": "https://mysite.com",
    "violated-directive": "require-trusted-types-for",
    "disposition": "report",
    "blocked-uri": "trusted-types-sink",
    "line-number": 20,
    "column-number": 12,
    "source-file": "https://mysite.com/dashboard.js",
    "status-code": 0,
    "script-sample": "Element innerHTML <img src=x"
  }
}

Это помогает определить, какие строки кода и в каком файле подвержены DOM XSS-атакам.


Устранение нарушений


Существует несколько способов устранения нарушений доверенных типов. Рассмотрим некоторые из них.


  1. Изменение кода, содержащего уязвимость

Например, код el.innerHTML = '<img src=xyz.jpg>' может быть переписан следующим образом:


el.textContent = '';
const img = document.createElement('img');
img.src = 'xyz.jpg';
el.appendChild(img);

  1. Использование библиотеки

Такие библиотеки, как DOMPurify могут использоваться для санитизации (обеззараживания, обезвреживания) HTML путем оборачивания разметки в объект TrustedHTML.


  1. Создание политики доверенных типов

Вместо использования библиотеки или удаления "опасного" кода, можно самостоятельно создать объект доверенных типов. Политики доверенных типов применяют правила безопасности к входным данным.


  • Шаг 1 — создание политики

if (window.trustedTypes && trustedTypes.createPolicy) {
  const escapeHTMLPolicy = trustedTypes.createPolicy('escapePolicy',    
  {
    createHTML: string => string.replace(/\</g, '&lt;')
  });
}

Данное правило будет заменять все символы < во избежание создания новых HTML-элементов, возвращая объект политики, содержащий значение правильного типа, в данном случае TrustedHTML.


  • Шаг 2 — использование политики

const escaped = escapeHTMLPolicy.createHTML('<img src=x onerror=alert(1)>');
console.log(escaped instanceof TrustedHTML);  // true
el.innerHTML = escaped;  // '&lt;img src=x onerror=alert(1)>'

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


if (window.trustedTypes && trustedTypes.createPolicy) {
  trustedTypes.createPolicy('default', {
    createHTML: (string, sink) => DOMPurify.sanitize(string, { RETURN_TRUSTED_TYPE: true })
  });
}

После устранения всех нарушений применение доверенных типов можно включить так:


Content-Security-Policy: require-trusted-types-for 'script'; report-uri //mysite.com/cspViolations

Обратите внимание на отсутствие префикса -Report-Only по сранению с предыдущим примером.


В данном разделе мы рассмотрели разрешение только тех нарушений, которые связанны с HTML. Однако, TTA позволяет определять нарушения и применять правила к:


  • HTML
  • Script
  • URL
  • ScriptURL

Дополнительную информацию об этом можно получить здесь.


Преимущества использования доверенных типов


Ниже представлен список преимуществ, предоставляемых использованием доверенных типов в приложении:


  • уменьшение поверхности для атаки — приложение становится более безопасным
  • проверка безопасности приложения, выполняемая во время компиляции и выполнения кода
  • обратная совместимость — возможность использования доверенных типов вместо строк
  • реализация других решений, связанных с безопасностью, таких как CSP для защиты от XSS на сервере

Поддержка


К сожалению, поддержка TTA браузерами оставляет желать лучшего. Будем надеяться, что это скоро изменится.



Заключение


В настоящее время XSS-атаки, связанные с внедрением вредоносного кода в DOM, являются очень распространенными и их количество растет с каждым днем. Обнаружение таких уязвимостей — задача не из легких.


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


Если вас интересуют другие аспекты рассмотренной темы, то вот еще одна статья, посвященная TTA.




Аренда VDS-сервера с быстрыми NVMе-дисками и посуточной оплатой. Загрузка своего ISO.


Комментарии (0)