Was bedeutet es, wenn sie sagen, dass React XSS-geschützt ist?

108

Ich habe dies im React-Tutorial gelesen. Was bedeutet das?

Reaktion ist sicher. Wir generieren keine HTML-Zeichenfolgen, daher ist der XSS-Schutz die Standardeinstellung.

Wie funktionieren XSS-Angriffe, wenn React sicher ist? Wie wird diese Sicherheit erreicht?

user1210233
quelle

Antworten:

175

ReactJS ist seitdem von Natur aus ziemlich sicher

  1. Zeichenfolgenvariablen in Ansichten werden automatisch maskiert
  2. Mit JSX übergeben Sie eine Funktion als Ereignishandler anstelle einer Zeichenfolge, die schädlichen Code enthalten kann

Ein typischer Angriff wie dieser funktioniert also nicht

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>

aber ...

"Warnung"

Es gibt noch einige XSS-Angriffsvektoren, die Sie in React!

1. XSS über dangerouslySetInnerHTML

Wenn Sie verwenden dangerouslySetInnerHTML, müssen Sie sicherstellen, dass der Inhalt kein Javascript enthält. React kann hier nichts für dich tun.

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 über ein a.href-Attribut

Beispiel 1: Verwenden von Javascript: Code

Klicken Sie auf "Code-Snippet ausführen" -> "Meine Website", um das Ergebnis anzuzeigen

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>

Beispiel 2: Verwenden von base64-codierten Daten:

Klicken Sie auf "Code-Snippet ausführen" -> "Meine Website", um das Ergebnis anzuzeigen

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 über vom Angreifer kontrollierte Requisiten

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>

Hier finden Sie weitere Ressourcen

CyberPanda-Beratung
quelle
13
Diese Antwort ist unglaublich! Mit den Codefragmenten und den Referenzen am Ende ...! Danke dir!
Ioanna
Wurde eines der obigen Beispiele von React behoben, seit diese Antwort geschrieben wurde? Ich frage, da ich in der folgenden Folie gelesen habe: slidehare.net/kseniadmitrieva/… Folie Nr. 20, dass benutzergesteuerte Requisiten in React
0.14
@omer nein, und reagieren entschieden, sich nicht um diese Angriffsvektoren im React-Level zu kümmern. Hier sind einige gute Kommentare, die erklären, warum sie nicht in React Level github.com/facebook/react/issues/3473 ( github.com/facebook/react/issues/3473#issuecomment-91349525 , github.com/facebook/react) behandelt werden / Issues / 3473 # issuecomment-90594748 )
CyberPanda Consulting
1
@omer das Problem, auf das Sie sich beziehen, war ein Sicherheitsfehler und es wurde behoben, aber der Punkt 3, den ich aufgelistet habe, hängt nicht mit diesem zusammen. Sie können diese 3. Punktarbeit trotzdem überprüfen, indem Sie meinen Code unter einer beliebigen Reaktionsversion ausführen.
CyberPanda Consulting
59

React entgeht automatisch Variablen für Sie ... Es verhindert die XSS-Injektion über String-HTML mit bösartigem Javascript. Natürlich werden Eingaben zusammen mit diesem bereinigt.

Nehmen wir zum Beispiel an, Sie haben diese Zeichenfolge

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

Wenn Sie versuchen, diese Zeichenfolge in Reaktion zu rendern

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

Sie sehen buchstäblich auf der Seite die gesamte Zeichenfolge einschließlich des <span>Element-Tags. aka im Browser sehen Sie<img src="javascript:alert('XSS!')" />

Wenn Sie die Quell-HTML anzeigen, würden Sie sehen

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

Hier finden Sie weitere Informationen zu einem XSS-Angriff

Reagieren im Grunde macht es so dass Sie nicht einfügen Markup können , wenn Sie die Elemente sich in der Funktion machen schaffen ... sagte , dass Wesen sie habe eine Funktion , die so erlaubt Rendering seine genannte dangerouslySetInnerHTML... hier ist etwas ausführlicher darüber


Bearbeiten:

Nur wenige Dinge zu beachten, es gibt Möglichkeiten, um zu umgehen, was React entgeht. Eine weitere Möglichkeit besteht darin, dass Benutzer Requisiten für Ihre Komponente definieren. Erweitern Sie keine Daten aus Benutzereingaben als Requisiten!

John Ruddell
quelle
13
Entkommt alles? "Ja wirklich?" Reagieren ist standardmäßig NICHT sicher. Es gibt eine Menge Dinge, die Sie manuell tun und Vektoren angreifen müssen, die Sie verstehen müssen. Alles, was React tut, ist, HTML in einen String zu maskieren, wenn Sie versuchen, es mit {html} einzufügen. Es gibt jedoch eine Million anderer Möglichkeiten, XSS zuzulassen, gegen die React NICHT schützt. <a href="{...}" />, <img src = {...} />, <iframe src = "{...} /> und jede Menge anderer Requisiten, mit denen ausführbares Javascript eingefügt werden kann. Und dann gibt es CSS-Skript-Injektionen durch style = {...} prop. Die Antwort unten von @Marty Aghajanyan beschreibt tatsächlich die möglichen Risiken.
andree
@andree danke für den Hinweis auf meinen Tippfehler. Es ist ein 3 Jahre alter Beitrag. Offensichtlich gibt es Möglichkeiten, um zu umgehen, was React entgeht, und jeder Entwickler sollte es leid sein.
John Ruddell
Vielen Dank für die Bearbeitung Ihrer Antwort @John Ruddell. Nichts für ungut, aber Ihre Antwort hat dazu geführt, dass React sicherer aussieht als es tatsächlich ist, und da Ihre Antwort eine der ersten ist, die zu diesem Thema auftaucht, wollte ich nur darauf hinweisen. Leider ist dies ein häufiges Thema, das ich in der allgemeinen Sicherheit des Frontends (nicht nur der Reaktion) sehe - die Dinge sehen an der Oberfläche sicher oder leicht zu sichern aus, aber wenn Sie sich einarbeiten, stellt sich heraus, dass es große Löcher gibt. Grundlegende Sicherheitsfragen sollten leicht zu findende Antworten enthalten, die irgendwo zusammengefasst sind. Leider ist dies in letzter Zeit nicht meine Erfahrung.
andree
Nun ... im Laufe der Zeit wird die Dokumentation veröffentlicht, während die Sicherheit getestet wird. Antworten, die wir einmal hilfreich waren, sind nicht so hilfreich. Der schwierige Teil ist es, alle Antworten mit der sich ändernden Technologie auf dem neuesten Stand zu halten
John Ruddell