Qu'est-ce que cela signifie quand ils disent que React est protégé par XSS?

109

J'ai lu ceci sur le tutoriel React. Qu'est-ce que ça veut dire?

React est sûr. Nous ne générons pas de chaînes HTML, la protection XSS est donc la valeur par défaut.

Comment fonctionnent les attaques XSS si React est sûr? Comment cette sécurité est-elle assurée?

user1210233
la source

Réponses:

179

ReactJS est assez sûr de par sa conception depuis

  1. Les variables de chaîne dans les vues sont automatiquement échappées
  2. Avec JSX, vous passez une fonction en tant que gestionnaire d'événements, plutôt qu'une chaîne pouvant contenir du code malveillant

donc une attaque typique comme celle-ci ne fonctionnera pas

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>

mais ...

❗❗❗Avertissement❗❗❗

Il y a encore des vecteurs d'attaque XSS que vous devez gérer vous-même dans React!

1. XSS via dangerouslySetInnerHTML

Lorsque vous utilisez, dangerouslySetInnerHTMLvous devez vous assurer que le contenu ne contient pas de javascript. React ne peut rien faire ici pour vous.

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 via un attribut.href

Exemple 1: utilisation de javascript: code

Cliquez sur "Exécuter l'extrait de code" -> "Mon site Web" pour voir le résultat

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>

Exemple 2: Utilisation de données encodées en base64:

Cliquez sur "Exécuter l'extrait de code" -> "Mon site Web" pour voir le résultat

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 via des accessoires contrôlés par l'attaquant

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>

Voici plus de ressources

Conseil CyberPanda
la source
13
Cette réponse est incroyable! Avec les extraits de code et les références à la fin ...! Je vous remercie!
Ioanna
L'un des exemples ci-dessus a-t-il été pris en charge par React depuis que cette réponse a été écrite? Je demande, depuis que j'ai lu dans les diapositives suivantes: slideshare.net/kseniadmitrieva/ ... slide # 20 que les accessoires contrôlés par l'utilisateur ont été corrigés dans React 0.14 en novembre 15 '
omer
@omer no, et react a décidé de ne pas prendre en charge ces vecteurs d'attaque au niveau React. Voici quelques bons commentaires, expliquant pourquoi ils ne sont pas gérés au niveau 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
1
@omer le problème que vous faites référence était un bogue de sécurité et il a été corrigé, mais le point 3 que j'ai listé n'est pas lié à celui-là, vous pouvez toujours vérifier ce 3ème point de travail en exécutant mon code sous n'importe quelle version de réaction.
CyberPanda Consulting
60

React échappe automatiquement les variables pour vous ... Il empêche l'injection XSS via une chaîne HTML avec Javascript malveillant .. Naturellement, les entrées sont nettoyées avec cela.

Par exemple, disons que vous avez cette chaîne

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

si vous essayez de rendre cette chaîne en react

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

vous verrez littéralement sur la page toute la chaîne, y compris la <span>balise d'élément. aka dans le navigateur, vous verrez<img src="javascript:alert('XSS!')" />

si vous affichez le code source html, vous verriez

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

Voici quelques détails supplémentaires sur ce qu'est une attaque XSS

React fait que vous ne pouvez pas insérer de balisage à moins que vous ne créiez les éléments vous-même dans la fonction de rendu ... cela étant dit, ils ont une fonction qui permet un tel rendu, c'est appelé dangerouslySetInnerHTML... voici plus de détails à ce sujet


Éditer:

Peu de choses à noter, il existe des moyens de contourner ce que React échappe. Une méthode plus courante consiste à définir des accessoires pour votre composant. N'étendez pas les données de l'entrée utilisateur comme accessoires!

John Ruddell
la source
13
Échappe à tout? Vraiment? React n'est PAS sûr par défaut, il y a beaucoup de choses que vous devez faire manuellement et d'attaquer les vecteurs que vous devez comprendre. Tout ce que React fait, c'est échapper le code HTML à une chaîne lorsque vous essayez de l'insérer avec {html}. Mais il existe un million d'autres façons d'autoriser XSS, contre lesquelles React ne protège PAS. <a href="{...}" />, <img src = {...} />, <iframe src = "{...} /> et une tonne d'autres accessoires qui permettent d'injecter du javascript exécutable. Et puis il y a des injections de scripts CSS via style = {...} prop. La réponse ci-dessous par @Marty Aghajanyan décrit en fait les risques possibles.
andree
@andree merci d'avoir signalé ma faute de frappe. C'est un poste vieux de 3 ans. De toute évidence, il existe des moyens de contourner ce que React échappe et chaque développeur devrait en avoir assez.
John Ruddell
Merci d'avoir édité votre réponse @John Ruddell. Aucune offense, mais votre réponse a rendu React plus sûr qu'il ne l'est en réalité, et comme votre réponse est l'une des premières à aborder le sujet, je voulais juste le souligner. Malheureusement, c'est un thème commun que je vois dans la sécurité globale du frontend (pas seulement React) - les choses semblent sécurisées ou facilement sécurisables en surface, mais lorsque vous creusez, il s'avère qu'il y a de gros trous. Les questions de sécurité de base devraient avoir des réponses faciles à trouver qui sont résumées quelque part, malheureusement ce n'est pas mon expérience ces derniers temps.
andree
Eh bien ... au fil du temps, la documentation sort au fur et à mesure des tests de sécurité. Les réponses que nous avons une fois utiles ne sont pas aussi utiles. La partie difficile est de garder toutes les réponses à jour avec l'évolution de la technologie
John Ruddell