Защита от инъекций кода

Riot.js — это современный JavaScript-фреймворк, ориентированный на компонентную архитектуру и реактивное обновление интерфейса. Несмотря на упрощённый синтаксис и мощные инструменты, приложения на Riot.js подвержены классическим веб-угрозам, включая инъекции кода. Понимание механизмов защиты критически важно для создания безопасных интерфейсов.


Природа инъекций кода

Инъекции кода возникают, когда пользовательский ввод интерпретируется браузером как исполняемый код. В контексте Riot.js это может проявляться в нескольких формах:

  1. HTML-инъекции (XSS) Возникают, когда небезопасные строки вставляются в DOM с помощью innerHTML или директив, которые рендерят сырой HTML.

  2. JavaScript-инъекции Происходят при динамическом формировании скриптов из пользовательских данных.

  3. Стили и атрибуты В редких случаях атаки могут использовать небезопасные значения для атрибутов style, src, href или on* обработчиков событий.


Безопасная вставка данных

Riot.js предоставляет реактивное связывание данных через фигурные скобки {}. Важно помнить, что:

  • { expression } — вставляет значение безопасно, экранируя HTML-сущности.
  • {@html expression} — вставляет HTML как есть, что делает приложение уязвимым, если expression содержит пользовательский ввод.

Пример безопасного связывания:

<p>{ userInput }</p>

Даже если userInput содержит <script>alert('XSS')</script>, браузер отобразит текст как строку, а не выполнит скрипт.

Опасный вариант:

<p>{@html userInput}</p>

Если userInput приходит от пользователя, злоумышленник может выполнить произвольный JavaScript.


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

Для предотвращения XSS рекомендуется:

  1. Использовать встроенное связывание {} для всех пользовательских данных.
  2. Избегать @html для данных, которые не прошли проверку.
  3. Применять сторонние библиотеки для безопасного рендеринга HTML, например DOMPurify:
import DOMPurify from 'dompurify';

<p>{@html DOMPurify.sanitize(userInput)}</p>

DOMPurify удаляет скрипты, вредоносные атрибуты и обеспечивает безопасное отображение HTML.


Безопасное связывание атрибутов

Riot.js позволяет динамически задавать атрибуты компонентов:

<img src={ imageUrl } alt="Image">

Важно убедиться, что imageUrl не содержит опасных схем вроде jav * ascript:. Для этого выполняются проверки:

function sanitizeUrl(url) {
  const allowed = /^https?:\/\//i;
  return allowed.test(url) ? url : '';
}

Работа с событиями

Динамические обработчики событий (onclick, oninput) в Riot.js должны использовать реактивные функции, а не формировать строки с кодом.

Правильно:

<button oncl ick={ handleClick }>Click</button>

<script>
  export default {
    handleClick() {
      console.log('Button clicked');
    }
  }
</script>

Неправильно:

<button oncl ick="{ 'alert(' + userInput + ')' }">Click</button>

Такой подход открывает дверь для JavaScript-инъекций.


Контроль над вводом

Дополнительно стоит применять следующие меры:

  • Валидация и фильтрация данных на клиенте и сервере: проверка форматов, длины и допустимых символов.
  • Ограничение доверенных источников для внешних ресурсов: использование Content Security Policy (CSP) для блокировки небезопасных скриптов.
  • Минимизация использования @html и динамических скриптов: даже при фильтрации HTML полностью исключить использование eval и подобных функций.

Пример безопасного компонента

<user-profile>
  <h2>{ name }</h2>
  <p>{@html DOMPurify.sanitize(description)}</p>
  <img src={ sanitizeUrl(avatarUrl) } alt="Avatar">
  
  <button oncl ick={ updateProfile }>Update</button>

  <script>
    import DOMPurify from 'dompurify';

    export default {
      name: 'John Doe',
      description: '<p>Hello!</p>',
      avatarUrl: 'https://example.com/avatar.jpg',
      updateProfile() {
        console.log('Profile updated');
      }
    }

    function sanitizeUrl(url) {
      const allowed = /^https?:\/\//i;
      return allowed.test(url) ? url : '';
    }
  </script>
</user-profile>

В этом компоненте:

  • Пользовательские данные безопасно отображаются через {} или через DOMPurify.
  • Все события обрабатываются через методы, без динамического исполнения кода.
  • Атрибуты проверяются перед вставкой в DOM.

Практические рекомендации

  • Всегда использовать фигурные скобки {} для текстового вывода.
  • @html применять только к проверенному и санитизированному контенту.
  • Проверять URL и другие внешние данные перед применением.
  • Не строить динамические строки для событий и скриптов.
  • Рассматривать внедрение CSP для дополнительного уровня защиты.

Эти принципы позволяют строить компоненты на Riot.js с минимальным риском XSS и других инъекций кода, обеспечивая надежность и безопасность веб-приложений.