Website-Sicherheit: Best Practices Schicht für Schicht (2026)

Advertisement
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.
In Schichten zu denken lohnt sich, weil Angreifer genau das tun. Laut Verizons 2026 Data Breach Investigations Report beginnen 31 % aller Datenpannen inzwischen mit einer ausgenutzten Software-Schwachstelle – damit liegt dieser Einstiegsweg erstmals vor gestohlenen Zugangsdaten –, und 48 % aller Datenpannen gehen mit Ransomware einher. Ein einziger fehlender Patch, ein geleakter 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 und eine andere auf Hochglanz poliert haben.
Dieser Leitfaden arbeitet sich von außen nach innen vor. Zu jeder Maßnahme erfahren Sie, warum sie wichtig ist, was genau Sie konfigurieren müssen und wie Sie sie überprüfen – per Befehl oder mit einem kostenlosen Tool. Denn der häufigste Fehler, den wir bei HTTP-Header-Checks und SSL-Checks sehen, ist keine schlechte Entscheidung, sondern eine Einstellung, von der jemand glaubte, sie sei aktiv, und die nie überprüft wurde.
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-Lookup, Subdomain-Finder |
| 2. Transport (TLS) | Herabstufung auf HTTP, Verschlüsselung aushebeln, alte Cipher ausnutzen, abgelaufene Zertifikate | TLS 1.2+, HSTS mit Preload, automatische 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, OWASP 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, Domain-Health-Check |
Advertisement
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 einem Zahlungsmittel, das nicht abläuft, und legen Sie trotzdem 60 Tage vor dem Ablaufdatum eine Kalendererinnerung an. Abgelaufene Domains schnappen sich Drop-Catcher innerhalb von Stunden, und 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 vergiftet, Ihre Besucher auf einen gefälschten Server schicken, während deren 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 das Hinterlegen des DS-Eintrags bei Ihrem Registrar. Prüfen Sie es mit dig oder mit dem DNSSEC-Test im Domain-Health-Check:
dig +dnssec +short yourdomain.com A
# A signed zone returns the record AND an RRSIG line:
# 203.0.113.10
# A 13 2 3600 20261015000000 20260924000000 34505 yourdomain.com. Kx3f...==
dig +short yourdomain.com DS
# A DS record at the parent zone proves the chain of trust is complete
# 34505 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 passiert, 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 Ihrem Namen Inhalte auf old-app.yourdomain.com ausliefern – samt gültigem Zertifikat. Es ist einer der häufigsten Funde in Bug-Bounty-Programmen, weil sich niemand mehr an den Eintrag erinnert.
Prüfen Sie Ihre Domain mit dem Subdomain-Finder, der Certificate-Transparency-Logs auswertet – so sehen Sie jeden Hostnamen, für den jemals ein Zertifikat ausgestellt wurde. Lösen Sie dann jeden davon per DNS-Lookup auf und löschen Sie jeden Eintrag, dessen Ziel NXDOMAIN oder die „no such app“-Seite eines Anbieters liefert. Wiederholen Sie das vierteljährlich, und machen Sie das Löschen des DNS-Eintrags zum festen Bestandteil jeder Stilllegung eines Dienstes.
Schicht 2: HTTPS und TLS richtig umsetzen
HTTPS ist keine Best Practice mehr, sondern die Grundvoraussetzung – Browser markieren reine HTTP-Seiten als „Nicht sicher“. Was eine sichere Website heute noch von einer lediglich verschlüsselten unterscheidet, sind die akzeptierten TLS-Versionen, die Frage, ob HTTP überhaupt noch zu Ihnen führen kann, und ob die Erneuerung so gut automatisiert ist, dass sie die im März 2026 begonnenen Kürzungen der Zertifikatslaufzeit übersteht.
Advertisement
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.
Beim Test von außen zählen zwei Zeilen: das ausgehandelte Protokoll und Verify return code: 0, was bedeutet, dass die vollständige Zertifikatskette validiert wurde. Ein fehlendes Zwischenzertifikat ist die häufigste Ursache für Meldungen nach dem Muster „funktioniert in Chrome, scheitert in curl und auf Android“; unser Leitfaden zur SSL-Zertifikatskette zeigt, wie Sie das beheben, und der SSL-Checker meldet eine unvollständige Kette direkt. Hier der Test gegen dnsrobot.net:
echo | openssl s_client -connect dnsrobot.net:443 -servername dnsrobot.net 2>/dev/null \
| grep -E 'Protocol|Cipher|Verify return'
# Protocol : TLSv1.3
# Cipher : TLS_AES_256_GCM_SHA384
# Verify return code: 0 (ok)
# Confirm the old versions are refused:
openssl s_client -connect dnsrobot.net:443 -tls1_1 2>&1 | grep -iE 'alert|no protocols'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.
Setzen Sie max-age auf mindestens ein Jahr (31536000 Sekunden), ergänzen Sie includeSubDomains, sobald jede Subdomain HTTPS ausliefert, und tragen Sie die Domain dann auf hstspreload.org ein, damit sie fest in Chrome, Firefox, Safari und Edge eingebaut wird. Das Preloading schließt die Lücke beim ersten Besuch vollständig. Prüfen Sie den Header mit dem HTTP-Header-Checker, der HSTS als Teil seiner Sicherheitsnote von A bis F bewertet.
Strict-Transport-Security: max-age=31536000; includeSubDomains; preload47-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 in einen Frame eingebettet werden darf, ob der Browser Content-Types raten darf und was er anderen Websites darüber verrät, woher ein Besucher kam. Sie kosten nichts, gelten für alle Seiten zugleich und blockieren ganze Angriffsklassen. Gleichzeitig ist es die Schicht, die die meisten Websites teilweise falsch umsetzen – deshalb bewertet der HTTP-Header-Checker sie. Das sendet dnsrobot.net, gekürzt auf die Sicherheitsheader:
curl -sI https://dnsrobot.net/ | grep -iE 'strict-transport|content-security|x-frame|x-content-type|referrer-policy|permissions-policy'
strict-transport-security: max-age=31536000; includeSubDomains; preload
content-security-policy: default-src 'self'; script-src 'self' ... https://*.googletagmanager.com; frame-ancestors 'none'; base-uri 'self'; form-action 'self'
x-frame-options: DENY
x-content-type-options: nosniff
referrer-policy: strict-origin-when-cross-origin
permissions-policy: camera=(self), microphone=(), geolocation=(), payment=(), usb=()Die sieben Header, die jede Website senden sollte
Das sind die Zielwerte für eine typische Website. Die ersten fünf verbessern Ihre Bewertung; die letzten beiden sind günstige Ergänzungen, sobald die anderen stehen.
| Header | Empfohlener Wert | Was er verhindert |
|---|---|---|
Strict-Transport-Security | max-age=31536000; includeSubDomains; preload | 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>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 sollten, sind wichtig: Server und X-Powered-By verraten Schwachstellenscannern die genauen Softwareversionen, und X-XSS-Protection ist veraltet und kann in alten Browsern Fehler verursachen – setzen Sie ihn auf 0 oder lassen Sie ihn weg. Der CMS-Detector zeigt, was ein Scanner allein aus den Headern über Ihren Stack erfährt.
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.
Advertisement
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);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 Passwort-Manager, akzeptieren Sie Leerzeichen und Unicode, und zeigen Sie eine Stärkeanzeige, die auf Entropie statt auf Regeln basiert.
Unser Passwort-Stärke-Test zeigt, wie sich diese Kriterien von den alten Regeln unterscheiden: Er schätzt die Knackzeit anhand von Entropie und Mustererkennung und gleicht das Passwort mit Leak-Daten ab – ein weit nützlicheres Feedback als ein rotes „Sonderzeichen fehlt“.
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 per minute per client IP
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;
}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=28800CSRF: 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.
Advertisement
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
Eine typische Webanwendung besteht vielleicht zu 5 % aus selbst geschriebenem und zu 95 % aus heruntergeladenem Code. Deshalb steigt Software Supply Chain Failures in den OWASP Top 10 von 2025 direkt auf A03 ein, und deshalb hat die Ausnutzung von Schwachstellen im DBIR 2026 gestohlene Zugangsdaten überholt. Im September 2025 schleuste ein einziger per Phishing kompromittierter Maintainer Malware zum Stehlen von Kryptowährungen in chalk, debug und 16 weitere npm-Pakete ein, die zusammen über zwei Milliarden Downloads pro Woche verzeichnen; jedes Projekt, das in diesem Zeitfenster eine nicht gepinnte 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>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
# SSH: keys only, no root password login
sudo sed -i 's/^#\?PasswordAuthentication.*/PasswordAuthentication no/' /etc/ssh/sshd_config
sudo sed -i 's/^#\?PermitRootLogin.*/PermitRootLogin prohibit-password/' /etc/ssh/sshd_config
sudo systemctl reload sshNach 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-Server. Es fängt volumetrische DDoS-Angriffe ab, wendet verwaltete Regeln gegen gängige Injection-Payloads und bösartige Bots an, verbirgt Ihre Origin-IP 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; andernfalls gehen Angreifer einfach außen herum. Der Hosting-Checker zeigt, ob der echte Origin einer Website hinter ihrem CDN offenliegt.
E-Mail-Authentifizierung: SPF, DKIM und DMARC
Zur Websicherheit gehört auch die E-Mail, über die Ihre Passwort-Resets, Rechnungen und Support-Antworten laufen. Ohne SPF, DKIM und DMARC kann jeder E-Mails als billing@yourdomain.com versenden, und seit Februar 2024 verlangen Google und Yahoo alle drei von Massenversendern. Der komplette Satz besteht aus drei DNS-TXT-Einträgen:
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"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 verschlüsselte Zustellung an Ihre Mailserver zu erzwingen, und veröffentlichen Sie auf Domains, die nie E-Mails versenden, einen Null-MX (MX 0 .), damit sie sich gar nicht erst fälschen lassen. Prüfen Sie jeden Eintrag mit dem SPF-Checker, DKIM-Checker und DMARC-Checker, und gleichen Sie Ihre Versand-IPs mit dem IP-Blacklist-Checker gegen Blocklisten ab, wenn die Zustellbarkeit sinkt.
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.
Überwachen Sie von außen: Verfügbarkeit, Zertifikatsablauf, DNS-Änderungen, Blocklisteneinträge und Header-Regressionen. Der Domain-Health-Check bündelt DNS-, SSL-, E-Mail-Authentifizierungs- und Header-Tests in einer Bewertung, die Sie nach jedem Deployment erneut ausführen können.
Schreiben Sie den Incident-Response-Plan, bevor Sie ihn brauchen
Legen Sie vorab fest, wer Rufbereitschaft hat, wie jedes Credential rotiert wird, wie Sie die Website in einen Nur-Lese-Modus versetzen, wo die sauberen Backups liegen und welche Aufsichtsbehörde oder welche Kunden innerhalb wie vieler Stunden zu benachrichtigen sind (72 nach der DSGVO). Führen Sie einmal im Jahr eine Tabletop-Übung durch. Teams mit einem geprobten Plan erholen sich in Tagen; Teams ohne Plan improvisieren wochenlang.
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 | Nach jeder Firewall- oder Cloud-Änderung |
| DNS, DNSSEC, E-Mail-Authentifizierung | Domain-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) | OWASP 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, includeSubDomains, im Preload | Auf hstspreload.org gelistet |
| 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 |
| 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 | Sechster Versuch innerhalb einer Minute 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 | Port-Checker zeigt 22, 3306 und 6379 aus dem Internet geschlossen |
| 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 |
Prüfen Sie die Sicherheitsheader Ihrer Website in Sekunden
Der kostenlose HTTP-Header-Checker von DNS Robot ruft jede URL ab und bewertet ihre Sicherheitsheader von A bis F: HSTS, Content-Security-Policy, X-Frame-Options, X-Content-Type-Options, Referrer-Policy und Permissions-Policy – mit dem exakt gefundenen Wert und allem, was fehlt. Ohne Anmeldung.
Testen HTTP-Header-CheckerAdvertisement
Häufige Fragen zur Website-Sicherheit
Erzwingen Sie HTTPS mit modernem TLS und HSTS, senden Sie strikte Sicherheitsheader (vor allem eine Content Security Policy), hashen Sie Passwörter mit Argon2id und sichern Sie Logins mit MFA und Rate Limiting ab, verwenden Sie parametrisierte Abfragen und Output-Encoding, setzen Sie die Zugriffskontrolle serverseitig für jedes Objekt durch, halten Sie Abhängigkeiten gepatcht und gepinnt, schließen Sie ungenutzte Ports und protokollieren Sie Sicherheitsereignisse zentral. Sichern Sie zuerst Domain und DNS ab, denn alles andere setzt voraus, dass Sie Ihren Namen noch kontrollieren.