Что это значит, когда говорят, что React защищен от XSS?


110

Я прочитал это в руководстве по React. Что это значит?

React безопасен. Мы не генерируем строки HTML, поэтому по умолчанию используется защита XSS.

Как работают XSS-атаки, если React безопасен? Как достигается такая безопасность?

Ответы:


181

ReactJS вполне безопасен по конструкции, поскольку

  1. Строковые переменные в представлениях экранируются автоматически
  2. С JSX вы передаете функцию в качестве обработчика событий, а не строку, которая может содержать вредоносный код.

поэтому типичная атака, подобная этой, не будет работать

const username = "<img onerror='alert(\"Hacked!\")' src='invalid-image' />";

class UserProfilePage extends React.Component {
  render() {
    return (
      <h1> Hello {username}!</h1>
    );
  }
}

ReactDOM.render(<UserProfilePage />, document.querySelector("#app"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="app"></div>

но ...

❗❗❗Предупреждение❗❗❗

Есть еще несколько векторов XSS-атак, с которыми вам нужно справиться в React самостоятельно!

1. XSS через dangerouslySetInnerHTML

Когда вы используете, dangerouslySetInnerHTMLвам необходимо убедиться, что контент не содержит javascript. React здесь ничего не может сделать для вас.

const aboutUserText = "<img onerror='alert(\"Hacked!\");' src='invalid-image' />";

class AboutUserComponent extends React.Component {
  render() {
    return (
      <div dangerouslySetInnerHTML={{"__html": aboutUserText}} />
    );
  }
}

ReactDOM.render(<AboutUserComponent />, document.querySelector("#app"))
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="app"></div>

2. XSS через атрибут a.href

Пример 1: Использование javascript: code

Нажмите «Выполнить фрагмент кода» -> «Мой веб-сайт», чтобы увидеть результат.

const userWebsite = "javascript:alert('Hacked!');";

class UserProfilePage extends React.Component {
  render() {
    return (
      <a href={userWebsite}>My Website</a>
    )
  }
}

ReactDOM.render(<UserProfilePage />, document.querySelector("#app"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="app"></div>

Пример 2: Использование данных в кодировке base64:

Нажмите «Выполнить фрагмент кода» -> «Мой веб-сайт», чтобы увидеть результат.

const userWebsite = "data:text/html;base64,PHNjcmlwdD5hbGVydCgiSGFja2VkISIpOzwvc2NyaXB0Pg==";

class UserProfilePage extends React.Component {
  render() {
    const url = userWebsite.replace(/^(javascript\:)/, "");
    return (
      <a href={url}>My Website</a>
    )
  }
}

ReactDOM.render(<UserProfilePage />, document.querySelector("#app"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="app"></div>

3. XSS через реквизиты, контролируемые злоумышленником.

const customPropsControledByAttacker = {
  dangerouslySetInnerHTML: {
    "__html": "<img onerror='alert(\"Hacked!\");' src='invalid-image' />"
  }
};

class Divider extends React.Component {
  render() {
    return (
      <div {...customPropsControledByAttacker} />
    );
  }
}

ReactDOM.render(<Divider />, document.querySelector("#app"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="app"></div>

Вот еще ресурсы


13
Это потрясающий ответ! С фрагментами кода и ссылками в конце ...! Спасибо!
Иоанна

React позаботился о каком-либо из приведенных выше примеров с момента написания этого ответа? Я спрашиваю, так как я прочитал на следующем слайде: slideshare.net/kseniadmitrieva/… слайд № 20, что управляемый пользователем реквизит был исправлен в React 0.14 15 ноября '
omer

@omer нет, и response решил не заботиться об этих векторах атаки на уровне React. Вот несколько хороших комментариев, объясняющих, почему они не обрабатываются на уровне React github.com/facebook/react/issues/3473 ( github.com/facebook/react/issues/3473#issuecomment-91349525 , github.com/facebook/react / issues / 3473 # issuecomment-90594748 )
CyberPanda Consulting 02

1
@omer проблема, о которой вы говорите, была ошибкой безопасности, и она исправлена, но пункт 3, который я перечислил, не связан с этим, вы все равно можете проверить эту работу третьего пункта, выполнив мой код в любой версии реакции.
CyberPanda Consulting

60

React автоматически экранирует переменные для вас ... Он предотвращает внедрение XSS через строковый HTML с вредоносным Javascript .. Естественно, входные данные дезинфицируются вместе с этим.

Например, допустим, у вас есть эта строка

var htmlString = '<img src="javascript:alert('XSS!')" />';

если вы попытаетесь отобразить эту строку в реакции

render() {
    return (
        <div>{htmlString}</div>
    );
}

вы буквально увидите на странице всю строку, включая <span>тег элемента. иначе в браузере вы увидите<img src="javascript:alert('XSS!')" />

если вы посмотрите исходный html, вы увидите

<span>"<img src="javascript:alert('XSS!')" />"</span>

Вот еще несколько подробностей о том, что такое XSS-атака.

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


Редактировать:

Несколько замечаний, есть способы обойти то, чего избегает React. Еще один распространенный способ - это когда пользователи определяют свойства вашего компонента. Не расширяйте данные из пользовательского ввода как реквизиты!


13
Убегает от всего? В самом деле? React НЕ безопасен по умолчанию, есть много вещей, которые вам нужно делать вручную, и векторы атак, которые вы должны понимать. Все, что делает React, - это преобразует html в строку, когда вы пытаетесь вставить ее с помощью {html}. Но есть миллион других способов разрешить XSS, от которых React НЕ защищает. <a href="{...}" />, <img src = {...} />, <iframe src = "{...} /> и множество других свойств, которые позволяют внедрять исполняемый javascript. А еще есть инъекции CSS-скриптов с помощью style = {...} prop. Ответ @Marty Aghajanyan, приведенный ниже, на самом деле описывает возможные риски.
andree

@andree, спасибо, что указали на мою опечатку. Этому посту 3 года. Очевидно, есть способы обойти то, чего избегает React, и каждый разработчик должен устать от этого.
Джон Радделл

Спасибо за редактирование ответа @John Ruddell. Без обид, но ваш ответ сделал React более безопасным, чем он есть на самом деле, и, поскольку ваш ответ является одним из первых, которые возникают по этой теме, я просто хотел указать на это. К сожалению, это обычная тема, которую я вижу в общей безопасности внешнего интерфейса (а не только в React) - на первый взгляд все выглядит безопасным или легко защищаемым, но когда вы копаетесь, оказывается, что есть большие дыры. Основные вопросы безопасности должны иметь ответы, которые легко найти и где-то резюмированы, к сожалению, в последнее время я не сталкивался с этим.
andree

Что ж ... со временем документация выходит, поскольку безопасность проверяется. Ответы, которые когда-то были полезны, не так полезны. Сложная часть состоит в том, чтобы держать все ответы в курсе с меняющейся технологией
Джон Радделл
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.