Web Security für alle: Content-Security-Policy Web Security für alle: X-Content-Type-Options

Web Security für alle: X-XSS-Protection

Published on Tuesday, September 27, 2016 4:00:00 AM UTC in Programming & Security

Genau begründen kann ich es gar nicht, aber in meinem Kopf sortiere ich den X-XSS-Protection-Header immer in ein persönliches Gruselkabinett ein. Es widerstrebt mir fast, ihn zu implementieren. Vielleicht liegt es daran, dass die Funktionsweise zunächst proprietär und kaum durchschaubar war, oder dass es durchaus false positives geben kann? Oder auch daran, dass der vor XSS-Attacken schützende Header dazu genutzt werden konnte, eigentlich sichere Seiten für XSS-Attacken verwundbar zu machen, was Microsoft 2010 den Pwnie-Award für den Most Epic FAIL eingebracht hat. Dennoch lohnt sich zumindest ein Blick auf die Details, also los!

X-XSS-Protection

Prinzipiell funktioniert der Mechanismus so, dass der Browser sich ausgehende Requests ansieht und verdächtig aussehende Fragmente, etwa in Query-Parametern, versucht mit dem zu matchen, was in der zugehörigen Serverantwort steckt. Wird eine vermeintliche reflective XSS-Attacke erkannt, hängt es von der zugehörigen Einstellung des Filters ab, ob das Rendern der Seite komplett unterbunden wird (mode=block), oder ob der Filter nur versucht, das fragliche Fragment zu entschärfen. In letzterem Fall wird dem Benutzer etwa im Internet Explorer ein entsprechender Hinweis angezeigt:

modified-page-by-xss-filter.png

Angreifer können dieses Verhalten ausnutzen, um etwa gutmütige Scripts zu deaktivieren (false positives) oder durch den Filter andere Teile der Seite so manipulieren zu lassen, dass eine XSS-Lücke erst entsteht. Wer sich für die Details interessiert, dem sei das ursprüngliche White Paper aus 2010 dazu ans Herz gelegt. Aber auch in jüngerer Zeit sind wieder und wieder Bugs öffentlich geworden (im Übrigen auch in der Chrome-Implementierung dieser Logik, mitnichten nur bei Microsoft), und selbst der restriktive Modus zum Blockieren des gesamten Renderns konnte für schwerwiegende Angriffe genutzt werden. Eine schöne Zusammenfassung mit Erklärungen aus jüngster Zeit findet sich beispielsweise hier. Größere Seiten wie etwa Facebook schalten die zugehörigen Funktionen daher gezielt ab(!), indem sie diesen Header auf den Wert 0 setzen.

facebook-xss-protection.png

Bei Facebook abgeschaltet

Letztendlich handelt es sich also um eine Fallunterscheidung, wie man mit dem Filter umgehen sollte. Ich nutze den Wert 1; mode=block.

Implementierung

Da die Werte für das Aktivieren und Deaktiveren des Filters nicht beliebig mit dem block-Modus kombiniert werden können (eine Kombination aus 0 und mode=block ist weder sinnvoll noch zulässig), verdrahte ich die Kombinationsmöglichkeiten auf fixe Kombinationen.

"XXssProtection": {
  "IsEnabled": true,
  "Value": "TurnOnAndBlock" 
}
public XXssProtectionOptions XXssProtection { get; set; }

public class XXssProtectionOptions
{
    public bool IsEnabled { get; set; }
    public XXssProtectionOptionsValue Value { get; set; }

    public enum XXssProtectionOptionsValue
    {
        TurnOff, // 0
        TurnOn, // 1
        TurnOnAndBlock // 1; mode=block
    }
}

Es gibt darüber hinaus noch den Wert report, mit dem der Browser blockierte Aufrufe an eine bestimmte Adresse posten soll, der nur in Chrome und WebKit umgesetzt ist. Wer sich für Details interessiert, findet hier mehr Informationen.

Die Umsetzung des Headers in der aus den bisherigen Artikeln zum Thema bekannten Middleware sieht dann in etwa so aus:

private Task ApplyHeaders(object state)
{
    var context = (HttpContext)state;

    ApplyHstsHeader(context);
    ApplyXFrameOptionsHeader(context);
    ApplyXContentTypeOptionsHeader(context);
    ApplyXXssProtectionHeader(context); // <-- there you go
            
    return Task.CompletedTask;
}

private void ApplyXXssProtectionHeader(HttpContext context)
{
    var xXssProtectionOptions = _options.XXssProtection;

    if (!xXssProtectionOptions.IsEnabled)
    {
        return;
    }

    switch (xXssProtectionOptions.Value)
    {
        case SecurityHeadersOptions.XXssProtectionOptions.XXssProtectionOptionsValue.TurnOff:
            context.Response.Headers["X-XSS-Protection"] = "0";
            break;
        case SecurityHeadersOptions.XXssProtectionOptions.XXssProtectionOptionsValue.TurnOn:
            context.Response.Headers["X-XSS-Protection"] = "1";
            break;
        case SecurityHeadersOptions.XXssProtectionOptions.XXssProtectionOptionsValue.TurnOnAndBlock:
            context.Response.Headers["X-XSS-Protection"] = "1; mode=block";
            break;
    }
}

Auch hier also kein Hexenwerk.

Ergebnis

Auch für die Umsetzung von X-XSS-Protection gibt es wieder einen kleinen Bonus bei einschlägigen Tests. In Summe:

grade-with-x-xss-protection.png

In der Liste der Header fehlt damit nur noch Content-Security-Policy - beim nächsten Mal.

Tags: ASP.NET Core · XSS