Website-Sicherheit: Best Practices Schicht für Schicht (2026)
Kernaussage
Website-Sicherheit nach Best Practices funktioniert in Schichten: Sichern Sie Domain und DNS ab (Registrar Lock, DNSSEC, CAA), erzwingen Sie modernes TLS mit HSTS, senden Sie einen strikten Satz an HTTP-Sicherheitsheadern, hashen Sie Passwörter mit Argon2id und schützen Sie Logins mit MFA und Rate Limiting, validieren Sie Eingaben und setzen Sie die Zugriffskontrolle auf dem Server durch, pinnen und prüfen Sie Abhängigkeiten, schließen Sie jeden Port, den Sie nicht bedienen, und protokollieren Sie genug, um einen Einbruch zu bemerken. Zu jeder Maßnahme unten finden Sie die genaue Konfiguration und einen kostenlosen Weg, um zu prüfen, ob sie wirklich greift – denn eine Schutzmaßnahme, die Sie nie getestet haben, ist eine, die Sie nicht haben.
Jetzt prüfen

Jetzt lesen
- Website-Sicherheit: Was Best Practices wirklich bedeuten
- Der Web-Security-Stack: Sechs Schichten, die Sie schützen müssen
- Schicht 1: Domain und DNS absichern
- Schicht 2: HTTPS und TLS richtig umsetzen
- Schicht 3: HTTP-Sicherheitsheader
- Schicht 4: Authentifizierung, die Credential Stuffing standhält
- Sessions, Cookies und CSRF
- Eingaben validieren, Ausgaben kodieren
- Broken Access Control: Das Risiko Nummer eins
- Schicht 5: Abhängigkeiten und Software-Lieferkette
- Schicht 6: Server-Härtung: Ports, Patches, Secrets und Backups
- E-Mail-Authentifizierung: SPF, DKIM und DMARC
- Protokollieren, überwachen und für den Ernstfall planen
- Testen: Scanner, Penetrationstests und laufende Prüfungen
- Die Checkliste für Website-Sicherheit
- So passt das zu den OWASP Top 10:2025
- Häufige Fragen zur Website-Sicherheit
Website-Sicherheit: Was Best Practices wirklich bedeuten
Website-Sicherheit nach Best Practices umfasst alle Maßnahmen, die verhindern, dass eine Website oder Webanwendung übernommen, verunstaltet, als Angriffswerkzeug gegen die eigenen Besucher missbraucht oder unbemerkt ihrer Daten beraubt wird. Das ist weder ein einzelnes Produkt noch eine einzelne Einstellung, sondern ein Stapel von Entscheidungen: Er beginnt beim Domain-Registrar und reicht über DNS, TLS, die HTTP-Header Ihres Servers, den Code für Logins und Eingaben, die Drittanbieter-Pakete, auf denen Sie aufbauen, und den Server selbst bis zu den Logs, die Ihnen zeigen, dass etwas schiefgelaufen ist.
Der Grund, in Schichten zu denken: Angreifer tun es auch. Der 2026 Data Breach Investigations Report von Verizon, der mehr als 22.000 Sicherheitsvorfälle von November 2024 bis Oktober 2025 auswertet, stellte fest: 31 % der Einbrüche begannen mit einer ausgenutzten Software-Schwachstelle – nach 20 % im Vorjahr und erstmals vor gestohlenen Zugangsdaten (13 %); Phishing blieb stabil bei 16 %. Ransomware kam bei 48 % der Vorfälle vor, nach 44 %. Ein einziger fehlender Patch, ein durchgesickerter API-Schlüssel oder eine Admin-Seite ohne Rate Limiting genügt. Keine der Maßnahmen in diesem Leitfaden ist exotisch; gehackt werden meist die Websites, die auf einer Schicht die Grundlagen ausgelassen haben, während sie eine andere perfektionierten.
Dieser Leitfaden ist von außen nach innen aufgebaut. Jede Maßnahme sagt Ihnen, warum sie wichtig ist, was genau zu konfigurieren ist und wie Sie sie prüfen – mit einem Befehl oder einem kostenlosen Tool wie dem HTTP-Header-Checker oder dem SSL-Checker. Denn eine Einstellung, die Sie für aktiv halten, aber nie geprüft haben, schützt nichts.
Check a site's security headers
Der Web-Security-Stack: Sechs Schichten, die Sie schützen müssen
Jeder Angriff auf eine Website trifft eine von sechs Schichten. Die folgende Tabelle ist die Landkarte für den Rest dieses Leitfadens: was auf jeder Schicht liegt, wie sie typischerweise angegriffen wird und mit welchem kostenlosen Test Sie bestätigen, dass Ihre Abwehr tatsächlich greift.
| Schicht | Was Angreifer hier tun | Zentrale Maßnahmen | Prüfen mit |
|---|---|---|---|
| 1. Domain und DNS | Domain kapern, Nameserver ändern, verwaiste Subdomains übernehmen, gefälschte Zertifikate ausstellen lassen | Registrar Lock, MFA, DNSSEC, CAA, Prüfung veralteter Einträge | WHOIS-Abfrage, DNS-Health-Check, Subdomain-Finder |
| 2. Transport (TLS) | Herabstufung auf HTTP, Verschlüsselung aushebeln, alte Cipher ausnutzen, abgelaufene Zertifikate | TLS 1.2+, HSTS (Preload optional), automatisierte Erneuerung | SSL-Checker |
| 3. HTTP-Header | Skripte einschleusen (XSS), die Seite für Clickjacking in Frames einbetten, Content-Types erraten lassen, Referrer preisgeben | CSP, frame-ancestors, nosniff, Referrer-Policy, Permissions-Policy | HTTP-Header-Checker |
| 4. Anwendung | Credential Stuffing, Injection, fehlerhafte Zugriffskontrolle, CSRF, unsichere Uploads | Argon2id + MFA + Rate Limits, parametrisierte Abfragen, serverseitige Autorisierung, SameSite-Cookies | Code-Review, ZAP, Passwort-Stärke-Test |
| 5. Abhängigkeiten | Vergiftete Pakete, bekannte CVEs in Bibliotheken, kompromittierte CI-Pipelines | Lockfiles, Audits, gepinnte Versionen, SBOM, Tokens mit minimalen Rechten | npm audit, Dependabot, Trivy |
| 6. Server und Betrieb | Offene Ports, Standard-Zugangsdaten, fehlende Patches, keine Backups, keine Logs | Firewall, SSH nur mit Schlüssel, Patching, 3-2-1-Backups, zentrales Logging | Port-Checker, IP-Blacklist-Checker |
Arbeiten Sie von oben nach unten. Die Schichten 1 bis 3 sind Konfiguration, die Sie an einem Nachmittag erledigen können, und sie schützen jede Seite auf einmal. Die Schichten 4 bis 6 sind dauerhafte Gewohnheiten, die in Ihrem Code-Review- und Deployment-Prozess verankert sein müssen.
Schicht 1: Domain und DNS absichern
Alles Weitere in diesem Leitfaden setzt voraus, dass Sie Ihre Domain noch kontrollieren. Kann sich ein Angreifer bei Ihrem Registrar anmelden oder Ihre Nameserver ändern, leitet er Ihren Traffic beliebig um, erhält ein gültiges Zertifikat für Ihren Namen und liest jede E-Mail an Sie mit – ohne dass Ihr Anwendungscode jemals ausgeführt wird. Die Sicherheit von Domain und DNS ist deshalb die erste Best Practice der Websicherheit, und sie besteht fast ausschließlich aus Konfiguration.
Beginnen Sie mit einer WHOIS-Abfrage Ihrer eigenen Domain und prüfen Sie drei Dinge: Die Statuscodes enthalten clientTransferProhibited, das Ablaufdatum liegt mehr als ein Jahr in der Zukunft, und der Registrar ist einer, bei dem Sie tatsächlich ein Konto haben. Erstaunlich oft liegt die Domain eines Unternehmens noch im Registrar-Konto eines ehemaligen Dienstleisters. Unser Leitfaden zur WHOIS-Abfrage erklärt jeden Statuscode, der Ihnen begegnen kann.
Registrar Lock, MFA und Ablaufwarnungen
Aktivieren Sie den Registrar Lock (auch Transfer-Sperre genannt), damit die Domain nicht zu einem anderen Registrar umgezogen werden kann, ohne dass Sie sie ausdrücklich entsperren, und schalten Sie Multi-Faktor-Authentifizierung für das Registrar-Konto selbst ein. Registrar-Konten sind ein beliebtes Phishing-Ziel, gerade weil ein einziger Login alles Nachgelagerte kontrolliert. Nutzen Sie einen Hardware-Schlüssel oder eine Authenticator-App statt SMS, wo immer der Registrar das zulässt.
Stellen Sie die Domain auf automatische Verlängerung mit einer Zahlungsmethode, die nicht abläuft, und legen Sie sich trotzdem 60 Tage vor dem Ablaufdatum einen Kalendereintrag an. Eine abgelaufene Domain ist nicht am Tag des Ablaufs verloren, aber sobald Karenz- und Einlösefrist verstrichen sind (bei .com bis zu etwa 80 Tage), wird sie gelöscht, und Drop-Catch-Dienste registrieren sie binnen Sekunden nach der Freigabe. Der Käufer erbt Ihre E-Mails, Ihren Traffic und alle OAuth-Logins, die Ihrer Domain vertrauen.
- Registry Lock (eine manuelle Sperre auf Registry-Ebene, die außerhalb des normalen Kontos gesetzt wird) ist für eine geschäftskritische Domain die Zusatzgebühr wert: Selbst ein kompromittiertes Registrar-Konto kann dann die Nameserver nicht mehr ändern.
- Trennen Sie die Rollen. Wer die Domain bezahlt, welches Konto sie besitzt und wer der DNS-Anbieter ist, sollte jeweils dokumentiert sein und nicht am Postfach eines einzelnen Mitarbeiters hängen.
- Aktivieren Sie WHOIS-Privacy, damit Ihre Kontaktdaten keine Vorlage für Phishing liefern, und hinterlegen Sie im Konto eine überwachte Rollenadresse wie
domains@.
Die Zone mit DNSSEC signieren
DNSSEC signiert Ihre DNS-Zone, damit ein Resolver gefälschte Antworten erkennen kann. Ohne DNSSEC kann ein Angreifer, der den Cache eines Resolvers vergiften kann, Ihre Besucher auf einen gefälschten Server schicken, während der Browser weiterhin Ihren Domainnamen anzeigt. Die meisten verwalteten DNS-Anbieter (Cloudflare, Route 53, Google Cloud DNS und viele Registrare) aktivieren es mit einem Schalter; der einzige manuelle Schritt ist die Veröffentlichung des DS-Eintrags beim Registrar. Prüfen Sie es mit dig oder mit dem DNS-Health-Check, der den DS-Eintrag und die Signaturen kontrolliert:
dig +dnssec +short yourdomain.com A
# A signed zone returns the record AND an RRSIG line:
# 203.0.113.10
# A 13 2 3600 20270115000000 20261225000000 34505 yourdomain.com. Kx3f...==
dig +short yourdomain.com DS
# A DS record at the parent zone proves the chain of trust is complete
# 2371 13 2 6A1B...C9Zertifikatsausstellung mit CAA einschränken
Ein CAA-Eintrag (RFC 8659) legt fest, welche Zertifizierungsstellen Zertifikate für Ihre Domain ausstellen dürfen. Jede öffentliche CA muss ihn vor der Ausstellung prüfen – ein CAA-Eintrag sperrt also einen Angreifer aus, der die Domain-Validierung einer anderen CA ausgetrickst hat. Drei Einträge decken die üblichen Fälle ab: wer ausstellen darf, wer Wildcards ausstellen darf und wohin abgelehnte Anfragen gemeldet werden:
yourdomain.com. CAA 0 issue "letsencrypt.org"
yourdomain.com. CAA 0 issuewild ";"
yourdomain.com. CAA 0 iodef "mailto:security@yourdomain.com"Veraltete Einträge prüfen: Subdomain Takeover
Ein Subdomain Takeover entsteht, wenn ein DNS-Eintrag noch auf einen Dienst zeigt, den Sie nicht mehr nutzen: ein CNAME auf eine gelöschte GitHub-Pages-Seite, eine Azure-App, einen S3-Bucket oder den Hostnamen eines SaaS-Anbieters. Jeder kann das verwaiste Ziel registrieren und dann unter old-app.yourdomain.com in Ihrem Namen Inhalte ausliefern – samt gültigem Zertifikat. Es ist ein regelmäßiger Fund in Bug-Bounty-Programmen, weil sich niemand an den Eintrag erinnert.
Lassen Sie Ihre Domain durch den Subdomain-Finder laufen: Er durchsucht zwei Certificate-Transparency-Log-Dienste, Cert Spotter (aktuelle Zertifikate) und crt.sh (jedes Zertifikat seit 2013), probiert 1.000 gängige Namen, löst jeden Namen live auf, markiert hängende CNAMEs und zeigt, welcher Host oder CDN dahintersteckt. Löschen Sie jeden Eintrag, dessen Ziel NXDOMAIN oder die „No such app“-Seite eines Anbieters liefert; ein DNS-Lookup bestätigt einen einzelnen Namen. Wiederholen Sie das vierteljährlich und machen Sie das Löschen des DNS-Eintrags zum Teil jeder Stilllegung eines Dienstes.
Certificate Transparency ist zugleich Ihr Frühwarnsystem: Cert Spotter und das CT-Monitoring von Cloudflare können Sie per E-Mail benachrichtigen, sobald irgendeine CA ein Zertifikat für Ihre Domain ausstellt. Ein unerwartetes Zertifikat ist oft das erste sichtbare Anzeichen dafür, dass DNS oder Registrar kompromittiert wurden.
Schicht 2: HTTPS und TLS richtig umsetzen
HTTPS ist keine Best Practice mehr, sondern die Grundlage, und Browser kennzeichnen reine HTTP-Seiten als „Nicht sicher“. Google hat zudem angekündigt, dass der Browser ab Chrome 154 (Oktober 2026) nachfragt, bevor er eine öffentliche Website über reines HTTP öffnet (Google). Was eine sichere Website noch von einer bloß verschlüsselten trennt, sind die akzeptierten TLS-Versionen, die Frage, ob man Sie überhaupt noch über HTTP erreichen kann, und ob die Erneuerung so gut automatisiert ist, dass sie die seit März 2026 greifenden Kürzungen der Zertifikatslaufzeiten übersteht.
Mindestens TLS 1.2, bevorzugt TLS 1.3
TLS 1.0 und 1.1 wurden 2021 mit RFC 8996 offiziell für veraltet erklärt, und kein aktueller Browser handelt sie noch aus. Deaktivieren Sie sie auf dem Server, bevorzugen Sie TLS 1.3 (das jeden als schwach bekannten Cipher streicht und den Handshake in einem einzigen Roundtrip abschließt) und behalten Sie TLS 1.2 nur mit AEAD-Cipher-Suites wie ECDHE-ECDSA-AES128-GCM-SHA256 oder ECDHE-RSA-CHACHA20-POLY1305 bei.
Zwei Zeilen zählen, wenn Sie von außen testen: das ausgehandelte Protokoll und Verify return code: 0, das bedeutet, dass die gesamte Zertifikatskette validiert wurde. Ein fehlendes Zwischenzertifikat ist eine häufige Ursache für Meldungen wie „funktioniert in Chrome, scheitert in curl und auf Android“; unser Leitfaden zur SSL-Zertifikatskette zeigt die Lösung, und der SSL-Checker meldet eine unvollständige Kette direkt. Hier die Prüfung gegen dnsrobot.net am 27. Oktober 2026, danach ein Test, ob der Server TLS 1.1 ablehnt:
echo | openssl s_client -connect dnsrobot.net:443 -servername dnsrobot.net 2>/dev/null \
| grep -E 'Protocol|Cipher|Verify return'
# New, TLSv1.3, Cipher is TLS_AES_256_GCM_SHA384
# Protocol: TLSv1.3
# Verify return code: 0 (ok)
# Is TLS 1.1 refused? SECLEVEL=0 lets OpenSSL 3 and later offer it at all
openssl s_client -connect example.com:443 -servername example.com -tls1_1 \
-cipher 'DEFAULT:@SECLEVEL=0' </dev/null 2>&1 | grep -E 'alert|Cipher is'
# Refused, as it should be: ...tlsv1 alert protocol version...
# New, (NONE), Cipher is (NONE)
# Still accepted (fix it): New, TLSv1.0, Cipher is ECDHE-ECDSA-AES128-SHA
# (TLSv1.0 is the cipher's version; the handshake was TLS 1.1)In Cipher-Listen veralten kopierte Konfigurationen am schnellsten. Statt sie von Hand zu schreiben, erzeugen Sie den aktuell empfohlenen Server-Block für nginx, Apache, Caddy oder HAProxy mit dem Mozilla SSL Configuration Generator und wählen das Profil „Intermediate“, sofern Sie nicht sehr alte Clients unterstützen müssen.
HSTS: Nie wieder HTTP im Browser
Eine Weiterleitung von HTTP auf HTTPS allein reicht nicht. Die allererste Anfrage eines Besuchers an http://yourdomain.com geht weiterhin im Klartext über die Leitung, und ein Angreifer im selben Netzwerk kann sie beantworten, bevor Ihre Weiterleitung greift. HTTP Strict Transport Security (RFC 6797) behebt das: Sobald ein Browser den Header einmal gesehen hat, schreibt er jede künftige http://-URL Ihrer Domain in https:// um, bevor er überhaupt etwas sendet.
Verwenden Sie ein max-age von mindestens einem Jahr (31536000 Sekunden) und ergänzen Sie includeSubDomains, sobald jede Subdomain HTTPS ausliefert. Das Preloading auf hstspreload.org, das die Domain fest in Chrome, Firefox, Safari und Edge einbaut, ist optional: Die Betreiber der Liste selbst sagen inzwischen, HSTS werde empfohlen, Preloading aber nicht, weil Chrome und Safari Navigationen ohnehin auf HTTPS hochstufen und das Verlassen der Liste Monate dauert. Prüfen Sie den Header mit dem HTTP-Header-Checker, der HSTS mit den Tests des Mozilla HTTP Observatory bewertet.
Strict-Transport-Security: max-age=31536000; includeSubDomains47-Tage-Zertifikate: Automatisieren Sie die Erneuerung jetzt
Das CA/Browser Forum verkürzt mit dem Ballot SC-081 die maximale Laufzeit jedes öffentlichen TLS-Zertifikats schrittweise. Die erste Stufe trat am 15. März 2026 in Kraft: Jedes Zertifikat, das Sie heute kaufen oder erneuern, ist bereits auf 200 Tage begrenzt, und ab 2029 muss ein Zertifikat etwa alle sechs Wochen ersetzt werden:
| Stichtag | Maximale Zertifikatslaufzeit | Wiederverwendung der Domain-Validierung |
|---|---|---|
| Vor dem 15. März 2026 | 398 Tage | 398 Tage |
| 15. März 2026 | 200 Tage | 200 Tage |
| 15. März 2027 | 100 Tage | 100 Tage |
| 15. März 2029 | 47 Tage | 10 Tage |
Manuelle Erneuerung hält diesem Zeitplan nicht stand. Best Practice ist die vollautomatische Ausstellung über ACME: Let's Encrypt oder Google Trust Services per certbot, acme.sh oder Caddy, oder die automatischen Zertifikate von Cloudflare, Vercel, Netlify und den meisten Hosting-Panels. Testen Sie den Erneuerungsweg, bevor Sie ihn brauchen (certbot renew --dry-run bei certbot); die typische Stolperfalle ist ein seit der letzten Erneuerung hinzugefügter CAA-Eintrag oder eine neue Firewall-Regel, die nun die Validierung blockiert. Egal, was Sie einsetzen: Überwachen Sie das Ablaufdatum auch von außen – der SSL-Checker zeigt die verbleibenden Tage, und ein abgelaufenes Zertifikat verwandelt jeden Besuch in eine ganzseitige Browserwarnung.
Schicht 3: HTTP-Sicherheitsheader
Sicherheitsheader sind Anweisungen Ihres Servers an den Browser, was er mit Ihren Seiten tun darf und was nicht: welche Skripte laufen dürfen, ob die Seite eingebettet werden darf, ob der Browser Content-Types erraten darf und was er anderen Websites darüber mitteilen soll, woher ein Besucher kam. Sie kosten nichts, gelten für jede Seite auf einmal und blockieren ganze Angriffsklassen. Außerdem ist dies die Schicht, die die meisten Websites teilweise falsch machen – deshalb bewertet der HTTP-Header-Checker sie mit den Tests des Mozilla HTTP Observatory. Das hat github.com am 27. Oktober 2026 gesendet, gekürzt auf die Sicherheitsheader (sein script-src nennt einen Asset-Host und einen Skript-Hash, ohne 'unsafe-inline'):
curl -sI https://github.com/ | grep -iE 'strict-transport|content-security|x-frame|x-content-type|referrer-policy'
strict-transport-security: max-age=31536000; includeSubdomains; preload
x-frame-options: deny
x-content-type-options: nosniff
referrer-policy: origin-when-cross-origin, strict-origin-when-cross-origin
content-security-policy: default-src 'none'; base-uri 'self'; ... frame-ancestors 'none'; ... script-src github.githubassets.com 'sha256-6AKuI+cDd1MoUL1u4eqrA9PXmnPAkOB4h7421hPUUm0='; ...Die sieben Header, die jede Website senden sollte
Das sind die Werte, die Sie bei einer typischen Website anstreben sollten. In der Bewertung des Mozilla HTTP Observatory, die unser HTTP-Header-Checker nutzt, kostet eine fehlende CSP 25 Punkte, ein fehlendes HSTS oder fehlender Framing-Schutz je 20 und ein fehlendes nosniff 5; Referrer-Policy und COOP bringen Bonuspunkte, sobald die Punktzahl noch bei 90 oder mehr liegt. Permissions-Policy wird nicht bewertet (nur Chromium-Browser lesen sie), ist aber trotzdem sinnvoll.
| Header | Empfohlener Wert | Was er verhindert |
|---|---|---|
Strict-Transport-Security | max-age=31536000; includeSubDomains | Protokoll-Downgrade, Cookie-Diebstahl über HTTP |
Content-Security-Policy | Nonce-basiertes script-src mit 'strict-dynamic'; object-src 'none'; base-uri 'none'; frame-ancestors 'none' | Cross-Site-Scripting (XSS), Dateninjektion, Clickjacking |
X-Content-Type-Options | nosniff | MIME-Sniffing, das einen Upload in ausführbares Skript verwandelt |
Referrer-Policy | strict-origin-when-cross-origin | Preisgabe vollständiger URLs (Tokens, Suchbegriffe) an Dritte |
Permissions-Policy | camera=(), microphone=(), geolocation=(), payment=() | Drittanbieter-Skripte, die unbemerkt mächtige Browser-APIs nutzen |
X-Frame-Options | DENY (Legacy-Fallback für frame-ancestors) | Clickjacking in Browsern ohne CSP Level 2 |
Cross-Origin-Opener-Policy | same-origin | Fensterübergreifende Angriffe über window.opener |
Content Security Policy einführen, ohne die Website lahmzulegen
Eine Content Security Policy ist die wirksamste Einzelmaßnahme gegen XSS, weil sie eingeschleuste Skripte selbst dann an der Ausführung hindert, wenn eine Injection-Lücke existiert. Der Haken: Eine strikte Policy bricht jedes Inline-Skript und jedes Drittanbieter-Tag, das Sie vergessen haben. Der moderne Ansatz, von Google empfohlen und auf MDN dokumentiert, ist eine Nonce-basierte Policy: Der Server erzeugt pro Antwort eine zufällige Nonce, setzt sie in jedes Script-Tag, das er bewusst ausgibt, und der Browser verweigert alles andere.
'strict-dynamic' macht die Policy praxistauglich: Ein Skript mit Nonce darf weitere Skripte nachladen (Analytics, Tag-Manager, Widgets), ohne dass jedes einzeln freigegeben werden muss, während moderne Browser die Tokens https: und 'unsafe-inline' ignorieren – sie dienen nur als Fallback für alte Browser. Führen Sie die Policy zuerst mit Content-Security-Policy-Report-Only ein, beobachten Sie eine Woche lang die Verstoßberichte und schalten Sie dann auf Durchsetzung um. Frameworks wie Next.js, Rails und Django unterstützen Nonces von Haus aus; statische Websites können stattdessen ein Hash-basiertes script-src verwenden.
Content-Security-Policy:
script-src 'nonce-r4nd0m1z3dV4lu3' 'strict-dynamic' https: 'unsafe-inline';
object-src 'none';
base-uri 'none';
frame-ancestors 'none';
form-action 'self';
report-to csp-endpoint
<!-- Only scripts carrying the nonce run; strict-dynamic lets them load their own dependencies -->
<script nonce="r4nd0m1z3dV4lu3" src="/app.js"></script>Eine Allowlist-Policy wie script-src 'self' https://cdn.example.com ist besser als nichts, doch jeder JSONP-Endpunkt und jede alte Bibliothek auf einem freigegebenen Host lässt sich zu ihrer Umgehung nutzen. Wenn Sie noch keine Nonces einsetzen können, setzen Sie zumindest object-src 'none' und base-uri 'none' – das schließt sofort zwei gängige Umgehungswege.
Clickjacking: frame-ancestors und X-Frame-Options
Beim Clickjacking wird Ihre Website unsichtbar in die Seite eines Angreifers geladen, und der Besucher wird dazu gebracht, auf einen Button zu klicken, den er nicht sieht. frame-ancestors 'none' in der CSP (oder 'self', wenn Sie eigene Seiten einbetten) verhindert das in allen aktuellen Browsern, X-Frame-Options: DENY deckt ältere ab. Bieten Sie bewusst ein einbettbares Widget an, nehmen Sie nur diesen Pfad aus – und nur für die Origins, die ihn brauchen. Unser Leitfaden zu X-Frame-Options zeigt die genauen Serverregeln und die „refused to connect“-Fehler, auf die Sie beim Testen stoßen werden.
nosniff, Referrer-Policy, Permissions-Policy und COOP
X-Content-Type-Options: nosniff hindert den Browser daran, einen Content-Type eigenmächtig anders zu deuten – genau das macht aus einem hochgeladenen „Bild“ mit HTML-Inhalt eine ausführbare Seite. Referrer-Policy: strict-origin-when-cross-origin (Standard in aktuellen Browsern, aber setzen Sie es explizit) sendet nur Ihren Origin an andere Websites, sodass Passwort-Reset-Tokens und Suchanfragen in URLs privat bleiben. Permissions-Policy deaktiviert Browserfunktionen, die Sie nicht nutzen, damit ein kompromittiertes Drittanbieter-Skript weder die Kamera öffnen noch den Standort auslesen kann. Cross-Origin-Opener-Policy: same-origin kappt die window.opener-Verbindung zu Seiten, die Sie öffnen, und blockiert damit eine Klasse fensterübergreifender Angriffe.
Auch Header, die Sie entfernen, zählen: Server und X-Powered-By verraten Schwachstellen-Scannern exakte Software-Versionen, und X-XSS-Protection ist veraltet und kann in alten Browsern Fehler verursachen – setzen Sie es auf 0 oder lassen Sie es weg. Der CMS-Detector zeigt, was jeder über Ihren Stack und dessen Versionen aus der Seite selbst erfahren kann.
Setzen Sie Header einmal zentral am Edge (CDN, Reverse Proxy oder Framework-Middleware) statt pro Seite. In Next.js ist das die Proxy- oder Middleware-Datei, in nginx ein add_header-Block im Server-Kontext, in Apache Header always set. Führen Sie den HTTP-Header-Checker anschließend nach jedem Deployment erneut aus, denn eine neue Framework-Version oder CDN-Einstellung kann stillschweigend einen Header verlieren.
Schicht 4: Authentifizierung, die Credential Stuffing standhält
Angreifer raten Passwörter selten einzeln. Sie spielen Milliarden von E-Mail-Passwort-Paaren ab, die bei anderen Websites geleakt wurden (Credential Stuffing), und phishen den Rest. Best Practices für die Authentifizierung haben daher drei Teile: Passwörter so speichern, dass ein Datenbank-Leak kein Passwort-Leak ist, ein gestohlenes Passwort allein nutzlos machen und Brute Force so verlangsamen, dass es keine Rolle spielt. OWASP führt Authentication Failures in den OWASP Top 10:2025 auf Platz A07.
Passwörter mit Argon2id oder bcrypt hashen
Speichern Sie niemals ein Passwort – und niemals einen schnellen Hash davon. MD5, SHA-1 und selbst SHA-256 sind auf Geschwindigkeit ausgelegt, sodass eine geleakte Tabelle solcher Hashes auf einer einzigen GPU mit Milliarden Versuchen pro Sekunde getestet werden kann. Verwenden Sie eine langsame, speicherintensive Passwort-Hashing-Funktion mit individuellem Salt pro Passwort. Das OWASP Password Storage Cheat Sheet empfiehlt in dieser Reihenfolge:
- Argon2id mit mindestens 19 MiB Speicher, 2 Iterationen und Parallelitätsgrad 1 (oder 46 MiB mit 1 Iteration).
- scrypt mit N = 2^17, r = 8, p = 1, wo Argon2 nicht verfügbar ist.
- bcrypt mit einem Work Factor von 10 oder höher (beachten Sie die Eingabegrenze von 72 Byte; das Vorab-Hashen längerer Passwörter erfordert Sorgfalt).
- PBKDF2-HMAC-SHA256 mit 600.000 Iterationen nur dort, wo FIPS-Konformität es erzwingt.
// Node.js with the argon2 package
import argon2 from "argon2";
const hash = await argon2.hash(password, {
type: argon2.argon2id,
memoryCost: 19456, // KiB = 19 MiB
timeCost: 2,
parallelism: 1,
});
// Later, on login:
const ok = await argon2.verify(hash, submittedPassword);Stimmen Sie die Kosten so ab, dass ein Hash auf Ihrem Login-Server etwa 100 bis 250 ms dauert. Für echte Nutzer ist das unmerklich, doch es hält jeden CPU-Kern bei einer Handvoll Versuche pro Sekunde und selbst eine High-End-Grafikkarte bei Tausenden statt Milliarden. Hashen Sie bei erfolgreichem Login neu, wann immer Sie die Parameter erhöhen – so aktualisieren sich alte Hashes von selbst.
Passwortregeln, die wirklich helfen (NIST SP 800-63B)
Die Kompositionsregeln, die die meisten Websites noch erzwingen (ein Großbuchstabe, ein Sonderzeichen, Wechsel alle 90 Tage), führen zu vorhersehbaren Passwörtern wie Summer2026! und verleiten Menschen dazu, sie wiederzuverwenden. Die aktuelle Richtlinie NIST SP 800-63B ersetzt sie durch Regeln, die messen, worauf es ankommt:
- Mindestens 8 Zeichen, wenn zusätzlich MFA verlangt wird, und mindestens 15 Zeichen für ein Passwort, das allein verwendet wird; erlauben Sie mindestens 64.
- Keine Kompositionsregeln und kein erzwungener regelmäßiger Wechsel; verlangen Sie eine Änderung nur bei Hinweisen auf eine Kompromittierung.
- Prüfen Sie jedes neue Passwort gegen eine Liste geleakter Passwörter (mit der Range-API von Have I Been Pwned geht das, ohne das Passwort zu übermitteln) und lehnen Sie bekannte ab.
- Erlauben Sie Einfügen und Passwortmanager, akzeptieren Sie Leerzeichen und Unicode und geben Sie Hinweise, die bei der Wahl eines starken Passworts helfen – besonders direkt nachdem Sie eines abgelehnt haben.
Unser Password-Strength-Tester zeigt, wie sich diese Maßnahmen von den alten Regeln unterscheiden: Er schätzt, wie lange ein Passwort unter 8 benannten Angriffen zum Knacken braucht, zeigt die Muster, die es schwächen, und gleicht es mit Leak-Daten ab, ohne das Passwort zu übertragen – ein weit nützlicheres Feedback als eine rote Meldung „Sonderzeichen erforderlich“.
MFA und Passkeys
Multi-Faktor-Authentifizierung macht ein gestohlenes Passwort zur Sackgasse. Bieten Sie sie allen an und verlangen Sie sie für Admin-, Finanz- und Support-Rollen. Ordnen Sie die Optionen nach Phishing-Resistenz: Passkeys und FIDO2-Sicherheitsschlüssel lassen sich nicht phishen, weil der Schlüssel an Ihren echten Origin gebunden ist; Authenticator-Apps (TOTP) sind gut; SMS-Codes sind besser als nichts, können aber per SIM-Swapping abgefangen werden. Passkeys werden von allen aktuellen Browsern und Betriebssystemen unterstützt und ersetzen das Passwort vollständig – womit auch Credential Stuffing als Angriffskategorie wegfällt.
Schützen Sie den Wiederherstellungsweg so sorgfältig wie den Login: Wiederherstellungscodes nur gehasht speichern, E-Mail-Resets mit Einmal-Tokens, die innerhalb von 15 Minuten ablaufen, und keine Sicherheitsfragen.
Rate Limiting, Sperren und Bot-Abwehr
Begrenzen Sie Login-, Registrierungs-, Passwort-Reset- und MFA-Endpunkte pro IP und pro Konto, und antworten Sie nach Erreichen des Limits mit 429 Too Many Requests und einem Retry-After-Header (unser Leitfaden zu HTTP-Fehler 429 erklärt, wie Clients reagieren sollten). Kombinieren Sie das mit einer wachsenden Verzögerung oder einer temporären Sperre nach wiederholten Fehlversuchen bei einem Konto sowie mit einem CAPTCHA oder einer Proof-of-Work-Challenge für Endpunkte, die verteilte Angriffe abbekommen. Protokollieren Sie jeden fehlgeschlagenen Login mit Quell-IP, damit das Muster eines Credential-Stuffing-Laufs in Minuten statt in Monaten sichtbar wird.
# nginx: 5 login attempts at once, then 1 every 12 seconds, per client IP
# (limit_req sends no Retry-After header; add one on your 429 page if clients need it)
limit_req_zone $binary_remote_addr zone=login:10m rate=5r/m;
location = /api/login {
limit_req zone=login burst=4 nodelay;
limit_req_status 429;
proxy_pass http://app;
}Halten Sie die Fehlermeldungen für „unbekannter Benutzer“ und „falsches Passwort“ identisch, und sorgen Sie für die gleiche Antwortzeit (hashen Sie ein Dummy-Passwort, wenn der Benutzer nicht existiert). Sonst dient das Login-Formular nebenbei als API zur Benutzer-Enumeration.
Sessions, Cookies und CSRF
Nach dem Login ist das Session-Cookie der Benutzer – es verdient also denselben Schutz wie das Passwort. Drei Cookie-Attribute und ein Namenspräfix erledigen den Großteil der Arbeit:
Securesorgt dafür, dass das Cookie nie über unverschlüsseltes HTTP gesendet wird und sich so nicht im öffentlichen WLAN mitschneiden lässt.HttpOnlymacht es für JavaScript unsichtbar, sodass eine XSS-Lücke es nicht auslesen kann.SameSite=Lax(oderStrictfür Admin-Panels) hält es aus Cross-Site-POST-Anfragen heraus und neutralisiert damit die meisten CSRF-Angriffe.- Das Präfix
__Host-lässt den Browser das Cookie nur akzeptieren, wenn esSecureist,Path=/und keinDomain-Attribut hat – so kann eine Subdomain es nicht überschreiben.
Set-Cookie: __Host-session=9f1c7e2a...; Path=/; Secure; HttpOnly; SameSite=Lax; Max-Age=28800Zustandsändernde Aktionen dürfen niemals per GET erreichbar sein. Ein Link wie /account/delete?id=42 lässt sich über ein <img>-Tag auf jeder beliebigen Seite auslösen, die der Nutzer besucht – ganz gleich, wie gut Ihre Cookie-Flags sind.
CSRF: Eine zweite Verteidigungslinie hinter SameSite
Cross-Site Request Forgery (CSRF) bringt einen eingeloggten Browser dazu, von einer anderen Seite aus eine zustandsändernde Anfrage an Ihre Website zu senden. SameSite-Cookies stoppen den Normalfall, doch behalten Sie für jede Nicht-GET-Anfrage eine zweite Abwehr bei: ein Anti-CSRF-Token pro Session in einem versteckten Feld oder einem eigenen Header, oder eine Prüfung, ob der Header Origin (oder Sec-Fetch-Site) zu Ihrem eigenen Origin passt. Die meisten Frameworks (Django, Rails, Laravel, Next.js Server Actions) tun das standardmäßig; der Fehler besteht darin, es für einen API-Endpunkt abzuschalten und diesen Endpunkt dann doch aus dem Browser aufzurufen.
Session-IDs, Rotation und JWTs
Erzeugen Sie Session-IDs mit mindestens 128 Bit Zufall, rotieren Sie die ID beim Login und bei jeder Rechteänderung, um Session Fixation zu verhindern, lassen Sie Sessions nach Inaktivität ablaufen und geben Sie Nutzern einen „Überall abmelden“-Button, der die Sessions serverseitig ungültig macht. Für JWTs gilt: kurzlebig halten (Minuten, mit einem widerrufbaren Refresh-Token), niemals in localStorage speichern, wo jedes Skript sie lesen kann, und einen geleakten Signaturschlüssel als vollständigen Einbruch behandeln, denn jedes jemals damit signierte Token lässt sich nun fälschen.
Eingaben validieren, Ausgaben kodieren
Injection (A05:2025) und Cross-Site-Scripting sind derselbe Fehler an verschiedenen Stellen: Daten eines Nutzers werden an einen Interpreter (SQL, die Shell, eine LDAP-Abfrage, eine HTML-Seite) übergeben, als wären sie Code. Die Lösung ist ebenfalls überall dieselbe: Daten und Code strikt trennen und niemals einen Befehl per String-Verkettung zusammenbauen.
Parametrisierte Abfragen statt zusammengebauter Strings
Verwenden Sie für SQL Prepared Statements oder ein ORM, das sie erzeugt; die Datenbank behandelt die Eingabe dann als Wert, der die Struktur der Abfrage nie verändern kann. Dieselbe Regel gilt für Shell-Befehle (ein Argument-Array übergeben, nie einen String), für NoSQL-Filter (Operator-Objekte wie {"$gt": ""} in Nutzereingaben ablehnen) und für Dateipfade (den Pfad auflösen und prüfen, dass er im vorgesehenen Verzeichnis bleibt).
// Vulnerable: the input becomes part of the query text
const rows = await db.query(`SELECT * FROM users WHERE email = '${email}'`);
// Safe: the driver sends the value separately from the query
const rows = await db.query("SELECT * FROM users WHERE email = $1", [email]);
// Python / psycopg: same idea
cur.execute("SELECT * FROM users WHERE email = %s", (email,))Output-Encoding stoppt XSS
Cross-Site-Scripting entsteht, wenn nutzergesteuerter Text in eine Seite geschrieben wird, ohne ihn für den jeweiligen Kontext zu kodieren. Moderne Template-Engines (React und JSX, Vue, Jinja2, Blade, ERB) kodieren standardmäßig; XSS entsteht heute meist über die Notausgänge: dangerouslySetInnerHTML, v-html, |safe, innerHTML sowie URLs oder Inline-Event-Handler, die aus Nutzerdaten gebaut werden. Kodieren Sie exakt für den jeweiligen Kontext, und bereinigen Sie Rich-HTML mit einer spezialisierten Bibliothek wie DOMPurify statt mit einer Regex.
| Wo die Daten landen | Kodieren als | Beispiel |
|---|---|---|
| HTML-Body | HTML-Entities | < wird zu <, " wird zu " |
| HTML-Attribut | Entities in einem Attribut mit Anführungszeichen | Attributwert immer in Anführungszeichen setzen; " und ' kodieren |
| JavaScript | Nicht in Skripttext einfügen; Daten über data--Attribute oder einen JSON-Block <script type="application/json"> übergeben | </script> in einem String wird zu \u003c/script\u003e |
| URL-Parameter | Prozentkodierung | encodeURIComponent(value) |
| CSS-Wert | Ganz vermeiden; Klassennamen aus einer Allowlist wählen | Nutzereingaben nie in style interpolieren |
SSRF, Datei-Uploads und Deserialisierung
Server-Side Request Forgery (SSRF): Ruft Ihr Server eine von Nutzern angegebene URL ab (Webhooks, Bild-Proxys, Link-Vorschauen), kann ein Angreifer ihn auf interne Dienste oder den Cloud-Metadaten-Endpunkt 169.254.169.254 richten und Zugangsdaten auslesen. Lösen Sie zuerst den Hostnamen auf, lehnen Sie private und Link-Local-Bereiche ab, deaktivieren Sie Weiterleitungen und betreiben Sie Fetcher in einem Netzwerksegment, das nichts Internes erreichen kann.
Datei-Uploads: Prüfen Sie den Typ anhand des Inhalts, nicht anhand der Dateiendung oder des vom Client gesendeten Content-Type; erzwingen Sie eine Größenbegrenzung; speichern Sie Dateien außerhalb des Web-Roots oder in einem Object Storage unter einem von Ihnen erzeugten Zufallsnamen; und liefern Sie sie nach Möglichkeit von einem separaten Origin mit nosniff und Content-Disposition: attachment aus. Ein Upload darf nie an einem Ort landen, an dem der Webserver ihn ausführt.
Deserialisierung und Mass Assignment: Deserialisieren Sie niemals nicht vertrauenswürdige Daten mit einem Format, das beliebige Klassen instanziieren kann (native Java-Serialisierung, Python pickle, PHP unserialize, YAML mit Custom Tags); verwenden Sie JSON mit einem Schema. Binden Sie Request-Bodys an eine explizite Allowlist von Feldern, damit ein Nutzer nicht "role": "admin" in ein Modell posten kann, das zufällig diese Spalte hat.
Broken Access Control: Das Risiko Nummer eins
Broken Access Control steht seit 2021 an der Spitze der OWASP Top 10 und behält diesen Platz als A01:2025. Es ist kein einzelner Bug, sondern eine Gewohnheit: zu prüfen, wer jemand ist (Authentifizierung), und dabei zu vergessen, bei jeder Anfrage zu prüfen, worauf er zugreifen darf (Autorisierung). Die klassische Form ist die Insecure Direct Object Reference: GET /api/invoices/1042 funktioniert für den Eigentümer der Rechnung – und für jeden, der die Nummer ändert.
- Standardmäßig verweigern. Jede Route braucht eine explizite Regel, die Zugriff gewährt; eine fehlende Regel bedeutet 403, nicht 200.
- Serverseitig und pro Objekt prüfen. Einen Button in der Oberfläche auszublenden ist keine Zugriffskontrolle. Jeder Lese- und Schreibzugriff muss bestätigen, dass der aktuelle Nutzer den konkreten Datensatz besitzt oder darauf zugreifen darf – auch in Bulk-Endpunkten, Exporten und Hintergrund-Jobs.
- Nicht erratbare IDs verwenden, wo es hilft (UUIDs), sich aber nie darauf verlassen: Verschleierung ist keine Autorisierung.
- CORS abriegeln.
Access-Control-Allow-Origin: *mit Credentials oder das Zurückspiegeln jedes beliebigenOriginaus der Anfrage liefert Ihre API jeder Website aus, die der Nutzer besucht. - Verzeichnislisten deaktivieren,
.git,.env, Backup- und Konfigurationsdateien auf Webserver-Ebene blockieren und Admin-Panels aus dem öffentlichen Internet heraushalten oder hinter MFA und IP-Allowlists stellen. - Autorisierungsfehler begrenzen und protokollieren. Eine Häufung von 403-Antworten aus einer Session ist ein laufender Enumerationsangriff.
// Express: ownership check on every object access
app.get("/api/invoices/:id", requireAuth, async (req, res) => {
const invoice = await Invoice.findById(req.params.id);
if (!invoice || invoice.ownerId !== req.user.id) {
return res.status(404).end(); // 404, not 403: don't confirm the record exists
}
res.json(invoice);
});Schicht 5: Abhängigkeiten und Software-Lieferkette
Der größte Teil des Codes einer typischen Webanwendung ist heruntergeladen, nicht selbst geschrieben. Deshalb debütieren Software Supply Chain Failures auf A03 der OWASP Top 10 von 2025, und deshalb hat die Ausnutzung von Schwachstellen im DBIR 2026 Phishing und gestohlene Zugangsdaten überholt. Im September 2025 schleuste ein einziger gephishter Maintainer Krypto-stehlende Malware in chalk, debug und 16 weitere npm-Pakete ein, die zusammen über zwei Milliarden Downloads pro Woche haben; jedes Projekt, das im Zeitfenster eine nicht festgelegte Version installierte, zog sie automatisch mit.
- Committen Sie ein Lockfile (
package-lock.json,yarn.lock,pnpm-lock.yaml,poetry.lock,go.sum) und installieren Sie in der CI mitnpm ci, damit Builds reproduzierbar sind und kein neues Upstream-Release ungeprüft hineinrutscht. - Scannen Sie kontinuierlich:
npm audit,pip-audit,bundler-audit, GitHub Dependabot oder Renovate für Updates und einen Container-Scanner wie Trivy oder Grype für die Betriebssystemebene. - Verzögern Sie Upgrades ohne Sicherheitsbezug um einige Tage (
minimumReleaseAgein Renovate), damit ein vergiftetes Release meist schon zurückgezogen ist, bevor Sie es übernehmen – Sicherheitspatches spielen Sie dagegen sofort ein. - Pinnen Sie Actions und Skripte von Drittanbietern in der CI auf einen Commit-SHA, und verwenden Sie Subresource Integrity (
integrity="sha384-...") für jedes Skript, das Sie von einem öffentlichen CDN laden. - Geben Sie der CI minimale Rechte: wo möglich schreibgeschützte Tokens, kurzlebige OIDC-Credentials statt langlebiger Secrets und Veröffentlichungsrechte nur für einen Release-Job.
- Erzeugen Sie beim Build eine SBOM (CycloneDX oder SPDX), damit Sie die Frage „Sind wir betroffen?“ in Minuten beantworten können, wenn die nächste CVE vom Kaliber Log4Shell auftaucht.
# Reproducible install + audit in CI
npm ci --ignore-scripts
npm audit --audit-level=high
# Pin a GitHub Action to a commit, not a floating tag
# uses: actions/checkout@v4 <- can change underneath you
# uses: actions/checkout@<full-commit-sha> # v4.2.2
# Subresource Integrity for a CDN script (hash from: openssl dgst -sha384 -binary lib.min.js | openssl base64 -A)
<script src="https://cdn.example.com/lib.min.js"
integrity="sha384-<base64-hash>"
crossorigin="anonymous"></script>npm ci --ignore-scripts blockiert die Install-Skripte, über die sich die meiste npm-Malware ausführt; aktivieren Sie Skripte danach gezielt nur für die wenigen Pakete, die wirklich einen Build-Schritt brauchen.
Wenn Sie WordPress oder ein anderes CMS betreiben, gelten dieselben Regeln für Plugins und Themes – dort beginnen die meisten CMS-Kompromittierungen. Halten Sie den Core und jedes Plugin aktuell, löschen Sie alles Ungenutzte, und prüfen Sie mit dem CMS-Detector, was ein Scanner über Ihre Versionen herausfinden kann.
Schicht 6: Server-Härtung: Ports, Patches, Secrets und Backups
Die Anwendungsschicht ist bedeutungslos, wenn der Server darunter Passwort-Logins per SSH akzeptiert, eine Datenbank auf einem öffentlichen Port betreibt oder seit seiner Einrichtung nie gepatcht wurde. Best Practices für Server sind langweilig – und genau hier dringt Ransomware ein.
Schließen Sie jeden Port, den Sie nicht bedienen
Ein öffentlicher Webserver braucht offene Ports 80 und 443 sowie SSH aus Ihrem eigenen IP-Bereich. Datenbanken (3306, 5432, 27017), Redis (6379), Elasticsearch (9200), Admin-Panels und Metrik-Endpunkte sollten nur an localhost oder ein privates Netzwerk gebunden sein. Prüfen Sie nach jeder Änderung von außen mit dem Port-Checker – das ist die Sicht, die ein Angreifer hat, und Cloud-Security-Groups sind leicht falsch zu lesen.
# Ubuntu: default-deny firewall, allow only web + SSH from your office range
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw allow from 203.0.113.0/24 to any port 22 proto tcp
sudo ufw enable # check your own IP is in that range first, or you lock yourself out
# SSH: keys only, no root password login, in a drop-in that sshd reads first
printf 'PasswordAuthentication no\nPermitRootLogin prohibit-password\n' \
| sudo tee /etc/ssh/sshd_config.d/00-hardening.conf
sudo sshd -T | grep -E '^(passwordauthentication|permitrootlogin) ' # what sshd will really use
sudo systemctl reload sshUnter Ubuntu und Debian liest sshd die Dateien in /etc/ssh/sshd_config.d/ vor dem Rest von sshd_config, und für jede Einstellung gilt der zuerst gelesene Wert. Deshalb schreiben die obigen Befehle eine Drop-in-Datei namens 00-hardening.conf: Eine Änderung weiter unten in der Hauptdatei verliert gegen das Drop-in eines Cloud-Images, das PasswordAuthentication yes setzt. Bestätigen Sie das Ergebnis mit sudo sshd -T, bevor Sie sich abmelden. Im Port-Checker erscheint ein Port, den Ihre Firewall verwirft, als filtered (keine Antwort), einer ohne lauschenden Dienst als closed: beides ist in Ordnung, open ist der, den Sie beheben sollten.
Nach Plan patchen, Secrets aus dem Code halten
Aktivieren Sie unbeaufsichtigte Sicherheitsupdates für das Betriebssystem, abonnieren Sie die Security-Mailinglisten Ihrer Runtime und Ihres Frameworks, und behandeln Sie eine kritische CVE in allem, was aus dem Internet erreichbar ist, als Aufgabe für denselben Tag. Betreiben Sie Dienste als unprivilegierte Benutzer, in Containern oder mit systemd-Sandboxing, damit ein kompromittierter Prozess nicht die ganze Maschine auslesen kann.
Secrets (Datenbankpasswörter, API-Schlüssel, Signaturschlüssel) gehören niemals ins Repository, in eine Docker-Image-Schicht oder in clientseitiges JavaScript. Laden Sie sie aus Umgebungsvariablen, die beim Deployment injiziert werden, oder aus einem Secrets-Manager, rotieren Sie sie, wenn jemand mit Zugriff das Team verlässt, und durchsuchen Sie die Repository-Historie mit einem Tool wie gitleaks – denn ein einmal committeter Schlüssel ist für immer kompromittiert, auch wenn der Commit später entfernt wird.
Ransomware-feste Backups und ein CDN davor
Befolgen Sie die 3-2-1-Regel: drei Kopien auf zwei verschiedenen Medien, eine davon außer Haus – und machen Sie mindestens eine Kopie unveränderlich oder offline, damit Ransomware, die den Server erreicht, nicht auch die Backups verschlüsseln kann. Verschlüsseln Sie Backups, schließen Sie die Datenbank und das Upload-Verzeichnis ein, und – ganz entscheidend – testen Sie regelmäßig eine Wiederherstellung. Ein Backup, aus dem nie jemand etwas wiederhergestellt hat, ist eine Hoffnung, kein Plan. Die Wiederherstellungszeit entscheidet, ob ein Vorfall ein bloßer Ausfall bleibt oder das Ende des Unternehmens bedeutet.
Stellen Sie ein CDN oder eine WAF (Cloudflare, Fastly, AWS CloudFront mit WAF oder das Pendant Ihres Hosters) vor den Origin. Es fängt volumetrische DDoS-Angriffe ab, wendet verwaltete Regeln gegen gängige Injection-Payloads und schädliche Bots an, verbirgt die IP Ihres Origins und bietet Ihnen einen Ort, um Rate Limits und Geo-Regeln durchzusetzen, ohne die Anwendung anzufassen. Beschränken Sie dann die Firewall des Origins so, dass nur die IP-Bereiche des CDN Port 443 direkt erreichen; sonst gehen Angreifer einfach daran vorbei. Der Hosting-Checker zeigt, welches CDN vor einer Website sitzt und was öffentliche Belege über den Host dahinter aussagen.
E-Mail-Authentifizierung: SPF, DKIM und DMARC
Zur Web-Sicherheit gehört auch die E-Mail, die Ihre Passwort-Resets, Rechnungen und Support-Antworten transportiert. Ohne SPF, DKIM und DMARC kann jeder Mail als billing@yourdomain.com versenden, und seit Februar 2024 verlangen Google und Yahoo alle drei von Massenversendern, Microsoft seit Mai 2025 dasselbe für Outlook.com. Das vollständige Set sind drei DNS-TXT-Einträge:
yourdomain.com. TXT "v=spf1 include:_spf.google.com -all"
google._domainkey.yourdomain.com. TXT "v=DKIM1; k=rsa; p=MIIBIjANBgkq..."
_dmarc.yourdomain.com. TXT "v=DMARC1; p=reject; rua=mailto:dmarc@yourdomain.com; adkim=s; aspf=s"DMARC p=reject ist zugleich eine Maßnahme zum Markenschutz: Nur so verhindern Sie, dass eine Phishing-Kampagne exakt Ihre Domain in die Absenderzeile setzt. Die aggregierten Berichte (rua=) zeigen Ihnen, wer es versucht.
Starten Sie DMARC mit p=none, um Berichte zu sammeln, und wechseln Sie zu p=quarantine und dann zu p=reject, sobald jeder legitime Absender (Marketing-Plattform, Helpdesk, CRM) das Alignment besteht. Ergänzen Sie MTA-STS- und TLS-RPT-Einträge, um die verschlüsselte Zustellung an Ihre Mailserver zu erzwingen. Veröffentlichen Sie auf Domains, die nie Mail senden oder empfangen, einen Null-MX (MX 0 .), v=spf1 -all und einen DMARC-Eintrag mit p=reject: Der Null-MX sagt nur, dass die Domain keine Mail annimmt – erst SPF und DMARC lassen Empfänger Fälschungen ablehnen. Prüfen Sie jeden Eintrag mit dem SPF-Checker, dem DKIM-Checker und dem DMARC-Checker und gleichen Sie Ihre Versand-IPs bei sinkender Zustellbarkeit mit dem IP-Blacklist-Checker gegen Sperrlisten ab.
Protokollieren, überwachen und für den Ernstfall planen
Zwei der zehn OWASP-Kategorien von 2025 drehen sich darum, was nach einem Fehler passiert: Security Logging and Alerting Failures (A09) und die neue Kategorie Mishandling of Exceptional Conditions (A10). Der typische Einbruch bleibt noch immer monatelang unentdeckt, weil die Spuren nie aufgezeichnet wurden – oder aufgezeichnet wurden und niemand hingesehen hat.
- Protokollieren Sie Sicherheitsereignisse mit Kontext: jeden erfolgreichen und fehlgeschlagenen Login, MFA-Änderungen, Passwort-Resets, Rechteänderungen, verweigerte Zugriffe, fehlgeschlagene Eingabevalidierungen und Admin-Aktionen, jeweils mit Zeitstempel, Benutzer-ID, Quell-IP und User-Agent.
- Protokollieren Sie niemals Secrets: Passwörter, Session-Tokens, vollständige Kartennummern, API-Schlüssel. Maskieren Sie sie in der Logging-Schicht, nicht an jeder einzelnen Aufrufstelle.
- Leiten Sie Logs vom Server weg in einen zentralen Speicher (CloudWatch, Loki, Elastic, ein SIEM) mit mindestens 90 Tagen Aufbewahrung, damit ein Angreifer mit Root-Rechten seine Spuren nicht verwischen kann.
- Alarmieren Sie bei Mustern, nicht bei Einzelereignissen: 50 fehlgeschlagene Logins in einer Minute, eine Häufung von 403-Antworten aus einer Session, ein außerhalb der Geschäftszeiten angelegter neuer Admin, ein Zertifikat für Ihre Domain, das Sie nicht beantragt haben.
- Im Zweifel blockieren (Fail Closed): Wenn eine nachgelagerte Prüfung (Auth-Dienst, Rate Limiter, WAF) einen Fehler liefert, lehnen Sie die Anfrage ab. A10 gibt es, weil so viele Systeme Zugriff gewähren, wenn die Prüfung, die ihn hätte blockieren sollen, eine Exception wirft.
- Von außen überwachen: Verfügbarkeit, Zertifikatsablauf, DNS-Änderungen, Sperrlisten-Einträge und Header-Rückschritte. Führen Sie nach jedem Deployment den SSL-Checker, den HTTP-Header-Checker und den DNS-Health-Check (40 Prüfungen zu Delegation, Nameservern, DNSSEC und SPF/DMARC) erneut aus.
Schreiben Sie den Incident-Response-Plan, bevor Sie ihn brauchen
Legen Sie vorab fest, wer Bereitschaft hat, wie alle Zugangsdaten rotiert werden, wie Sie die Website in den Nur-Lese-Modus versetzen, wo die sauberen Backups liegen und welche Aufsichtsbehörde oder Kunden innerhalb von wie vielen Stunden informiert werden müssen (72 nach DSGVO). Führen Sie einmal im Jahr eine Tabletop-Übung durch. Ein geübter Plan macht aus Tagen des Improvisierens eine Checkliste.
Veröffentlichen Sie eine security.txt-Datei unter /.well-known/security.txt (RFC 9116) mit einer Contact:-Zeile und einem Expires:-Datum – den beiden Pflichtfeldern (ein Encryption:-Schlüssel ist optional). Sicherheitsforscher, die einen Bug in Ihrer Website finden, schauen zuerst dort nach; ohne sie finden sie womöglich niemanden, dem sie es melden können.
Testen: Scanner, Penetrationstests und laufende Prüfungen
Jede Maßnahme oben lässt sich überprüfen, und die Prüfung sollte wo immer möglich automatisiert sein, damit sie nicht verkümmert. Eine sinnvolle Stufenleiter, von kostenlos und sofort bis periodisch und kostenpflichtig:
| Prüfung | Tool | Wie oft |
|---|---|---|
| TLS-Konfiguration, Kette, Ablauf | SSL-Checker, SSL Labs, testssl.sh | Nach jeder Zertifikats- oder Serveränderung; Ablauf täglich |
| Sicherheitsheader und CSP | HTTP-Header-Checker, MDN HTTP Observatory | Nach jedem Deployment (in die CI aufnehmen) |
| Offene Ports | Port-Checker, nmap von außerhalb Ihres Netzwerks | Nach jeder Firewall- oder Cloud-Änderung |
| DNS, DNSSEC, E-Mail-Authentifizierung | DNS-Health-Check, DMARC-Checker | Monatlich und nach jeder DNS-Änderung |
| Veraltete Subdomains | Subdomain-Finder | Vierteljährlich und bei jeder Stilllegung |
| Abhängigkeiten mit bekannten Schwachstellen | npm audit, Dependabot, Trivy | Bei jedem Build |
| Schwachstellen im Code (SAST) | Semgrep, CodeQL | Bei jedem Pull Request |
| Web-Schwachstellen zur Laufzeit (DAST) | ZAP, Nuclei | Wöchentlich gegen Staging |
| Autorisierung und Geschäftslogik | Manueller Penetrationstest oder Bug-Bounty-Programm | Jährlich und nach größeren Features |
Scanner sind gut bei Injection, Headern und veralteten Komponenten und schlecht bei Autorisierung und Geschäftslogik – planen Sie daher für alles, was mit Geld oder personenbezogenen Daten umgeht, mindestens einen manuellen Test pro Jahr ein. Beheben Sie Funde nach Angriffsfläche: Was ein nicht angemeldeter Nutzer aus dem Internet ausnutzen kann, kommt zuerst.
Die Checkliste für Website-Sicherheit
Kopieren Sie sie in die README Ihres Projekts oder in Ihren Ticket-Tracker. Jede Zeile entspricht einer der Maßnahmen oben und ist so formuliert, dass sie sich als erledigt oder nicht erledigt abhaken lässt; die letzte Spalte ist der Nachweis.
| Schicht | Maßnahme | Erledigt, wenn |
|---|---|---|
| Domain | Registrar Lock und MFA für das Registrar-Konto; automatische Verlängerung aktiv | WHOIS zeigt clientTransferProhibited; Ablauf mehr als 12 Monate entfernt |
| DNS | DNSSEC-signiert; CAA-Eintrag nennt nur Ihre CAs | dig +dnssec liefert RRSIG; DS-Eintrag in der übergeordneten Zone vorhanden |
| DNS | Keine verwaisten CNAME- oder A-Einträge | Jeder Hostname aus dem Subdomain-Finder zeigt auf etwas, das Sie kontrollieren |
| TLS | Nur TLS 1.2+, TLS 1.3 bevorzugt, vollständige Kette ausgeliefert | SSL-Checker: Kette vollständig, TLS 1.0/1.1 abgelehnt |
| TLS | HSTS mit einem Jahr max-age und includeSubDomains (Preload optional) | Der HTTP-Header-Checker besteht den HSTS-Test |
| TLS | Erneuerung per ACME automatisiert; Ablauf überwacht | certbot renew --dry-run läuft durch; Alarm bei 14 Tagen eingerichtet |
| Header | CSP (Nonce-basiert), frame-ancestors, nosniff, Referrer-Policy, Permissions-Policy | HTTP-Header-Checker: Note A oder A+ |
| Auth | Hashing mit Argon2id oder bcrypt; NIST-Passwortregeln; Abgleich mit Leak-Listen | Ein Hash dauert 100 bis 250 ms; keine Kompositionsregeln |
| Auth | MFA für alle angeboten, für Admins Pflicht; Passkeys unterstützt | Admin-Login ohne zweiten Faktor unmöglich |
| Auth | Login-, Reset- und MFA-Endpunkte pro IP und pro Konto begrenzt | Sechs schnelle Versuche von einer IP: der sechste liefert 429 |
| Sessions | __Host--Cookie mit Secure, HttpOnly, SameSite; ID beim Login rotiert | Cookie-Attribute in den DevTools sichtbar; alte Session nach Login ungültig |
| Eingaben | Überall parametrisierte Abfragen; Ausgabe kontextgerecht kodiert; Uploads anhand des Inhalts validiert | Codesuche findet keine zusammengebauten Query-Strings; XSS-Payloads erscheinen als Text |
| Zugriffskontrolle | Routing nach Deny-by-Default; Eigentümerprüfung pro Objekt; strikte CORS-Regeln | Abspielen fremder IDs liefert 404 oder 403 |
| Abhängigkeiten | Lockfile committet; npm ci; Audit in der CI; Actions auf SHA gepinnt; SRI für CDN-Skripte | Build schlägt bei einer CVE mit hohem Schweregrad fehl |
| Server | Nur 80 und 443 öffentlich; SSH nur mit Schlüssel; unbeaufsichtigte Sicherheitsupdates; Secrets in Env oder Vault | Der Port-Checker zeigt 3306 und 6379 als closed oder filtered, und 22 ebenfalls von außerhalb Ihres eigenen Bereichs |
| Backups | 3-2-1 mit einer unveränderlichen Kopie; Wiederherstellung getestet | Letzter erfolgreicher Wiederherstellungstest liegt höchstens 90 Tage zurück |
SPF -all, DKIM, DMARC p=reject, MTA-STS | DMARC-Checker besteht; aggregierte Berichte gehen ein | |
| Monitoring | Authentifizierungs- und Autorisierungsereignisse zentral protokolliert; Alarme bei Mustern; externes Monitoring von Verfügbarkeit, Zertifikaten und DNS | Testalarm ausgelöst und empfangen |
| Reaktion | Schriftlicher Incident-Plan; security.txt veröffentlicht; Tabletop-Übung durchgeführt | Plan in den letzten 12 Monaten überprüft |
So passt das zu den OWASP Top 10:2025
Die OWASP Top 10 sind die meistzitierte Liste von Risiken für Webanwendungen; die Ausgabe 2025 hat die Reihenfolge neu gemischt und zwei neue Kategorien eingeführt. Wenn ein Kunde, Auditor oder Compliance-Framework fragt, wie Sie damit umgehen, ist dies die Zuordnung zu den Maßnahmen in diesem Leitfaden:
| OWASP Top 10:2025 | Maßnahmen in diesem Leitfaden |
|---|---|
| A01 Broken Access Control | Deny by Default, Prüfungen pro Objekt, strikte CORS-Regeln, abgeschottete Admin-Bereiche |
| A02 Security Misconfiguration | Sicherheitsheader, HSTS, geschlossene Ports, entfernte Versions-Header, Verzeichnislisten deaktiviert |
| A03 Software Supply Chain Failures (neu) | Lockfiles, Audits, gepinnte Actions, SRI, SBOM, CI mit minimalen Rechten |
| A04 Cryptographic Failures | TLS 1.2+ und 1.3, HSTS, Argon2id, Secrets-Management, verschlüsselte Backups |
| A05 Injection | Parametrisierte Abfragen, Output-Encoding, CSP, Upload-Validierung |
| A06 Insecure Design | Bedrohungsmodell pro Schicht, Fail-Closed-Voreinstellungen, Rate Limiting als Designprinzip |
| A07 Authentication Failures | NIST-Passwortregeln, Leak-Prüfungen, MFA und Passkeys, Session-Rotation |
| A08 Software or Data Integrity Failures | SRI, signierte und gepinnte Abhängigkeiten, sichere Deserialisierung |
| A09 Security Logging and Alerting Failures | Zentrales Logging, Alarme bei Mustern, externes Monitoring |
| A10 Mishandling of Exceptional Conditions (neu) | Fail Closed, einheitliche Fehlerantworten, keine Stacktraces an Nutzer |
Der ASVS von OWASP (Application Security Verification Standard) macht aus demselben Material eine nummerierte Checkliste für Audits. Level 1 ist ein realistisches Ziel für jede öffentliche Website, Level 2 für alles, was personenbezogene oder finanzielle Daten verarbeitet.
Prüfen Sie die Sicherheitsheader Ihrer Website in Sekunden
Der kostenlose HTTP-Header-Checker von DNS Robot zeigt die Antwort-Header jeder URL genau so, wie der Server sie sendet, und bewertet die Sicherheitsheader mit den Tests des Mozilla HTTP Observatory – mit der Lösung für jeden fehlenden. Ohne Anmeldung.
Quellen
- 2026 Data Breach Investigations Report, Verizon
- OWASP Top 10:2025, OWASP
- Password Storage Cheat Sheet, OWASP
- SP 800-63B-4: Authentication and Authenticator Management, NIST
- Ballot SC-081v3: reducing certificate validity and data reuse periods, CA/Browser Forum
- HTTPS by default, Google
- RFC 9116: A File Format to Aid in Security Vulnerability Disclosure, IETF
Häufige Fragen zur Website-Sicherheit
Was sind die wichtigsten Best Practices für Website-Sicherheit?
Was sind die OWASP Top 10 und sind sie 2026 noch relevant?
Welche HTTP-Security-Header sollte jede Website senden?
Reicht HTTPS aus, um eine Webseite abzusichern?
Wie speichere ich Benutzerpasswörter sicher?
Was ist eine Content Security Policy und brauche ich eine?
Wie prüfe ich, ob meine Website sicher ist?
Warum werden TLS-Zertifikate immer kurzlebiger?
Wie oft sollte ich die Abhängigkeiten meiner Website aktualisieren?
Werden kleine Websites wirklich angegriffen?
Verwandte Artikel
Verwandte Tools
HTTP-Header-Checker
HTTP-Antwort-Header und Sicherheits-Header-Bewertung analysieren
SSL-Zertifikat-Check
Gültigkeit und Sicherheitsdetails des SSL-Zertifikats überprüfen
Port-Checker
Port-Konnektivität und Service-Verfügbarkeit testen
DNS-Health-Check
DNS einer Domain bewerten: Delegation, Nameserver, SOA, DNSSEC, Mail · 40 Tests
DMARC-Check
DMARC-Richtlinie und Alignment-Einstellungen für jede Domain prüfen
Subdomain-Finder
Alle Subdomains einer Domain entdecken



