XSS защита

Основы XSS

Cross-Site Scripting (XSS) представляет собой тип уязвимости, при котором злоумышленник внедряет вредоносный скрипт в веб-приложение. В контексте Stencil, как и других фреймворков на JavaScript, защита от XSS особенно важна, так как компонентная архитектура активно работает с DOM и часто использует динамическое рендеринг-содержимое. XSS-атаки могут привести к краже сессий, изменению данных на клиенте или внедрению вредоносного кода.

Автоматическая защита через JSX

Stencil использует JSX для описания компонентов, что обеспечивает встроенную защиту от XSS при стандартной вставке данных. Все выражения в JSX, такие как:

render() {
  return <div>{this.userInput}</div>;
}

автоматически экранируются. Это значит, что специальные символы HTML (<, >, &, ", ') преобразуются в безопасные сущности, предотвращая выполнение произвольного JavaScript-кода.

Прямое управление innerHTML

Использование innerHTML или dangerouslySetInnerHTML обходят автоматическую экранизацию, что делает их потенциально опасными:

render() {
  return <div innerHTML={this.userInput}></div>;
}

Чтобы безопасно работать с динамическим HTML:

  1. Проверять и фильтровать контент с помощью специализированных библиотек, например DOMPurify.
  2. Ограничивать источник данных, гарантируя доверенность контента.
  3. Избегать вставки данных, введённых пользователями, без предварительной обработки.

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

import DOMPurify from 'dompurify';

render() {
  const safeHTML = DOMPurify.sanitize(this.userInput);
  return <div innerHTML={safeHTML}></div>;
}

Санитизация и валидация данных

Санитизация — процесс удаления или преобразования небезопасных элементов в данных, а валидация — проверка соответствия данных допустимым форматом. В Stencil рекомендуется:

  • Валидировать все входные данные на уровне компонентов.
  • Использовать строгие типы для пропсов и состояния компонентов.
  • Ограничивать формат HTML и атрибутов, если необходимо динамическое рендеринг-содержимое.

Пример валидации строкового пропса:

@Component({
  tag: 'safe-message',
  shadow: true
})
export class SafeMessage {
  @Prop() text: string;

  render() {
    const sanitizedText = this.text.replace(/</g, '&lt;').replace(/>/g, '&gt;');
    return <p>{sanitizedText}</p>;
  }
}

Shadow DOM и XSS

Использование Shadow DOM в Stencil создаёт изолированное дерево DOM для компонентов, что затрудняет внедрение скриптов извне, но не заменяет полноценную санитизацию. Любой контент, передаваемый через свойства или атрибуты, должен быть обработан и экранирован, так как Shadow DOM защищает только от внешнего CSS и DOM-перезаписи, но не предотвращает выполнение скриптов, вставленных внутрь компонента.

Рекомендации по безопасному кодированию

  • Никогда не доверять данным от пользователя и внешним API.
  • Использовать JSX-выражения вместо innerHTML, когда это возможно.
  • Применять библиотеки для санитизации HTML.
  • Проверять все динамически создаваемые атрибуты и ссылки на предмет внедрения скриптов.
  • Проводить аудит компонентов, особенно при использовании сторонних библиотек, генерирующих HTML.

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

  1. Текстовые данные:
render() {
  return <span>{this.dynamicText}</span>;
}
  1. HTML с фильтрацией:
render() {
  const safeContent = DOMPurify.sanitize(this.htmlContent);
  return <div innerHTML={safeContent}></div>;
}
  1. Атрибуты с проверкой:
render() {
  const safeUrl = encodeURI(this.url);
  return <a href={safeUrl}>Ссылка</a>;
}

Эти практики минимизируют риск XSS и обеспечивают высокий уровень безопасности в приложениях на Stencil.