EN DE

Content Security Policy in Apache (.htaccess)

Eine Content Security Policy schränkt ein, welche Ressourcen der Browser auf Ihrer Apache-Website laden darf. Diese Anleitung zeigt das minimale, funktionierende Deployment: mod_headers aktivieren, Header in .htaccess eintragen, im Report-Only-Modus testen, dann auf Enforcing umschalten. Fünf Minuten Ende-zu-Ende, sobald mod_headers läuft.

Voraussetzung: mod_headers aktivieren

Apaches mod_headers-Modul ist das was der .htaccess erlaubt, Response-Header zu setzen. Auf Debian/Ubuntu-Derivaten:

sudo a2enmod headers
sudo systemctl restart apache2

Auf RHEL/CentOS/Fedora die /etc/httpd/conf/httpd.conf öffnen und sicherstellen, dass diese Zeile vorhanden und nicht auskommentiert ist:

LoadModule headers_module modules/mod_headers.so

Apache danach neu starten. Mit apachectl -M | grep headers prüfen Sie, ob das Modul wirklich geladen ist.

Das minimale .htaccess-Snippet

Öffnen Sie die .htaccess-Datei im Document-Root (oder legen Sie sie an, falls sie nicht existiert) und fügen Sie Folgendes ein:

<IfModule mod_headers.c>
  Header always set Content-Security-Policy-Report-Only "default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; font-src 'self'"
</IfModule>

Ein paar Dinge zum Merken:

Testen

Seite neu laden, DevTools (F12) → Konsole. Sie sehen rote Warnungen für jede Ressource die blockiert werden würde, z. B.:

[Report Only] Refused to load the script 'https://cdn.example.com/analytics.js' because it violates the following Content Security Policy directive: "script-src 'self' 'unsafe-inline'".

Jede dieser Zeilen ist eine echte Ressource die Ihre Seite lädt und die die aktuelle Policy nicht abdeckt. Sie haben zwei Optionen: Domain in die passende Direktive aufnehmen, oder die Abhängigkeit loswerden. Iterieren bis die Konsole sauber ist.

Der schnellere Weg: Lassen Sie unseren kostenlosen Scanner über Ihre Seite laufen. Er crawlt jede Unterseite, findet alle externen Ressourcen und generiert die exakte CSP die Sie brauchen — ohne Trial and Error. Das Ergebnis können Sie direkt in die .htaccess einfügen.

In den Enforcing-Modus wechseln

Sobald die Konsole ruhig bleibt, ändern Sie den Header-Namen von Content-Security-Policy-Report-Only zu Content-Security-Policy und laden neu:

<IfModule mod_headers.c>
  Header always set Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; font-src 'self'"
</IfModule>

Fertig. Ihre Seite setzt jetzt eine CSP durch. Ab diesem Moment wird jeder Verstoß vom Browser wirklich blockiert, nicht nur gemeldet.

Typische Fehlerquellen

„mod_headers is not loaded"

Wenn das im Apache-Error-Log auftaucht, haben Sie die Voraussetzung übersprungen. sudo a2enmod headers && sudo systemctl restart apache2 (Debian/Ubuntu) oder die LoadModule-Zeile in der httpd.conf auskommentieren.

Der Header ist da, aber die Policy wird ignoriert

Prüfen Sie, ob an einer anderen Stelle ein zweiter CSP-Header gesetzt wird (von PHP, einer VirtualHost-Datei, einer anderen .htaccess). Wenn mehrere Content-Security-Policy-Header gesendet werden, nehmen Browser die Schnittmenge — und die ist oft restriktiver als beabsichtigt. Mit curl -I https://ihre-seite.example sehen Sie alle Header. Duplikate eliminieren und nur den einen aus .htaccess behalten.

WordPress/PHP-Anwendungen brauchen 'unsafe-inline'

Die meisten CMS und PHP-Frameworks erzeugen Inline-<script>- und <style>-Blöcke. Ohne 'unsafe-inline' in script-src und style-src bricht die Seite. Die striktere Alternative wären Nonces oder Hashes, aber das erfordert Code-Anpassungen — Details in der WordPress-Anleitung.

CORS und CSP sind zwei verschiedene Dinge

Ein häufiges Missverständnis: Wenn Ihre Seite beim Laden einer Ressource blockiert wird, kann das CORS (Access-Control-Allow-Origin) sein und nicht CSP. CSP regelt was Ihre Seite laden darf; CORS regelt, ob der andere Server bereit ist, von Ihrer Seite aus geladen zu werden. Beide können Ressourcen blockieren, die Lösung ist jeweils eine andere.

Dev-Server mit Hot-Reload

Webpack Dev Server, Vite, Next.js im Dev-Modus — die injizieren alle Inline-Skripte für Hot Reloading. Wenn Ihre CSP das blockiert, bricht die Dev-Umgebung zusammen. Lösung: die strikte CSP nur in Produktion ausrollen. In Apache lässt sich das über SetEnvIf lösen, oder einfach indem die .htaccess mit der CSP nur in Produktion deployt wird.

Apache-spezifische Feinheiten

.htaccess und Performance

Jede Direktive in der .htaccess wird bei jedem Request neu ausgewertet. Für ein einzelnes Header set ist der Overhead vernachlässigbar, aber wenn Sie maximale Performance wollen, verschieben Sie die Direktive in den VirtualHost-Block unter /etc/apache2/sites-enabled/ihre-seite.conf und deaktivieren .htaccess komplett mit AllowOverride None. Gleiche Syntax, kein Overhead pro Request.

Header append vs. Header set

Nehmen Sie immer set, niemals append. append würde mehrere CSP-Werte aneinanderhängen, und Browser behandeln das als Schnittmenge — in der Regel nicht das was Sie wollen.

Reporting-Endpoints

Sobald Sie im Enforcing-Modus sind, lohnt sich eine report-uri-Direktive, damit Sie Verstöße sehen die draußen in freier Wildbahn passieren (nicht nur bei Ihren eigenen Tests):

Header always set Content-Security-Policy "default-src 'self'; ... ; report-uri https://ihr-reporting-endpunkt.example/csp"

Dienste wie report-uri.com bieten kostenlose Stufen; Sie können aber auch selber einen Collector hosten.

Ihre exakte CSP in 30 Sekunden generieren → Wir crawlen Ihre Seite, finden jede Ressource, und spucken einen .htaccess-Block aus der zu Ihrem echten Stack passt — kein Rumraten