Bevor mit dem eigentlichen Thema dieses Blog-Eintrages begonnen wird, noch kurz eine Anmerkung zu der Buildroot-Vorlage „dhbw_html_defconfig“. Diese hat bei uns nicht direkt funktioniert. Beim Starten des Browsers erschien die Warnung, dass der Prozess keine Berechtigung hat, auf verschiedene Eingabegeräte wie Maus und Tastatur zuzugreifen. Aus diesem Grund wurden folgende Zeilen in die Inittab Datei eingefügt:

#change input access permissions
::sysinit:/bin/chmod 0666 /dev/input/event0
::sysinit:/bin/chmod 0666 /dev/input/event1
::sysinit:/bin/chmod 0666 /dev/input/event2

Diese bewirken, dass alle Prozesse schreibend und lesend auf die Geräte zugreifen dürfen.

Was ist CORS?

Cross-Origin Resource Sharing (CORS) bezeichnet einen Mechanismus, mithilfe dessen Webseiten, die über einen Browser aufgerufen werden, auf Ressourcen (=HTTP Request) anderer Domains (=Origin) zugreifen können. Eine Origin wird dabei eindeutig durch die drei Attribute Domain, Protokoll und Port definiert. Aufgrund der damit einhergehenden Sicherheitslücken blockieren Browser die meisten Cross-Origin Request. Mithilfe von speziellen HTTP Headern kann das CORS Verhalten einer Webseite gesteuert werden.

HTTP-Anfragen werden im Kontext von CORS in zwei Gruppen eingeteilt:

  1. Simple Anfragen: Dies sind HTTP Requests, von denen nicht erwartet wird, dass sie gespeicherte Daten beeinflussen. Nur die HTTP Verben GET, HEAD und POST sind erlaubt. Des Weiteren sind nur bestimmte HTTP Header erlaubt. Eine weitere Einschränkung betrifft den Content-Type Header, dieser darf nur application/x-www-form-urlencoded,multipart/form-data oder text/plain sein.
    Der Browser führt den Request ohne weitere vorherige Prüfungen aus. Falls es ein CORS Request ist, wird der HTTP Header Access-Control-Allow-Origin der Antwort überprüft. Falls dieser die aktuelle Domain beinhaltet oder * entspricht, gibt der Browser die Antwort an die Webseite weiter, da dies bedeutet, dass der Server die CORS-Anfrage zulässt.
  2. Bei allen anderen Requests führt der Browser vorher eine Prüfung durch. Würde die Anfrage direkt ausgeführt werden, würde der Server eventuell Daten ändern, noch bevor CORS-Header an den Browser zurückgesendet werden.
    Der Browser sendet dann einen sogenannten „Preflight“-Request. Dazu wird das OPTIONS Verb verwendet. Der Browser fragt damit beim Server nach, ob ein CORS-Request für diesen Origin, den angegebenen Pfad und das angegebene HTTP-Verb zulässig ist. Erst wenn der Server dies bestätigt, wird die eigentliche Anfrage ausgeführt.

Bezüglich der Authentifizierung bei HTTP-Requests ist anzumerken, dass bei (nicht-simplen) CORS-Requests der Browser standardmäßig keine Cookies und Authentifizierungs-Informationen sendet. Dies muss explizit erwünscht werden. Des Weiteren muss der Server mithilfe des Headers Access-Control-Allow-Credentials explizit das Empfangen von Authentifizierungsdaten erlauben.

Quelle: https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS

Projekt Setup

In der Produktivumgebung unserer Anwendung ist kein CORS notwendig, da alle Anfragen an den gleichen Server gehen (Statische Dateien und API). In der Entwicklungsumgebung sieht das anders aus. Der Server ist über eine registrierte Domain erreichbar, während die Entwickler des Frontends einen lokalen Webserver benutzen, um ihren Code zu testen. Der Browser würde diese CORS-Anfrage standardmäßig blockieren, da keine CORS-Header gesendet werden. Aufgrund der Verwendung verschiedener HTTP Verben und dem JSON Content Type werden Preflight Requests durchgeführt. Folgende Änderungen waren notwendig, dass die Entwickler die Anwendung sinnvoll testen können:

  • CORS-Requests serverseitig erlauben, jedoch nur im Test-Modus (Siehe Code unten). Als Origin wird der von der WebStorm IDE standardmäßig aufgesetzte Web Server verwendet, des Weiteren müssen Cookies explizit erlaubt werden.
  • Beim Versender der HTTP-Requests muss explizit angegeben werden, dass vorhandene Cookies gesendet werden sollen. (Bei der Verwendung der AXIOS Bibliothek: withCredentials Option)

if (testMode) {
const corsOptions = {
origin: ‚http://localhost:63342‘, // WebStorm default test web server
credentials: true
};

this.express.use(cors(corsOptions));
}

 

CSRF Attacken

Cross-Site Request Forgery (CSRF) Angriffe nutzen Schwachstellen in der CORS-Konfiguration, um durch das Ausnutzen bestehender Sessions Daten zu erhalten beziehungsweise zu manipulieren. Ein möglicher Ablauf sieht wie folgt aus:

  1. Ein Nutzer meldet sich bei einer Online-Banking Anwendung im Browser an
  2. Der Nutzer öffnet in einem zweiten Browser-Tab eine Webseite, die Schadsoftware enthält. Diese löst bspw. mit einer HTML-Form eine simple HTTP-Request an die Online-Banking Webseite aus (d.h. kein Preflight Request). Der Browser sendet dabei die Login-Cookies mit, sodass aus Serversicht die Anfrage zulässig ist.
  3. Die Anfrage löst eine Überweisung aus. Da der Server kein CORS erlaubt, blockiert der Browser die Weitergabe der Antwort an die Webseite. Dies ist aber egal, da die Überweisung bereits getätigt wurde.

Eine Möglichkeit, eine Webseite dagegen zu schützen, besteht in der Nutzung von speziellen CSRF Tokens. Diese erhält der Sender der Anfrage bspw. über ein HTTP-Response Header. Bei jeder nicht-simplen Anfrage muss das Token mitgegeben werden, damit die Anfrage ausgeführt werden kann. Andere Webseiten haben bei richtiger CORS-Konfiguration keine Möglichkeit, dieses Token zu bekommen.

Auswirkungen auf unser Projekt

Für unser Projekt haben wir evaluiert, inwiefern wir uns gegen CSRF Attacken schützen müssen. Durch das Deaktivieren von CORS und simplen Requests (JSON Content Type –> immer Preflight Request) ist die Anwendung bereits ausreichend gegen CSRF Attacken geschützt. Es sind, im Gegensatz zum ursprünglichen Plan, keine CSRF Tokens notwendig.

Quelle: https://github.com/pillarjs/understanding-csrf

RaspberryBuy (4): CORS und CSRF Attacken