Auge: Wie funktioniert CSRF? Verständnisproblem.

Hallo

In einem Projekt, in das ich involviert bin, wurde (u.A.) eine Cross-Site-Request-Forgery-Sicherheitslücke gemeldet. Die Meldung erfolgte nicht öffentlich und auch nicht an mich, weshalb ich sie hier auch nicht im Wortlaut wiedergeben möchte. Die im Projekt verwendete Sprache ist PHP.

Lücke #1

Sinngemäß heißt es in der Meldung, ein Angreifer könne für einen angemeldeten Benutzer Aktionen mit dessen Account auslösen, wenn der Benutzer gleichzeitig sowohl in einer Installation des Projekts angemeldet ist, als auch eine präparierte Website des Angreifers aufgerufen hat. Als Beispiel wird die Registrierung eines neuen Benutzers und die Ausweitung der Rechte eines Benutzers mit gefälschten Formularen (ginge, wenn es geht, natürlich auch ohne sie) genannt.

Die Anmeldung in einer Installation erfolgt per Formular und es wird bei erfolgreicher Anmeldung eine Session erstellt. Der Session-Name wird per Cookie hin- und hergereicht. Die hiesige Suche zum Begriff CSRF ergibt im Zeitraum der letzten zwei Jahre bisher nur drei Ergebnisse. In einem der Beiträge wird auf einen CSRF-Token verwiesen. Was macht der? Wie funktioniert der?

Es wird auch noch auf zwei weitere Lücken hingewiesen. Ich kann, da ich mir den betreffenden Code noch nicht angeschaut habe, keine Aussage darüber treffen, ob eine oder beide Lücken mit der oben beschriebenen in Zusammenhang stehen.

Lücke #2

Es wird darauf verwiesen, dass zwei Felder eines bestimmten Formulars anfällig für einen „reflected XSS“ seien. Als Beispiel wird folgende Zeile gezeigt …

<input type="hidden" name="email" value="test&#64;example&#46;comle3d4&quot;&gt; &lt;script&gt;alert&#40;1&#41;&lt;&#47;script&gt;"/> 

… die ich in folgenden Code aufgelöst habe.

<input type="hidden" name="email" value="test@example.comle3d4"> <script>alert(1)</script>"/>

Dazu ein paar Fragen.

  1. Im gezeigten Originalcode sind das Ausführungszeichen und das Größer-Als-Zeichen, welche die Emailadresse und das input-Tag abschließen, als maskierte Zeichen notiert.
    • Sollten sie damit nicht ungefährlich sein?
    • Kann es sein, dass die Maskierungen aus dem Test des Fehlermelders stammen, aber der Angriffscode so, wie in meiner Auflösung notiert, unmaskiert sein müsste?
  2. Wenn die Emailadresse serverseitig validiert wird, ist ja nach „.comle3d4“ Schluss. Wem wird das Alert untergeschoben? Wird es denjenigen untergeschoben, die sich den betroffenen, bereits gespeicherten Datensatz anschauen, falls die Eingaben nicht mit htmlspecialchars behandelt werden oder lauert da noch an anderer Stelle Ungemach?

Lücke #3

Lücke Numero 3 betrifft CSS-Injektion über den relativ angegebenen Pfad zur CSS-Ressource im Link-Element des Dokumentkopfes. Diesen Umstand zu beheben und daraus eine absolute URL zu machen, ist einfach. Ich verstehe aber leider den Angriffsvektor nicht.

Mir stellen sich folgende Fragen …

… auf deren Beantwortung ich hoffe.

Ich habe leider keine Vorstellung, wie solche Angriffe funktionieren. Wie kommt eine andere Website, die gleichzeitig mit der des Projektes im Browser geöffnet ist, an die Anmeldung in Form des Cookie, wie es die oben verlinkte Wikipedia-Seite und auch der Melder der Lücken beschreiben? Wie kann mir jemand externe CSS-Ressourcen unterschieben, bloß, weil der originale Aufruf mit einer relativen Pfadangabe erfolgt? Wer ist das Ziel des JavaScript-Codes, wenn dieser bei der serverseitigen Verarbeitung der Eingaben nicht gefunden und zurückgewiesen wird? Und was bleibt von diesem Angriff übrig, wenn die serverseitige Validierung funktioniert?

Tschö, Auge

--
Wo wir Mängel selbst aufdecken, kann sich kein Gegner einnisten.
Wolfgang Schneidewind *prust*

akzeptierte Antworten

  1. Ich hoffe das und das hilft weiter!

    1. Hallo

      Ich hoffe das

      Da bist du zu spät. Diese Quelle hatte ich in meiner Frage schon selbst verlinkt, war mir also schon bekannt. :-)

      … und das hilft weiter!

      Das tat es tatsächlich. Die Seite enthält gut verständliche, ballastarme Erklärungen für verschiedene Angriffsszenarien. Danke.

      Tschö, Auge

      --
      Wo wir Mängel selbst aufdecken, kann sich kein Gegner einnisten.
      Wolfgang Schneidewind *prust*
  2. Tach!

    CSRF-Token ... Was macht der? Wie funktioniert der?

    Der stellt sicher, dass das Formular vom Server und nicht von anderswo kommt. Der Token wird vom Server generiert und als Hidden-Input ausgeliefert. In der Antwort wird der Wert mit dem gespeicherten verglichen. Wenn nun jemand das Formular fälscht, hat er kein valides Token und die Verarbeitung wird abgelehnt.

    Lücke #2

    1. Im gezeigten Originalcode sind das Ausführungszeichen und das Größer-Als-Zeichen, welche die Emailadresse und das input-Tag abschließen, als maskierte Zeichen notiert.
      • Sollten sie damit nicht ungefährlich sein?
      • Kann es sein, dass die Maskierungen aus dem Test des Fehlermelders stammen, aber der Angriffscode so, wie in meiner Auflösung notiert, unmaskiert sein müsste?

    Diese Frage kann ich dir nicht beantworten, weil ich dein Meldungssystem nicht kenne. Mitunter haben Systeme eine gutgemeinte Intelligenz eingebaut und filtern oder machen anderweitig Eingaben kaputt, anstatt sie lediglich kontextgerecht zu maskieren. Lass dir im Zweifelsfall die Daten per Plain-Text-Mail oder als (eingepackte) Textdatei im Anhang schicken. Wenn die Lücke Wirkung zeigen soll, muss jedenfalls die dekodierte Variante an den Browser geschickt werden, damit der als Code interpretiert, was der Autor, der die potentielle Lücke nicht beachtet hat, dachte es sei Text.

    1. Wenn die Emailadresse serverseitig validiert wird, ist ja nach „.comle3d4“ Schluss. Wem wird das Alert untergeschoben? Wird es denjenigen untergeschoben, die sich den betroffenen, bereits gespeicherten Datensatz anschauen, falls die Eingaben nicht mit htmlspecialchars behandelt werden oder lauert da noch an anderer Stelle Ungemach?

    Ziel ist es, den Browser Code ausführen zu lassen, in der Regel Javascript-Code, wenn das Opfer auf einen Link klickt. Der Link mit Daten im Anhang wird zum Server gesendet, der erzeugt eine Webseite und baut die Eingabe unmaskiert ein. Damit kann man dann prinzipiell alles machen, was der Anwender von sich aus zu machen in der Lage wäre. Z.B. Requests absetzen, während sein Anmeldungs-/Sessioncookie mitgesendet wird.

    Lücke #3

    Lücke Numero 3 betrifft CSS-Injektion über den relativ angegebenen Pfad zur CSS-Ressource im Link-Element des Dokumentkopfes. Diesen Umstand zu beheben und daraus eine absolute URL zu machen, ist einfach. Ich verstehe aber leider den Angriffsvektor nicht.

    PathInfo - /das/ist/die/url.php/aber/da/hängt/noch/was/dran

    Der Browser weiß ja nicht, dass das Dokument, in dem das CSS relativ verlinkt ist, url.php heißt, und so fordert er eben nicht /das/ist/die/datei.css, sondern /das/ist/die/url.php/aber/da/hängt/noch/was/datei.css an. Wenn dabei das URL-Rewriting mitspielt, bekommt man vielleicht sogar eine real existierende Datei ausgeliefert. Inwieweit die dann Unfug anstellen kann, sei mal dhingestellt.

    Ich habe leider keine Vorstellung, wie solche Angriffe funktionieren. Wie kommt eine andere Website, die gleichzeitig mit der des Projektes im Browser geöffnet ist, an die Anmeldung in Form des Cookie, wie es die oben verlinkte Wikipedia-Seite und auch der Melder der Lücken beschreiben?

    In der anderen Website (oder auch in einer Email) ist ein Link zum Projekt enthalten, den der Anwender klickt. Cookies werden zur URL gespeichert und nicht zu Tabs/Fenstern, so dass auch im der Request im Nachbartab das aktuelle Session-Cookie mitsendet.

    Wie kann mir jemand externe CSS-Ressourcen unterschieben, bloß, weil der originale Aufruf mit einer relativen Pfadangabe erfolgt?

    Du beschreibst Lücke #3 nicht ausführlich genug. War da wirklich von externen CSS-Ressourcen die Rede? Die müssten ja dann ähnlich zu #1 eingebunden werden.

    Wer ist das Ziel des JavaScript-Codes, wenn dieser bei der serverseitigen Verarbeitung der Eingaben nicht gefunden und zurückgewiesen wird?

    Der Browser des Opfers. Kontextgerechte Maskierung reicht schon, um einen solchen Angriff wirkungslos verpuffen zu lassen. Irgendeine Intelligenz, die schädlichen Code erkennt, braucht man da nicht. Falls eine solche überhaupt in der Lage ist, alle gefährlichen Situationen zu erkennen.

    Und was bleibt von diesem Angriff übrig, wenn die serverseitige Validierung funktioniert?

    Validierung ist die Prüfung gegen die Regeln der Geschäftslogik. Ob man damit Angriffe erkennen kann oder nicht, spielt keine Rolle, solange die kontextgerechte Maskierung beachtet wird.

    Anders ausgedrückt, ich würde die Anwendung so schreiben, dass sie nur die Gültigkeit von Eingaben gemäß ihrem eigenen Bedarf prüft. Angriffe herausfiltern würde ich nur dann, um die Handarbeit des Entfernens von Spam- und Unsinns-Einträgen zu sparen/minimieren. Gegen schädliche Wirkung hilft kontextgerechte Maskierung, die man ja auch für gutartige Daten braucht. Kontextgerechte Maskierung ist nicht nur eine Abwehrmaßnahme sondern vor allem für die ordnungsgemäße Arbeit des eigentlichen Programms notwendig. Das Ins-Leere-Laufen von XSS-Angriffen ist dann nur noch ein Nebeneffekt.

    dedlfix.

    1. Hallo

      CSRF-Token ... Was macht der? Wie funktioniert der?

      Der stellt sicher, dass das Formular vom Server und nicht von anderswo kommt. Der Token wird vom Server generiert und als Hidden-Input ausgeliefert. In der Antwort wird der Wert mit dem gespeicherten verglichen.

      Soweit, so (vorher schon) klar.

      Wenn nun jemand das Formular fälscht, hat er kein valides Token und die Verarbeitung wird abgelehnt.

      Ich habe wohl gedanklich dieses mit anderen Szenarien, in denen der Angreifer z.B. durch Übernahme einer Session selbst direkt in die Anwendung eindringt, verwechselt. Hier geht es nur darum, sicherzustellen, dass die Eingaben direkt aus dem an den angemeldeten Benutzer gesendeten HTML-Formular und nirgendwoanders her stammen. Ist das so korrekt?

      1. Im gezeigten Originalcode sind das Ausführungszeichen und das Größer-Als-Zeichen, welche die Emailadresse und das input-Tag abschließen, als maskierte Zeichen notiert.
        • Sollten sie damit nicht ungefährlich sein?
        • Kann es sein, dass die Maskierungen aus dem Test des Fehlermelders stammen, aber der Angriffscode so, wie in meiner Auflösung notiert, unmaskiert sein müsste?

      … Wenn die Lücke Wirkung zeigen soll, muss jedenfalls die dekodierte Variante an den Browser geschickt werden, damit der als Code interpretiert, was der Autor, der die potentielle Lücke nicht beachtet hat, dachte es sei Text.

      Ich bin zwar nicht der Hauptentwickler, gehe aber davon aus, dass aus Eingaben stammende Daten bei deren Ausgabe samt und sonders maskiert werden. Ich werde mich dennoch durch den Code, der die Eingaben prüft und den, der die Ausgaben generiert, hangeln.

      1. Wenn die Emailadresse serverseitig validiert wird, ist ja nach „.comle3d4“ Schluss. Wem wird das Alert untergeschoben? Wird es denjenigen untergeschoben, die sich den betroffenen, bereits gespeicherten Datensatz anschauen, falls die Eingaben nicht mit htmlspecialchars behandelt werden oder lauert da noch an anderer Stelle Ungemach?

      Ziel ist es, den Browser Code ausführen zu lassen, in der Regel Javascript-Code, wenn das Opfer auf einen Link klickt. Der Link mit Daten im Anhang wird zum Server gesendet, der erzeugt eine Webseite und baut die Eingabe unmaskiert ein.

      Wie gesagt, ich gehe davon aus, dass keine unmaskierte Ausgabe erfolgt [1]. Das war auch der Grund, warum ich die Form der Meldung nicht verstehe. Wenn eine unbehandelte Ausgabe erfolgen sollte, würde ich die Meldung genau dieses Fehlers erwarten. Wenn hingegen der durch Eingaben eingeschleuste Code bei sämtlichen Ausgabe entschärft wird und somit seine Wirkung nicht entfalten kann, liegt mMn kein Fehler vor. Eine Fehlermeldung zum rätselraten finde ich jedenfalls befremdlich.

      Lücke Numero 3 betrifft CSS-Injektion über den relativ angegebenen Pfad zur CSS-Ressource im Link-Element des Dokumentkopfes. Diesen Umstand zu beheben und daraus eine absolute URL zu machen, ist einfach. Ich verstehe aber leider den Angriffsvektor nicht.

      PathInfo - /das/ist/die/url.php/aber/da/hängt/noch/was/dran

      Der Browser weiß ja nicht, dass das Dokument, in dem das CSS relativ verlinkt ist, url.php heißt, und so fordert er eben nicht /das/ist/die/datei.css, sondern /das/ist/die/url.php/aber/da/hängt/noch/was/datei.css an. Wenn dabei das URL-Rewriting mitspielt, bekommt man vielleicht sogar eine real existierende Datei ausgeliefert.

      Mit einer vollständigen, absoluten URL, z.B. mit //www.example.com/data/default.css, sollte sich das beheben lassen.

      Wie kann mir jemand externe CSS-Ressourcen unterschieben, bloß, weil der originale Aufruf mit einer relativen Pfadangabe erfolgt?

      Du beschreibst Lücke #3 nicht ausführlich genug. War da wirklich von externen CSS-Ressourcen die Rede? Die müssten ja dann ähnlich zu #1 eingebunden werden.

      Wer ist das Ziel des JavaScript-Codes, wenn dieser bei der serverseitigen Verarbeitung der Eingaben nicht gefunden und zurückgewiesen wird?

      Der Browser des Opfers. Kontextgerechte Maskierung reicht schon, um einen solchen Angriff wirkungslos verpuffen zu lassen.

      Danke für die Klarstellung.

      Irgendeine Intelligenz, die schädlichen Code erkennt, braucht man da nicht. Falls eine solche überhaupt in der Lage ist, alle gefährlichen Situationen zu erkennen.

      Dass das nur ungenügend und mit der Gefahr unerwünschter Nebenwirkungen funktioniert, ist mir klar. Ich werde den HTML-Teil auf HTML5 und damit die Formularfelder auf die damit eingeführten Typen umstellen, um im Browser Vorprüfungen durchzuführen, aber gegen Angriffe mit gefakten Formularen hilft das auch nicht. Die dafür bestimmten Änderungen sind jedoch von anderer Seite in Arbeit. :-)

      Und was bleibt von diesem Angriff übrig, wenn die serverseitige Validierung funktioniert?

      … ich würde die Anwendung so schreiben, dass sie nur die Gültigkeit von Eingaben gemäß ihrem eigenen Bedarf prüft. Angriffe herausfiltern würde ich nur dann, um die Handarbeit des Entfernens von Spam- und Unsinns-Einträgen zu sparen/minimieren. Gegen schädliche Wirkung hilft kontextgerechte Maskierung, die man ja auch für gutartige Daten braucht. Kontextgerechte Maskierung ist nicht nur eine Abwehrmaßnahme sondern vor allem für die ordnungsgemäße Arbeit des eigentlichen Programms notwendig. Das Ins-Leere-Laufen von XSS-Angriffen ist dann nur noch ein Nebeneffekt.

      Ja, so sehe ich das auch. Ich wollte nur sicherstellen, dass ich wegen meiner Unkenntnis nicht irgendwelchen Voodoo übersehe und wir uns, auf halbem Wege stehenbleibend, in falscher Sicherheit wiegen.

      Danke auch an dich.

      Tschö, Auge

      --
      Wo wir Mängel selbst aufdecken, kann sich kein Gegner einnisten.
      Wolfgang Schneidewind *prust*

      1. Wie ebenfalls gesagt, prüfe ich das noch einmal. ↩︎

      1. Tach!

        Hier geht es nur darum, sicherzustellen, dass die Eingaben direkt aus dem an den angemeldeten Benutzer gesendeten HTML-Formular und nirgendwoanders her stammen. Ist das so korrekt?

        Ja.

        dedlfix.

  3. Hallo,

    In einem Projekt, in das ich involviert bin, wurde (u.A.) eine Cross-Site-Request-Forgery-Sicherheitslücke gemeldet.

    Hast du sie denn verursacht? Und sollst du sie nun schließen?

    Alle Projekte, die mit Cookie-Authentifizierung arbeiten, sind von CSRF betroffen, sofern sie KEINE Gegenmaßnahmen ergreifen (wie CSRF-Token). Das ist das "täglich Brot" eines Webprogrammierers. Das sollte man unbedingt wissen, bevor man irgendwelche Projekte mit User-Authentifizierung online stellt.

    In einem der Beiträge wird auf einen CSRF-Token verwiesen. Was macht der? Wie funktioniert der?

    Der CSRF-Token ist eine weitere vertrauliche Information, die bei nicht-idempotenten Requests (PUT, POST, DELETE) zur Authentifizierung an den Server gesendet werden muss. Im Gegensatz zum Cookie wird der CSRF-Token nicht automatisch gesendet, wenn eine fremde Seite einen Request auf deine Seite initiiert. Der CSRF-Token wird üblicherweise in der User-Session auf dem Server gespeichert. Er wird z.B. in jedes Formular als Hidden Input geschrieben und wird mit den Formulardaten mitsendet. Erst wenn Cookie und CSRF-Token valide sind, dann ist der Request gültig.

    Es wird auch noch auf zwei weitere Lücken hingewiesen. Ich kann, da ich mir den betreffenden Code noch nicht angeschaut habe, keine Aussage darüber treffen, ob eine oder beide Lücken mit der oben beschriebenen in Zusammenhang stehen.

    <input type="hidden" name="email" value="test&#64;example&#46;comle3d4&quot;&gt; &lt;script&gt;alert&#40;1&#41;&lt;&#47;script&gt;"/> 
    
    1. Im gezeigten Originalcode sind das Ausführungszeichen und das Größer-Als-Zeichen, welche die Emailadresse und das input-Tag abschließen, als maskierte Zeichen notiert.
      • Sollten sie damit nicht ungefährlich sein?

    Ja, was diesen Kontext angeht schon.

    - Kann es sein, dass die Maskierungen aus dem Test des Fehlermelders stammen, aber der Angriffscode so, wie in meiner Auflösung notiert, unmaskiert sein müsste?
    

    Ja – das kannst du testen, indem du <script>alert(1)</script> als Wert ins Formular eingibst. Wird der JS-Code ausgeführt auf der Folgeseite oder auf irgendeiner Seite, wo die E-Mail vorkommt, bist du verwundbar.

    1. Wenn die Emailadresse serverseitig validiert wird, ist ja nach „.comle3d4“ Schluss. Wem wird das Alert untergeschoben?

    Allen Usern die sich diese Seite ansehen bzw. durch einen Link oder eine fremde Seite zum Reflected XSS geführt werden. JavaScript wird ja im Browser ausgeführt. XSS bedeutet dass ein Angreifer JavaScript-Code in deine Seite einschleust.

    Lücke Numero 3 betrifft CSS-Injektion über den relativ angegebenen Pfad zur CSS-Ressource im Link-Element des Dokumentkopfes. Diesen Umstand zu beheben und daraus eine absolute URL zu machen, ist einfach. Ich verstehe aber leider den Angriffsvektor nicht.

    Das wird mir aus deiner Beschreibung auch nicht klar.

    Ich habe leider keine Vorstellung, wie solche Angriffe funktionieren.

    Falls du Webanwendungen entwickelst, solltest du dich informieren/weiterbilden. XSS und CSRF sind das "Einmaleins" der Websicherheit.

    Wie kommt eine andere Website, die gleichzeitig mit der des Projektes im Browser geöffnet ist, an die Anmeldung in Form des Cookie, wie es die oben verlinkte Wikipedia-Seite und auch der Melder der Lücken beschreiben?

    Die fremde Seite kommt nicht an den Cookie selbst. Muss sie auch nicht. Sie initiiert einfach nur einen Request an deine Seite. Das Senden des Cookies (und damit die erfolgreiche User-Authentifizierung) macht der Browser des Opfers automatisch. Sämtliche URL- oder Formulardaten erscheinen deiner Anwendung daher als "legitim", sie kommen aber vom Angreifer.

    Wie kann mir jemand externe CSS-Ressourcen unterschieben, bloß, weil der originale Aufruf mit einer relativen Pfadangabe erfolgt?

    Ich wüsste nicht dass dies möglich ist.

    Wer ist das Ziel des JavaScript-Codes, wenn dieser bei der serverseitigen Verarbeitung der Eingaben nicht gefunden und zurückgewiesen wird?

    Schau dir einmal mal die Definition von "Reflected XSS" an. Das sollte genau diese Frage klären.

    Und was bleibt von diesem Angriff übrig, wenn die serverseitige Validierung funktioniert?

    Eigentlich nichts. Eine serverseitige Validierung plus eine saubere Maskierung in allen Kontexten verhindern XSS.

    Hans

    1. nicht-idempotenten Requests (PUT, POST, DELETE)

      Korrektur: Wie hinter dem Link auch beschrieben, ist PUT zwar idempotent aber nicht "safe", da es Ressourcen auf dem Server verändert.

    2. Hallo

      In einem Projekt, in das ich involviert bin, wurde (u.A.) eine Cross-Site-Request-Forgery-Sicherheitslücke gemeldet.

      Hast du sie denn verursacht? Und sollst du sie nun schließen?

      Nein und ja.

      Alle Projekte, die mit Cookie-Authentifizierung arbeiten, sind von CSRF betroffen, sofern sie KEINE Gegenmaßnahmen ergreifen (wie CSRF-Token). Das ist das "täglich Brot" eines Webprogrammierers. Das sollte man unbedingt wissen, bevor man irgendwelche Projekte mit User-Authentifizierung online stellt.

      Das ist wohl wahr. Das Projekt ist zu einer Zeit öffentlich verfügbar gemacht worden, als sich wohl noch kaum jemand um solche Angriffe Gedanken gemacht hat. Mit der erfolgten Meldung ist es höchste Zeit, sich damit zu beschäftigen.

      In einem der Beiträge wird auf einen CSRF-Token verwiesen. Was macht der? Wie funktioniert der?

      Der CSRF-Token ist eine weitere vertrauliche Information, die bei nicht-idempotenten Requests (PUT, POST, DELETE) zur Authentifizierung an den Server gesendet werden muss. Im Gegensatz zum Cookie wird der CSRF-Token nicht automatisch gesendet, wenn eine fremde Seite einen Request auf deine Seite initiiert. Der CSRF-Token wird üblicherweise in der User-Session auf dem Server gespeichert. Er wird z.B. in jedes Formular als Hidden Input geschrieben und wird mit den Formulardaten mitsendet. Erst wenn Cookie und CSRF-Token valide sind, dann ist der Request gültig.

      Danke auch für deine Funktions- und Angriffsbeschreibungen …

      … sowie die Links.

      Tschö, Auge

      --
      Wo wir Mängel selbst aufdecken, kann sich kein Gegner einnisten.
      Wolfgang Schneidewind *prust*