Що це означає, коли кажуть, що React захищений XSS?


109

Я прочитав це у підручнику React. Що це означає?

Реагуйте безпечно. Ми не генеруємо рядки HTML, тому захист XSS є типовим.

Як працюють атаки XSS, якщо React безпечний? Як досягається така безпека?

Відповіді:


179

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 ні, і, реагуючи, вирішив не піклуватися про ці вектори атак на рівні 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>тег елемента. aka у браузері, який ви побачите<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 через prop = {...} prop. Відповідь нижче від @Marty Aghajanyan насправді окреслює можливі ризики.
andree

@andree дякую, що вказав мою помилку. Це 3-річний пост. Очевидно, що є способи обійти те, що уникне React, і кожен розробник повинен це втомитися.
Джон Радделл,

Дякуємо за редагування Вашої відповіді @ John Ruddell. Не ображайтесь, але ваша відповідь зробила React більш безпечним, ніж є насправді, і оскільки ваша відповідь одна з перших, що з’являється на цю тему, я просто хотів зазначити це. На жаль, це загальна тема, яку я бачу в загальній безпеці інтерфейсу (а не лише у реагуванні) - речі виглядають безпечними або легко захищаються на поверхні, але коли ви зариваєтесь, виявляється, є великі діри. Основні питання безпеки повинні мати відповіді, які легко знайти, десь коротко викласти, на жаль, останнім часом це не мій досвід.
andree

Ну .. з часом документація виходить, коли перевіряється безпека. Відповіді, які ми колись допомогли, не такі корисні.
Важливим
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.