Що це означає, коли кажуть, що 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.