Articles

CORS, XSS und CSRF mit Beispielen in 10 Minuten

Dieser Artikel soll Ihr Einstieg in die bestehenden Web-Sicherheitsstandards, die häufigsten Web-Angriffe und die Methoden zu deren Verhinderung sein. Am Ende werden Sie auch erfahren, wie und warum Samy jedermanns Held war (außer Rupert Murdoch, schätze ich)

Cross-origin resource sharing, oder CORS, ist ein Sicherheitsmerkmal von IE10+, Chrome 4+, Firefox 3.5+ oder fast jeder Browserversion, die nach 2012 veröffentlicht wurde, außer Opera Mini.

Wenn CORS auf einem Server konfiguriert ist, der in der Domäne website.com verfügbar ist, dann müssen Ressourcen aus dieser Domäne, die über AJAX angefordert werden, von Assets initiiert werden, die von der gleichen Domäne bereitgestellt werden.
CORS

Mit anderen Worten, wenn wir CORS auf domain-b.com aktivieren und es so konfigurieren, dass es nur GET Anfragen von der Domain domain-b.com zulässt, dann wird, wenn Sie ein unter https://domain-b.com/images/example.png verfügbares Bild im Canvas auf Ihrer Website, die auf domain-a.com gehostet wird, verwenden möchten, dieses Bild für die meisten Ihrer Besucher nicht geladen.
Ihre Ressourcen, die durch CORS geschützt sind, werden immer noch verfügbar sein, wenn sie von einem Tool oder Browser angefordert werden, der CORS policy nicht respektiert.

CORS-Konfiguration

CORS sind standardmäßig deaktiviert, was bedeutet, dass es keinen adäquaten Server-Handler gibt, der CORS konfiguriert, was bedeutet, dass Sie in Ihrer XHR nicht auf Ressourcen aus anderen Quellen zugreifen können. Wenn Sie nichts unternehmen oder CORS nur für bestimmte Domains aktivieren, wird jede AJAX-Anfrage, die auf Ihre Ressourcen zugreifen möchte, abgelehnt, da Webbrowser die CORS policy.
Das ist der Grund, warum Sie auf CORS-Probleme stoßen, wenn Sie mit der Entwicklung von SPAs mit VueJS und NodeJS beginnen. Ihre VueJS-Anwendung wird auf http://localhost:8080 gehostet und wenn Sie versuchen, auf die NodeJS-Serveranwendung auf http://localhost:8000 zuzugreifen, erhalten Sie „No Access-Control-Allow-Origin header is present„, weil dies zwei verschiedene ORIGINS sind (Kombination aus PROTOCOL, HOST und PORT).

Ein cooler Fix für das CORS Problem im VueJS Entwicklungsmodus ist es, den devServer Proxy in der vue.config.js Datei wie folgt zu setzen:

module.exports = { ... devServer: { proxy: 'http://localhost:8000', }, ...}
Enter fullscreen mode Exit fullscreen mode

Um CORS in der Produktion einzurichten, sollte man einen entsprechenden Listener für OPTIONS Anfragen hinzufügen. Dieser Listener sollte die Antwort 200 mit no body, aber mit Headers senden, die Ihre gewünschte CORS-Richtlinie definiert:

Access-Control-Allow-Origin: https://domain-b.comAccess-Control-Allow-Methods: GET
Vollbildmodus betreten Vollbildmodus verlassen

Weitere Informationen zur Konfiguration von CORS finden Sie unter https://enable-cors.org/index.html, und um tiefer in die Materie einzutauchen, lesen Sie CORS policyunter https://livebook.manning.com/book/cors-in-action/part-1/

XSS

XSS steht für Cross Site Scripting und ist ein Injektionsangriff. Es ist auf Platz 7 der Top 10 der von OWASP im Jahr 2017 identifizierten Schwachstellen gelistet. Cross Site Scripting ist die Methode, bei der der Angreifer ein bösartiges Skript in eine vertrauenswürdige Website einschleust.(Abschnitt aktualisiert, danke Sandor) Es gibt 3 Arten solcher Angriffe.

  1. Stored XSS – Schwachstelle, die von ungeschützten und nicht sanitisierten Benutzereingaben ausgeht, die direkt in der Datenbank gespeichert und anderen Benutzern angezeigt werden
  2. Reflected XSS – Schwachstelle, die von ungeschützten und nicht sanitisierten Werten von URLs ausgeht, die direkt in Webseiten verwendet werden
  3. DOM based XSS – Ähnlich wie reflected XSS, ungeschützte und nicht bereinigte Werte von URLs, die direkt in Webseiten verwendet werden, mit dem Unterschied, dass DOM-basiertes XSS nicht einmal auf die Serverseite geht

Attacke

1. Stored XSS

Hier ist ein Beispiel für einen Angriff. Der Angreifer kommt auf Ihre Website und findet ein ungeschütztes Eingabefeld wie das Kommentarfeld oder das Feld für den Benutzernamen und gibt anstelle des erwarteten Wertes ein bösartiges Skript ein. Wenn dieser Wert dann anderen Benutzern angezeigt wird, wird bösartiger Code ausgeführt. Das bösartige Skript kann versuchen, auf Ihr Konto auf anderen Websites zuzugreifen, kann an DDoS-Angriffen beteiligt sein oder ähnliches. Visuelle Darstellung (Quelle geeksforgeeks.org):

XSS example

2. Reflected XSS

Reflected XSS ist ein Angriff, der stattfindet, wenn ein Angreifer eine Seite mit einer solchen Schwachstelle entdeckt, zum Beispiel:

erwartete URL: https://mywebpage.com/search?q=javascript
Bösartige URL: https://mywebpage.com/search?q=<script>alert('fortunately, this will not work!')</script>

<body>...<div> showing results for keyword <script> document.write(window.location.href.substr(window.location.href.indexOf('q=') + 2))</script></div>......JavaScript results......</body>
Vollbildmodus betreten Vollbildmodus verlassen

Nach der Entdeckung ködert der Angreifer den Benutzer, auf diese bösartige URL zu klicken und voila. Die sensiblen Daten des Benutzers werden ausgenutzt.

Der Lebenszyklus des Angriffs wird in dem von geekforgeeks.com bereitgestellten Beispiel veranschaulicht:

Reflected XSS example

3. DOM-basiertes XSS

Diese Art des Angriffs ist die gleiche wie die reflektierte, aber mit dem Unterschied, dass der bösartige URL Teil überhaupt nicht an den Server gesendet wird. Für obiges Beispiel:

erwartete URL: https://mywebpage.com/search?q=javascript
Schadhafte URL (reflektiertes XSS): https://mywebpage.com/search?q=<script>alert('fortunately, this will not work!')</script>
Schadhafte URL(DOM based XSS): https://mywebpage.com/search#q=<script>alert('fortunately, this will not work!')</script>

Der Unterschied besteht darin, dass das Zeichen # anstelle von ? verwendet wird. Die Browser senden den Teil der URL nach dem # nicht an den Server, sondern leiten ihn direkt an Ihren Client-Code weiter.

Schutz

Jeder Wert, der vom Benutzer eingegeben werden kann und in Ihrer Anwendung verwendet wird (entweder auf der Server- oder auf der Client-Seite), sollte als nicht vertrauenswürdige Daten behandelt und daher vor der Verwendung verarbeitet werden! Sie sollten eine Sicherheitsüberprüfung sowohl in Ihrer Server- als auch in Ihrer Client-App durchführen!
Wie in der Dokumentation gezeigt, entschlüsselt VueJS selbst die Zeichenkette, bevor es den Wert aus der Variable erhält. Neuere Versionen von Angular escapen Strings auch implizit, wenn Sie also Vanilla JS, JQuery oder ähnliches verwenden, sollten Sie String-Escape manuell implementieren.

Es gibt drei gängige Ansätze für die Verarbeitung von nicht vertrauenswürdigen Daten, die unten aufgeführt sind, und die ideale Methode hängt vom tatsächlichen Typ des Feldes ab, das Sie verarbeiten müssen.

1. String-Validierung

Die Validierung ist eine Methode, bei der der Benutzer eine Reihe von Regeln definiert und verlangt, dass die nicht vertrauenswürdigen Daten diese Regeln erfüllen, bevor sie weiterverarbeitet werden. Diese Methode ist gut für Zahlenwerte, Benutzernamen, E-Mail, Passwort und ähnliche Felder mit konkreten Syntaxregeln geeignet.

Prüfen Sie, ob es Bibliotheken für Ihr Framework gibt, bevor Sie überlegen, eigene Validatoren zu schreiben.

2. String Escape

Die Escape-Methode ist nützlich für Fälle, in denen Sie dem Benutzer die Verwendung von Satzzeichen ermöglichen wollen. Diese Methode durchläuft die Zeichenkette und sucht nach Sonderzeichen wie < > und ersetzt sie durch den entsprechenden HTML-Zeichenentitätsnamen. Hier ist eine grundlegende Funktion, die Sie verwenden können:

function escapeText(text) { return text.replace(/&/g, '&amp;') .replace(/</g, '&lt;') .replace(/>/g, '&gt;') .replace(/"/g, '&quot;')}
Vollbildmodus einschalten Vollbildmodus verlassen

Auch hier sollten Sie nach vorhandenen Bibliotheken suchen, bevor Sie Ihre eigene schreiben.

3. String sanitization

Sanitizing string wird verwendet, wenn der Benutzer einige HTML-Tags in seine Kommentare, Artikel oder ähnliches eingeben darf. Die Sanitize-Methode geht durch den Text und sucht nach HTML-Tags, die Sie angeben, und entfernt sie. Eine der populärsten Bibliotheken, die diesen Ansatz verwendet, ist Google Closure.
Diese Methode ist ressourcenintensiv und gilt als schädlich, daher sollten Sie mehr recherchieren, bevor Sie sich dafür entscheiden.

Webbrowser (keine verfügbaren Quellen, seit welcher Version, IE hat dieses Problem 2014 behoben.) entschlüsseln automatisch URLs, bevor sie an die Serverseite gesendet werden, und stellen sie auch im window.location-Objekt zur Verfügung, daher sind die zweite und dritte Art von Angriffen hier nur, um sich ihrer bewusst zu sein und um klarzustellen, dass URL-Parameter auch als nicht vertrauenswürdige Daten behandelt werden sollten.

Für detailliertere Informationen über XSS und wie man seine Anwendung richtig schützt, wenn man viele nicht vertrauenswürdige Daten rotieren lässt, lesen Sie bitte das OWASP Cheatsheet zur XSS-Prävention.

CSRF

Cross-Site-Request-Forgery oder CSRF ist eine Angriffsart, die auftritt, wenn eine bösartige Website, E-Mail, ein Blog, eine Sofortnachricht oder ein Programm den Webbrowser eines Benutzers dazu veranlasst, eine unerwünschte Aktion auf einer anderen vertrauenswürdigen Website durchzuführen, auf der der Benutzer authentifiziert ist. Diese Schwachstelle ist möglich, wenn der Browser bei jeder Anfrage automatisch eine Autorisierungsressource wie ein Sitzungscookie, eine IP-Adresse oder ähnliches sendet.

ATTACK

Angenommen, der Benutzer ist bei Ihrer ungeschützten Börsen-Webanwendung angemeldet und Sie verwenden entweder ein Sitzungscookie oder ein JWT-Cookie zur Authentifizierung. Der Angreifer nutzt auch Ihren Dienst und kann überprüfen, wie Ihre API funktioniert. Der Angreifer bringt den Benutzer dazu, ein Skript auszuführen (indem er auf einen SPAM-Link in einer E-Mail oder ähnlichem klickt), das eine Anfrage an Ihre API https://www.stockexchange.com/users/withdraw?how_much=all&address=MY_ADDRESS sendet (schreckliches API-Design, fragen Sie nicht). Da die Anfrage von einem Browser ausgeführt wird, der bei jeder Anfrage einen Authentifizierungs-Payload sendet, wird Ihr Börsen-Webserver den Benutzer erfolgreich authentifizieren und die Transaktion ausführen, und der getäuschte Benutzer wird sein gesamtes Guthaben verlieren, ohne es zu bemerken, da alles im Hintergrund passiert. Visuelle Darstellung (Quelle miro.medium.com)
CSRF attack

SCHUTZ

Glücklicherweise gibt es einfach zu implementierende Muster, die diese Webangriffe verhindern. Eines der häufigsten Muster ist die Verwendung von CSRF token. Grundsätzlich ist das Verfahren wie folgt:

  1. Erzeugen Sie ein eindeutiges Token für jede Anfrage des Benutzers, das so genannte CSRF token.
  2. Speichern Sie es sicher auf dem Server und senden Sie es als Nutzlast der Antwort an den Benutzer zurück.
  3. Speichern Sie CSRF token auf der Client-Seite.
  4. Wenn der Benutzer versucht, eine zustandsändernde* Anfrage auszuführen, sendet er CSRF token mit der Anfrage als Payload.
  5. Vor der Ausführung der Anfrage auf der Serverseite prüfen, ob CSRF token vorhanden und gültig ist.

Dies ist der einfachste Weg, um CSRF-Angriffe für alle Benutzer zu verhindern.

Wenn Sie es nur mit Besuchern zu tun haben, die moderne Browser verwenden, dann können Sie sich auf das SameSite-Attribut des Session-Cookies verlassen.(Danke Gergely)

Da die Antworten des Servers in der XHR-Antwort verarbeitet werden können, gibt es keinen Schutz vor CSRF-Angriffen, wenn Ihre Webanwendung XSS-anfällig ist!

Um tiefer einzutauchen, lesen Sie das OWASP Cheatsheet zu CSRF.

BONUS

Kurzdokumentation über Samy, den Autor des Wurms, der 2005 MySpace zum Absturz brachte, indem er eine XSS-Schwachstelle ausnutzte und die CSRF-Abwehr von MySpace überwand.
https://youtu.be/DtnuaHl378M

Mehr Informationen über Samys Wurm
https://samy.pl/myspace/tech.html