Die Autorin des Artikels, dessen Übersetzung wir heute veröffentlichen, sagt, dass React ihre Lieblingsbibliothek für die Erstellung interaktiver Schnittstellen ist. React ist sowohl einfach zu bedienen als auch ziemlich gut geschützt. Dies bedeutet jedoch nicht, dass React-Anwendungen vollständig unverwundbar sind. Es ist sehr leicht, in ungerechtfertigte Ruhe zu geraten, nachdem Sie entschieden haben, dass Sie sich keine Sorgen über XSS-Angriffe machen können, da das Projekt React verwendet.
Sicherheitslücken in React treten am häufigsten auf, wenn ein Entwickler glaubt, die Schutzmechanismen dieser Bibliothek zu verwenden, obwohl sich herausstellt, dass dies nicht der Fall ist. Daher ist es wichtig, die Funktionen von React richtig zu bewerten und zu wissen, welche Aufgaben ein Programmierer selbst lösen muss.

Heute werden wir über typische React-Schwachstellen sprechen, wie man sie während einer Codeüberprüfung findet und wie man sich gegen sie verteidigt.
Erstes (sehr kurzes) Cross-Site-Scripting-Beispiel
Cross Site Scripting (XSS) ist eine Client-Sicherheitsanfälligkeit, die zu schwerwiegenden Problemen führen kann. XSS-Angriffe treten auf, wenn ein Angreifer eine Website austricksen und dazu zwingen kann, beliebigen JavaScript-Code in den Browsern seiner Benutzer auszuführen.
Der reflektierte XSS-Angriff wird über einen Link ausgeführt, der Textinformationen enthält, die vom Browser in Form von Code verarbeitet werden. Dies ist beispielsweise ein Formularfeld, in das auf der Clientseite ein spezieller Anforderungstext eingegeben wird.
Ein gespeicherter XSS-Angriff ist eine Situation, in der ein Angreifer Zugriff auf den Server hat und wenn der auf dem Server ausgeführte Code generiert, was auf die Webseite des Clients gelangt. Typische Vektoren solcher Angriffe sind das Hochladen von Kommentaren und Bildern auf Server.
Samy Wurm hat die Sicherheitsanfälligkeit in MySSpace XSS ausgenutzt. Es war eines der am schnellsten verbreiteten Viren aller Zeiten.
Anfällige Websites können ihre Benutzer dem Diebstahl von Passwörtern oder persönlichen Daten aussetzen. Und dies ist die übliche Art, andere Schwachstellen auszunutzen. Schädliche Skripte werden am häufigsten verwendet, um Spam zu senden und Benutzer auf betrügerische Websites umzuleiten. Dies kann den Ruf und die SEO-Leistung einer erfolgreich angegriffenen Website beeinträchtigen.
Sicherheitsanfälligkeit Nr. 1: Kontrolle über den Anfangszustand der Seite, der beim Rendern des Servers verwendet wird
Wenn wir den Anfangszustand einer Seite bilden, erstellen wir manchmal, was gefährlich ist, ein Dokument basierend auf einer JSON-Zeichenfolge. Diese Sicherheitsanfälligkeit im Code sieht ungefähr so aus:
<script>window.__STATE__ = ${JSON.stringify({ data })}</script>
Dies ist gefährlich, da die
JSON.stringify()
-Methode, ohne an etwas zu „denken“, alle ihr bereitgestellten Daten in Zeichenfolgenform konvertiert (sofern es sich um gültige JSON-Daten handelt) wird auf der Seite angezeigt. Wenn
{ data }
Felder enthält, die ein nicht vertrauenswürdiger Benutzer bearbeiten kann, z. B. einen Benutzernamen oder Benutzerinformationen, kann Folgendes in solche Felder eingebettet werden:
{ username: "pwned", bio: "</script><script>alert('XSS Vulnerability!')</script>" }
Dieses Muster wird häufig beim serverseitigen Rendern von React-Anwendungen verwendet, die Redux verwenden. Er war in der offiziellen Redux-Dokumentation vertreten, weshalb viele Tutorials und Beispielanwendungsvorlagen, die auf GitHub zu finden sind, diese weiterhin verwenden.
Glaubst du nicht? Dann überzeugen Sie sich selbst. Durchsuchen Sie Google nach dem Text "Reagieren Sie auf einer serverseitigen Rendering-Beispiel-App" und versuchen Sie diesen Angriff auf eines der Suchergebnisse auf der ersten Seite.
▍ Identifizierung der Sicherheitsanfälligkeit während der Codeüberprüfung
Suchen Sie nach Aufrufen der
JSON.stringify()
-Methode, die Variablen akzeptieren, die möglicherweise nicht vertrauenswürdige Daten im
script
Tag enthalten. Hier ist ein Beispiel, das früher in der Redux-Dokumentation enthalten war:
function renderFullPage(html, preloadedState) { return ` <!doctype html> <html> <head> <title>Redux Universal Example</title> </head> <body> <div id="root">${html}</div> <script> window.__PRELOADED_STATE__ = ${JSON.stringify(preloadedState)} </script> <script src="/static/bundle.js"></script> </body> </html> ` }
Und hier ist ein Teil des Codes aus der Beispielanwendung auf GitHub:
function htmlTemplate( reactDom, reduxState, helmetData ) { return ` <!DOCTYPE html> <html> <head> <meta charset="utf-8"> ${ helmetData.title.toString( ) } ${ helmetData.meta.toString( ) } <title>React SSR</title> <link rel="stylesheet" type="text/css" href="./styles.css" /> </head> <body> <div id="app">${ reactDom }</div> <script> window.REDUX_DATA = ${ JSON.stringify( reduxState ) } </script> <script src="./app.bundle.js"></script> </body> </html> `; }
Manchmal ist es etwas schwieriger, diese Sicherheitsanfälligkeit zu finden. Der folgende Code wird sich ebenfalls als unsicher herausstellen - wenn das korrekte
context.data
von
context.data
nicht ausgeführt wird:
const RenderedApp = htmlData.replace('{{SSR}}', markup) .replace('<meta-head/>', headMarkup) .replace('{{data}}', new ArrayBuffer(JSON.stringify(context.data)).toString('base64'))
Achten Sie beim serverseitigen Rendern darauf, was genau gerendert wird. Wenn das, was der Benutzer eingibt, nicht ordnungsgemäß abgeschirmt und im DOM angezeigt wird, kann dies gefährlich sein.
▍ Schutz
Eine der Optionen zum Schutz vor dieser Sicherheitsanfälligkeit ist die Verwendung des
serialize-javascript
PMM-Moduls, das den JSON-Ausgang abschirmt. Wenn Sie das Server-Rendering in einer Umgebung ausführen, die nicht von Node.js stammt, müssen Sie das für Ihre Sprache geeignete Paket auswählen.
Hier ist der Befehl zum Installieren des Moduls:
$ npm install --save serialize-javascript
Danach müssen Sie es in eine Datei importieren und zuvor anfälligen Code für
window
folgt neu schreiben:
<script>window.__STATE__ = ${ serialize( data, { isJSON: true } ) }</script>
Hier ist ein großartiger Artikel zu diesem Thema.
Sicherheitslücke №2: heimtückische Links
Das
<a>
-Tag kann das
href
Attribut haben, das einen Link zu einer anderen Seite der Site, zu einer anderen Site oder zu einer Stelle auf der aktuellen Seite enthält. Links können Skripte enthalten, die ungefähr so aussehen:
javascript: stuff()
. Wenn Sie diese HTML-Funktion nicht kennen, probieren Sie sie jetzt aus, indem Sie den folgenden Code in die Browserzeile kopieren:
data:text/html, <a href="javascript: alert('hello from javascript!')" >click me</a>
Für Webentwickler bedeutet dies, dass der Angreifer diesen Daten schädlichen Code hinzufügen kann, der mit
javascript:
beginnt, wenn der Inhalt von Links auf der Grundlage der vom Benutzer eingegebenen Daten festgelegt wird. Wenn der Benutzer dann auf einen fehlerhaften Link klickt, wird im Browser ein Angreiferskript gestartet.
Diese Sicherheitsanfälligkeit ist definitiv nicht nur für React charakteristisch, sondern auch eines der Probleme, auf die React-Entwickler häufig stoßen, wenn sie erwarten, dass der entsprechende Wert automatisch korrekt maskiert wird. Es sollte beachtet werden, dass dieses Problem in einer
zukünftigen Version von React weniger akut sein wird.
▍ Identifizierung der Sicherheitsanfälligkeit während der Codeüberprüfung
Können Projektbenutzer Links zu Seiten hinzufügen, auf die andere Benutzer klicken können? Wenn ja, fügen Sie der Seite einen „Link“ wie folgt hinzu:
javascript: alert("You are vulnerable to XSS!")
Wenn das entsprechende Meldungsfeld durch Klicken auf den Link angezeigt wird, bedeutet dies, dass das Projekt für XSS-Angriffe anfällig ist. Versuchen Sie dies überall dort, wo Sie Links hinzufügen können. Es ist wahrscheinlich, dass nicht alle diese Orte anfällig sind.
▍ Schutz
Der Schutz vor dieser Sicherheitsanfälligkeit eignet sich nicht nur für React-Projekte. Was genau getan werden muss, hängt von der Anwendung ab. Darüber hinaus müssen Sie möglicherweise Korrekturen am Server vornehmen.
Sie könnten denken, dass es zur Lösung des Problems ausreicht, das Präfix
javascript:
aus den Daten zu entfernen. Dies ist ein Beispiel für die Verwendung der Blacklist-Strategie, die beim
Bereinigen von Daten nicht als erfolgreich angesehen werden
kann . Hacker haben geniale Möglichkeiten, solche Filter zu umgehen. Stellen Sie daher anstelle einer solchen Verschiebung (oder zusätzlich dazu) sicher, dass die Links ein Protokoll auf der Whitelist verwenden (z. B.
http:
und HTML-Entitäten maskieren.
Hier ist ein ausführlicher Artikel zu diesem Thema über die Abschirmung von Eigenschaften, die ein Angreifer kontrollieren kann.
Eine weitere Strategie, die dem Projekt eine zusätzliche Schutzstufe hinzufügen kann, besteht darin, den Mechanismus zum Öffnen benutzerdefinierter Links in neuen Browser-Registerkarten zu verwenden. Ich würde jedoch nicht empfehlen, diese Strategie als einzige "Verteidigungslinie" des Projekts zu verwenden. Öffnen von
javascript:
Links in einer neuen Registerkarte sind ein Beispiel für das nicht standardmäßige Verhalten von Seitenelementen. Die meisten Browser führen das Skript in einem leeren Tab aus, ohne den Benutzer zu verletzen. Dies ist jedoch nicht garantiert, und Sie können dies wahrscheinlich umgehen, was vom Browser abhängt.
Erwägen Sie die Verwendung der speziellen
UserLink- Komponente, die dazu führt, dass das anfällige
<a>
-Tag in Zukunft weniger wahrscheinlich auf die Seiten Ihres Projekts gelangt. Darüber hinaus lohnt es sich, dem Projekt einige Tests und Flusenregeln hinzuzufügen, um potenziell gefährlichen Code zu identifizieren und zu verhindern, dass er in Produktion geht.
Links sind nicht die einzigen Entitäten, die auf diese Weise verwendet werden können. Sie sind jedoch das wahrscheinlichste Angriffsziel in React-Anwendungen. Jedes Element kann für diesen Angriff anfällig sein, wenn der Angreifer seinen
URI
Wert steuern kann. Eine andere Möglichkeit, diesen Angriff auszuführen, ist beispielsweise ein Ansichtsdesign. Eine vollständige Liste der Attribute, die URIs enthalten können, finden Sie in
dieser Liste unter Verwendung des Schlüsselworts
%URI
Verwendung der Browsersuche (
Ctrl+F
).
Sicherheitslücke # 3: Missverständnis der Bedeutung der Konstruktion gefährlichSetInnerHtml
Ich bin React sehr dankbar, dass die Sicherheitswarnung direkt im Methodennamen enthalten ist. Dies ist der Name
dangerouslySetInnerHTML
. Trotz dieser Warnung sind wir immer noch häufig mit der Tatsache konfrontiert, dass Entwickler Risiken eingehen, indem sie unsichere Vorgänge ausführen. Gleiches gilt für
eval()
.
Betrachten Sie das folgende Beispiel, das ich auf der Website auf der ersten Seite der Google-Suchergebnisse gefunden habe:
<script dangerouslySetInnerHTML={{ __html: `window.__PRELOADED_STATE__ = ${JSON.stringify(initialState)};`}}></script>
Dies ist ein Beispiel für die Sicherheitsanfälligkeit Nr. 1, aber mit einer Funktion, die sofort darauf aufmerksam machen sollte, dass hier etwas nicht stimmt. Wo ich dies fand, wurde versucht zu erklären: "Wir verwenden
gefährlich SetInnerHTML als Methode zum Bereinigen von Daten und zum Verhindern von XSS-Angriffen." Nun, nein! Das ist nicht richtig. Tu das nicht. Weitere Informationen zu
dangerouslySetInnerHTML
SetInnerHTML finden Sie in der React-Dokumentation.
Ein weiteres Beispiel dafür, dass dies tatsächlich die ganze Zeit passiert, ist die Art und Weise, wie Mitglieder desselben Teams entdeckten, dass sie eine
Sicherheitsanfälligkeit hatten, als sie der Seite Markierung mit
dangerouslySetInnerHTML
SetInnerHTML Markup hinzufügten. Um sich in Zukunft davor zu schützen, begannen sie, eine spezielle Flusenregel anzuwenden.
▍ Identifizierung der Sicherheitsanfälligkeit während der Codeüberprüfung
Bevor Sie Pull-Anforderungen senden oder Zusammenführungsvorgänge ausführen, ist es hilfreich, den Code nach
dangerouslySetInnerHTML
console.log
und
eval
Zeichenfolgen zu durchsuchen (auf diese Weise suche ich auch nach
console.log
Befehlen) oder die entsprechende Linter-Regel zu verwenden.
▍ Schutz
Stellen Sie sicher, dass in allen Fällen, in denen die
dangerouslySetInnerHTML
verwendet wird, nur Daten auf die Seite geladen werden, denen Sie vertrauen können. Woher wissen Sie, ob Daten vertrauenswürdig sind? Wenn etwas nicht von Ihnen kommt, kann es eine Bedrohung sein. Dies umfasst Daten, die von externen APIs heruntergeladen wurden, und Daten, die mit Markdown-Tools ausgegeben werden.
Hinweis zum Spoofing von Komponenten
Im Jahr 2015 hat
jemand herausgefunden, dass Sie Komponenten fälschen können, indem Sie JSON an diejenigen Komponenten übergeben, die Text erwarten. Ich konnte nur einen Fall einer Komponenten-Spoofing-Nachricht und eine
lange Diskussion finden, die durch diese Nachricht verursacht wurde. Die Diskussion konzentrierte sich darauf, was React für die Verhinderung von XSS-Angriffen verantwortlich ist. Infolgedessen haben die React-Entwickler einen
Fix veröffentlicht , der anscheinend dazu beigetragen hat, diese Sicherheitsanfälligkeit zu beheben.
Ich habe beschlossen, keine Geschichte über diese Sicherheitsanfälligkeit in den Artikel aufzunehmen, aber dieses Thema könnte für weitere Forschungen von Interesse sein.
SSR Hinweis
Die Sicherheitsanfälligkeit beim Rendern von Servern ist so weit verbreitet, dass sie in der Redux-Dokumentation vorhanden war und sich daher auf viele andere Materialien verteilte. Dieses Problem wurde 2016 behoben. Aber auch heute, nach drei Jahren, unterrichten Anfängerführer, die über das Internet verstreut sind, immer noch, was Sie nicht unterrichten sollten.
Übrigens, hier sind Ihre Hausaufgaben: Finden Sie ein Beispiel für dieses Problem auf GitHub und senden Sie eine Pull-Anfrage, um es zu beheben.
Hier ist ein Beispiel .
Gemeinsam können wir diese Schwachstelle ein für alle Mal beseitigen!
Liebe Leser! Sind Sie auf Angriffe auf Ihre React-Projekte gestoßen?
