Security-Header-Architektur für PHP

Alle Security Headers zentral verwalten — mit auto_prepend_file für vanilla PHP oder PSR-15 Middleware für Frameworks. Eine Datei, alle Header, jeder Request.

PHP · Schritt für Schritt

Security-Header-Architektur in PHP

Security Headers schützen Ihre PHP-Anwendung vor XSS, Clickjacking, MIME-Sniffing und weiteren Angriffen. Der Wolf-Agents Web Security Check bewertet 166 Prüfpunkte — eine konsolidierte Architektur stellt sicher, dass alle Header konsistent gesetzt werden.

In PHP gibt es drei Architektur-Ansätze: auto_prepend_file über die .user.ini für zentrale Header-Verwaltung ohne Code-Änderungen (ideal für vanilla PHP und Shared Hosting), PSR-15 Middleware für Framework-basierte Projekte, und direkte header()-Aufrufe für einfache Scripts. Diese Anleitung zeigt alle drei Wege.

1 Schritt 1 von 4

Zentrale Security-Headers-Datei erstellen

Erstellen Sie eine eigene PHP-Datei, die alle Security Headers über header()-Aufrufe setzt. Die Datei prüft mit headers_sent(), ob Header noch gesendet werden können, und generiert einen CSP-Nonce mit random_bytes().

security-headers.php Produktiv
<?php
// security-headers.php — Zentrale Header-Datei
// Eingebunden über auto_prepend_file in .user.ini

if (!headers_sent()) {
    // 1. Content Security Policy
    $nonce = base64_encode(random_bytes(16));
    header("Content-Security-Policy: default-src 'self'; script-src 'self' 'nonce-" . $nonce . "'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self'; object-src 'none'; base-uri 'self'; form-action 'self'; frame-ancestors 'none'");

    // 2. HSTS — HTTPS erzwingen
    header('Strict-Transport-Security: max-age=63072000; includeSubDomains; preload');

    // 3. Weitere Security Headers
    header('X-Content-Type-Options: nosniff');
    header('X-Frame-Options: DENY');
    header('Referrer-Policy: strict-origin-when-cross-origin');
    header('Permissions-Policy: camera=(), microphone=(), geolocation=()');
    header('Cross-Origin-Opener-Policy: same-origin');
    header('Cross-Origin-Resource-Policy: same-origin');

    // Nonce für Templates verfügbar machen
    define('CSP_NONCE', $nonce);
}
Warum auto_prepend_file statt include?

Mit auto_prepend_file wird die Header-Datei automatisch vor jedem PHP-Script geladen — ohne manuelles include in jeder Datei. Das verhindert vergessene Header und funktioniert auch auf Shared Hosting über die .user.ini.

2 Schritt 2 von 4

auto_prepend_file in .user.ini konfigurieren

Erstellen Sie eine .user.ini im Document Root Ihrer Anwendung. PHP liest diese Datei automatisch und führt die angegebene Datei vor jedem Script aus. Zusätzlich konfigurieren Sie hier die Session-Sicherheit.

.user.ini Produktiv
; .user.ini — im Document Root
; Wird alle 5 Minuten (user_ini.cache_ttl) neu eingelesen

auto_prepend_file = "/var/www/html/security-headers.php"

; Session-Sicherheit
session.cookie_secure = On
session.cookie_httponly = On
session.cookie_samesite = Lax
session.use_strict_mode = On
Die .user.ini wird alle 5 Minuten (Standardwert von user_ini.cache_ttl) neu eingelesen. Nach Änderungen müssen Sie diesen Zeitraum abwarten oder den PHP-FPM-Pool neustarten.
3 Schritt 3 von 4

PSR-15 Middleware (Framework-Alternative)

Für Framework-basierte Projekte (Slim, Lumen, Mezzio) implementieren Sie eine PSR-15 Middleware. Diese Variante ist typsicher, testbar und fügt sich nahtlos in die Middleware-Pipeline des Frameworks ein.

src/Middleware/SecurityHeadersMiddleware.php Produktiv
<?php
// src/Middleware/SecurityHeadersMiddleware.php
// PSR-15 Middleware für Slim, Lumen, Mezzio

namespace App\Middleware;

use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\MiddlewareInterface;
use Psr\Http\Server\RequestHandlerInterface;

class SecurityHeadersMiddleware implements MiddlewareInterface
{
    public function process(
        ServerRequestInterface $request,
        RequestHandlerInterface $handler
    ): ResponseInterface {
        $response = $handler->handle($request);

        return $response
            ->withHeader('Strict-Transport-Security', 'max-age=63072000; includeSubDomains; preload')
            ->withHeader('X-Content-Type-Options', 'nosniff')
            ->withHeader('X-Frame-Options', 'DENY')
            ->withHeader('Referrer-Policy', 'strict-origin-when-cross-origin')
            ->withHeader('Permissions-Policy', 'camera=(), microphone=(), geolocation=()');
    }
}
Verwenden Sie nicht gleichzeitig auto_prepend_file und eine Framework-Middleware für dieselben Header. Doppelte Header können zu unerwarteten Browser-Interpretationen führen — wählen Sie einen Ansatz pro Projekt.
4 Schritt 4 von 4

Verifizierung und Monitoring

Prüfen Sie die Header mit curl oder dem Wolf-Agents Web Security Check. Alle Header müssen in der Response sichtbar sein — unabhängig davon, ob Sie auto_prepend_file oder PSR-15 Middleware verwenden.

Terminal Verifizierung
# Security Headers prüfen
curl -sI https://ihre-domain.de | grep -iE "strict-transport|content-security|x-frame|x-content-type|referrer-policy|permissions-policy"

# Erwartete Ausgabe:
Strict-Transport-Security: max-age=63072000; includeSubDomains; preload
Content-Security-Policy: default-src 'self'; ...
X-Content-Type-Options: nosniff
X-Frame-Options: DENY
Referrer-Policy: strict-origin-when-cross-origin
Permissions-Policy: camera=(), microphone=(), geolocation=()
Automatisiertes Monitoring

Der Wolf-Agents Web Security Check prüft alle 166 Punkte automatisch. Mit aktivem Monitoring werden Sie bei fehlenden oder geänderten Headern sofort benachrichtigt.

Häufige Fehler bei der PHP-Header-Architektur

Headers already sent

Der häufigste PHP-Header-Fehler. Ursache: Ausgabe (echo, HTML, BOM, Leerzeichen vor <?php) vor dem header()-Aufruf. Lösung: ob_start() am Script-Anfang oder auto_prepend_file verwenden — dort wird vor jeder Ausgabe geladen.

Doppelte Header durch Include-Kette

Wenn security-headers.php sowohl per auto_prepend_file als auch per include eingebunden wird, werden Header doppelt gesetzt. Prüfen Sie mit defined('SECURITY_HEADERS_LOADED') ob die Datei bereits geladen wurde.

.user.ini wird nicht gelesen

Die .user.ini funktioniert nur mit PHP-FPM und FastCGI — nicht mit mod_php. Prüfen Sie mit phpinfo() ob user_ini.filename gesetzt ist. Auf manchen Shared-Hosting-Anbietern heißt die Datei .php.ini.

Nonce wird gecacht

Wenn ein Reverse-Proxy (Varnish, nginx) die PHP-Response cached, wird der CSP-Nonce im HTML zum statischen Wert. Browser blockieren dann alle Scripts, weil der Nonce im Header nicht mehr zum HTML passt. Lösung: Sensible Seiten vom Cache ausschließen.

Compliance-Relevanz

Eine konsolidierte Security-Header-Architektur erfüllt zentrale Anforderungen mehrerer Compliance-Frameworks. In PHP liegt die Verantwortung beim Entwickler — das Framework setzt keine Header automatisch.

OWASPASVS V14 — HTTP Security Response Headers als Pflichtanforderung
NIS2Art. 21(e) — Sicherheit bei Erwerb, Entwicklung und Wartung von Informationssystemen
BSIAPP.3.1 — Webserver-Absicherung mit Security Headern

Wie steht Ihre Domain bei Implementierungs-Architektur?

Prüfen Sie es jetzt — kostenlos, ohne Registrierung, mit 166 Prüfpunkte.