Cross Site Scripting (XSS) abwehren, Texte maskieren

Bei der Erstellung von sicheren Webanwendungen ist das Verhindern von Cross Site Scripting (kurz XSS genannt) eine zentrale Anforderung.
XSS bezeichnet das Einschleusen von gefährlichen Inhalt in eine Webanwendung, der z.B. bei der Ausgabe dazu führt das bestimmte HTML oder JavaScript Anweisungen die Seite verändern, Daten auslesen, fremde Seiten einbinden etc.
Ein typischer und einfacher Vorgang ist z.B. die Eingabe von HTML Anweisungen in Formularfelder. Werden die Eingaben später ohne Maskierung ausgegeben, kann ein Angreifer Code einschleusen.

Beispiel: Ein Text Eingabefeld „GLOBAL:Name“ wird an den Server übermittelt, dieser gibt dann die Meldung „Hallo $GLOBAL:Name“ aus.
Gibt man nun im Namen „<script>alert(`Hallo`);</script>“ ein, führt das dazu das bei der Ausgabe ein möglicherweise schädliches JavaScript ausgeführt wird, da der Browser denkt, dieses sei in Ordnung, da es ja vom selben Server kommt.
Die einzige wirklich wirksame Methode gegen XSS ist es, konsequent potentiell unsicheren Inhalt vor der Ausgabe zu maskieren. Im obigen Beispiel also die gefährlichen Zeichen < > und ` durch die entsprechenden HTML Entitäten wie &lt; &gt; &quot; zu ersetzen.
Eine Prüfung der Eingabe allein ist keine wirksame Maßnahme gegen XSS. Die möglichen Angriffsvektoren sind einfach zu vielfältig und hängen zudem stark von der Verarbeitung und Ausgabe der Daten ab.

Die DLE bietet für das Maskieren einige Möglichkeiten. Im Basispaket gibt es ein Kommando „Zeichenkette Maskieren“, mit der man manuell eine Zeichenkette je nach Inhalt maskieren kann.

Einfacher ist jedoch die Verwendung spezieller Maskierungsanweisungen im Text selber. Ähnlich wie die Übersetzung mittels @@ Maskierung gibt es in der DLE im Webumfeld die Möglichkeit, mit folgenden Maskierungen zu arbeiten:

  • @H{....}@
  • @A{....}@
  • @C{....}@
  • @J{....}@
  • @U{....}@
  • @X{....}@
  • @!{....}@

Diese Maskierungen maskieren nach bestimmten Regeln für: HTML Daten, HTML Attribute (strikter als HTML, eignet sich auch für Attributdaten die ohne Anführungszeichen benutzt werden), CSS Werte, JavaScript Zeichenketten, URL Daten, XML Daten. Dabei wird der Text zwischen den geschweiften Klammern entsprechend maskiert. Die Begrenzer werden dann entfernt. Einen Sonderfallt stellt das @! Muster dar, hier werden die Daten nicht maskiert, sondern verschlüsselt und die Maskierung wird nicht entfernt. Siehe Kapitel 13 (Kryptografie im Web).

Die Maskierung kann auch ganz einfach im Brickeditor in der Feldauswahl gewählt werden. Dazu ist das Häkchen „Erweiterte WEB-Optionen“ oben im Editor anzuhaken. Dann kann die gewünschte Maskierung einfach vorgegeben werden.

Für die Ausgabe von Text, der aus unsicheren Quellen stammt, gibt es zudem das HTML Kommando „Label“. Dieses HTML-maskiert den kompletten Text und gibt ihn im HTML Dokument aus.

Die DLE maskiert zudem automatisch dort, wo kein HTML oder JavaScript Markup erwartet wird. Wie z.B. bei den Parametern für ID, CSS Style, Tooltip, HTML Klassen, Namen, Werte etc.

Cross Site Request Forgery (CSRF) abwehren

Definition

Eine Cross-Site-Request-Forgery (meist CSRF oder XSRF abgekürzt, deutsch etwa Website-übergreifende Anfragenfälschung) ist ein Angriff auf ein Computersystem, bei dem der Angreifer eine Transaktion in einer Webanwendung durchführt. Dies geschieht nicht direkt, sondern der Angreifer bedient sich dazu eines Opfers, das bei einer Webanwendung bereits angemeldet sein muss. Dem Webbrowser des Opfers wird ohne dessen Wissen ein arglistiger HTTP-Request (‚Anforderung‘) untergeschoben. Der Angreifer wählt den Request so, dass bei dessen Aufruf die Webanwendung die vom Angreifer gewünschte Aktion ausführt.

Abwehrmaßnahme: Manuell

Die DLE erstellt auf dem Server ein sogenanntes CSRF Token, eine speziell codierte und sichere Zufallszeichenkette. Diese wird dem Browser mitgeteilt, der wiederum bei jeder Anfrage dieses Token über einen speziellen HTTP Header (X-CSRFToken) an den Server übermittelt.
Im Brick stehen beide Tokens als DLE Variablen ($CSRF_Token_Server und $CSRF_Token_Client) zur Verfügung. Im Brick kann damit manuell überprüft werden, ob beide Tokens übereinstimmen und entsprechend eine Aktion durchgeführt werden.

Abwehrmaßnahme: Automatisch

In der web.xml kann mittels Init-Parameter angegeben werden, ob eine automatische Prüfung erfolgen soll und welche URL-Pfade davon ausgeschlossen sind (White List), z.B.:

<!--
CSRF protection
-->
<context-param>
<description>
Enable automatic CSRF check on app start.
Defaults to "false".
</description>
<param-name>dle.csrf.autoCheck</param-name>
<param-value>true</param-value>
</context-param>
<context-param>
<description>
Paths that will not be CSRF checked, when CSRF check is enabled. Multiple entries must be separated by a semicolon.
</description>
<param-name>dle.csrf.whitelist</param-name>
<param-value>/Demo/Index.brick;/Demo/css</param-value>
</context-param>

In diesem Fall ist die automatische Prüfung eingeschaltet, nur Anfragen deren ServletPath mit /Demo/Index.brick oder /Demo/css beginnen, werden ausgenommen.

Ist eine automatische Prüfung eingeschaltet, muss zumindest die Startseite zwingend in der White List stehen, da erst beim Laden der Startseite der CSRF Token an den Browser übermittelt wird.

Prüfung ein- bzw. ausschalten

Zusätzlich steht das Kommando „HTTP Automatische CSRF Token Prüfung“ zur Verfügung. Mit diesem kann die automatische Prüfung im Brick ein- bzw. ausgeschaltet werden.
Mit der Variablen $CSRF_Automatische_Prüfung kann dies abgefragt werden. Ist entweder Ja oder Nein (Y/N), je nachdem ob die automatische CSRF Prüfung derzeit ein- oder ausgeschaltet ist.

Clickjacking abwehren

Clickjacking ist eine Technik, bei der ein Computerhacker die Darstellung einer Internetseite überlagert und dann deren Nutzer dazu veranlasst, scheinbar harmlose Mausklicks und/oder Tastatureingaben durchzuführen.

Clickjacking ist ein konzeptionelles Problem von JavaScript und Webanwendungssicherheit. Es beruht nicht auf einem "Fehler" des Anwendungsprogrammierers, insofern sind Gegenmaßnahmen nicht trivial.

Fast alle Browser haben inzwischen die Möglichkeit eingeführt, dass Webanwendungen einen Header "X-Frame-Options" senden, der dem Browser anzeigt, ob die Webseite in einem Frame angezeigt werden darf oder nicht. Möglich sind hierfür die Werte "DENY" (Seite darf nicht in Frame angezeigt werden), "SAMEORIGIN" (Seite darf nur von Frames auf derselben Domain angezeigt werden) und "ALLOW-FROM" (Seite darf von spezifizierte Domäne und URL angezeigt werden). Voraussetzung für diesen Schutz ist aber, dass er sowohl von der Webanwendung als auch vom Browser unterstützt wird. Der Header ist bislang kein offizieller Standard. Unterstützt wird er vom Internet Explorer ab Version 8.0, Firefox ab 3.6.9, Opera ab 10.50, Safari ab 4.0 und Chrome ab 4.1.249.1042.

In der DLE kann für das CallFolderServlet in der web.xml angegeben werden, diesen Header bei jeder Antwort zu setzen. Dazu ist in der Definition des CallFolderServlet z.B. folgendes hinzuzufügen:

<init-param>
<description>
Disables display of data in an iframe.
This protects against clickjacking attacks.
</description>
<param-name>dle.response.header.X-Frame-Options</param-name>
<param-value>DENY</param-value>
</init-param>

Kryptografie im Web

Inhalte, die einem potenziellen Angreifer Hinweise auf die Funktionsweise der Anwendung geben, oder zwar am Browser gespeichert werden müssen aber nicht im Klartext sichtbar sein dürfen, können mittels der DLE Kryptografie Funktionen (Zeichenkette verschlüsseln, Zeichenkette entschlüsseln) vor dem Senden an den Browser verschlüsselt werden.
Nach Erhalt am Server als z.B. Formular- oder URL Parameter, können diese dann wieder entschlüsselt werden. Eine einfache Möglichkeit, Ausgaben automatisch zu verschlüsseln funktioniert ähnlich wie die Maskierung von Texten (Kapitel 9 Cross Site Scripting (XSS) abwehren, Texte maskieren). Wird das Textmuster @!{….}@ in einem Ausgabetext gefunden, wird der zwischen den geschweiften Klammern stehende Text mit einem internen Schlüssel verschlüsselt.
Anders als bei den Maskierungen für HTML, CSS etc. wird die Maskierung um den Verschlüsselten Text jedoch nicht entfernt.
Entschlüsselt werden kann der Text wiederum mit dem Kommando „Zeichenkette entschlüsseln“. Es muss kein Password angegeben werden.
Erkennt das Kommando, das die Zeichenkette mit @!{ beginnt und mit }@ endet, so wird der Inhalt automatisch entschlüsselt und in der Zielvariable gespeichert. Damit lassen sich z.B. in einem Formular verschlüsselte Werte speichern, die dann wieder zum Server übermittelt werden:

<input type=“hidden“ name=“GLOBAL:CryptoTest“ value=“@!{Geheimer Text}@”/>