Geschützte Downloads in WordPress: Dateien nur für angemeldete Benutzer bereitstellen
Warum Dateien aus der Mediathek trotz Passwortseite öffentlich sind und wie Sie vertrauliche Downloads in einem gesperrten Ordner ablegen, per Must-Use-Plugin nur an angemeldete Benutzer ausliefern und den Schutz mit curl prüfen.
Mit KI erstellt – redaktionelle Prüfung ausstehend
WerbelinksMit * markierte Links sind Werbelinks: Bei einem Kauf erhalten wir eine Provision, der Preis bleibt gleich. Mehr dazu

Preislisten für Händler, Schulungsunterlagen für Kunden oder Formulare für Mitarbeiter: Viele Firmenwebsites sollen Dateien nur für einen bestimmten Kreis bereitstellen. Der naheliegende Weg ist eine passwortgeschützte Seite, auf der ein Link zur Datei steht. Das schützt aber nur die Seite, nicht die Datei. Wer die Adresse der PDF kennt oder sie weitergibt, lädt sie ohne jedes Passwort herunter. Diese Anleitung zeigt, warum das so ist, wie Sie Dateien in einem gesperrten Ordner ablegen und nur an angemeldete Benutzer ausliefern und wann ein Download-Plugin die bessere Wahl ist.
Voraussetzungen
- WordPress: eine aktuelle Installation, getestet mit WordPress 7.1.2 auf Apache 2.4. Die WordPress-Versionsschnittstelle empfiehlt mindestens PHP 7.4.
- Rolle: ein Administrator-Konto im Backend.
- Zugriff: SFTP oder SSH, um einen Ordner und eine PHP-Datei anzulegen. Mit reinem Backend-Zugang bleibt nur der Weg über ein Plugin aus Schritt 5.
- Webserver: Apache mit erlaubten
.htaccess-Dateien oder nginx mit Zugriff auf die Server-Konfiguration. - Benutzerkonten: für jeden Empfänger ein WordPress-Konto, zum Beispiel mit der Rolle Abonnent. Wie Sie Rollen sauber vergeben, zeigt Benutzerrollen und Rechte in WordPress.
- Backup: ein aktuelles Backup von Dateien und Datenbank, bevor Sie ein Must-Use-Plugin anlegen.
Schritt 1: Ist-Zustand prüfen
WordPress speichert jede hochgeladene Datei unter wp-content/uploads/JAHR/MONAT/. Der Webserver liefert diese Dateien direkt aus, ohne dass WordPress beteiligt ist. Deshalb kann WordPress beim Abruf weder ein Passwort noch eine Anmeldung prüfen.
Im Test haben wir eine PDF in die Mediathek geladen und auf einer Seite mit Passwortschutz verlinkt. Die Seite selbst zeigte wie erwartet nur das Passwortformular. Die Datei war dagegen ohne Anmeldung abrufbar:
curl -s -o /dev/null -w "%{http_code} %{content_type}\n" \
https://www.ihre-domain.de/wp-content/uploads/2026/09/preisliste.pdf
200 application/pdf
Auch die Anhangseite der Datei hilft nicht weiter. Seit WordPress 6.4 sind Anhangseiten bei neuen Installationen abgeschaltet, im Test stand die Option wp_attachment_pages_enabled auf 0, und der Aufruf von ?attachment_id=5 leitete per 301 direkt auf die Datei weiter. Suchen Sie in Ihrer Mediathek nach Dateien, die nicht öffentlich sein sollen, und notieren Sie deren Adressen.
Verifizieren: Sie haben eine Liste der vertraulichen Dateien, und der curl-Aufruf zeigt Ihnen für jede, ob sie heute öffentlich erreichbar ist.
Schritt 2: Geschützten Ordner anlegen
Vertrauliche Dateien gehören nicht in die Mediathek, sondern in einen eigenen Ordner, den der Webserver nicht ausliefert. Legen Sie ihn per SSH oder SFTP an und sperren Sie ihn:
cd /var/www/html/wp-content/uploads
mkdir geschuetzt
printf 'Require all denied\n' > geschuetzt/.htaccess
sudo chown -R www-data:www-data geschuetzt
Require all denied ist die Schreibweise von Apache 2.4 aus dem Modul mod_authz_core. Die ältere Form Deny from all funktionierte im Test ebenfalls, weil das Kompatibilitätsmodul mod_access_compat geladen war. Verlassen Sie sich darauf nicht, bei manchen Hostern fehlt das Modul. Der Benutzer www-data steht für den Webserver unter Debian und Ubuntu, bei Ihrem Hoster kann er anders heißen.
Laden Sie die vertraulichen Dateien per SFTP in diesen Ordner. Löschen Sie die bisherigen Kopien aus der Mediathek, sonst bleiben sie unter der alten Adresse öffentlich.
Läuft Ihre Website auf nginx, liest der Server keine .htaccess. Dann gehört eine Sperre in den Server-Block, und zwar vor die Regeln für PHP-Dateien:
location ^~ /wp-content/uploads/geschuetzt/ {
deny all;
}
Der Schalter ^~ sorgt dafür, dass nginx für diesen Pfad keine weiteren Regex-Locations prüft. Diese nginx-Regel haben wir im Rahmen dieser Anleitung nicht getestet. Wie Sie nginx-Sperren prüfen, beschreibt WordPress auf nginx härten.
Verifizieren: Der direkte Aufruf einer Datei im Ordner liefert 403. Im Test sah das so aus, und ohne die .htaccess kam dieselbe Datei mit 200 zurück:
/wp-content/uploads/geschuetzt/preisliste-2026.pdf 403
Schritt 3: Auslieferung per Must-Use-Plugin
Jetzt braucht es einen Weg, auf dem berechtigte Benutzer die Dateien trotzdem bekommen. Das übernimmt PHP: WordPress prüft die Anmeldung, liest die Datei vom Server und schickt sie an den Browser. Ein Must-Use-Plugin eignet sich dafür, weil WordPress es automatisch lädt und es sich im Backend nicht versehentlich deaktivieren lässt. Legen Sie die Datei wp-content/mu-plugins/interne-downloads.php an, den Ordner mu-plugins gegebenenfalls ebenfalls:
<?php
/*
* Plugin Name: Geschützte Downloads
* Description: Liefert Dateien aus wp-content/uploads/geschuetzt nur an angemeldete Benutzer aus.
*/
add_action( 'init', function () {
if ( ! isset( $_GET['download'] ) ) {
return;
}
if ( ! is_user_logged_in() ) {
auth_redirect();
}
if ( ! current_user_can( 'read' ) ) {
wp_die( 'Kein Zugriff.', '', array( 'response' => 403 ) );
}
$name = sanitize_file_name( wp_basename( wp_unslash( $_GET['download'] ) ) );
$dir = wp_upload_dir()['basedir'] . '/geschuetzt/';
$file = $dir . $name;
$type = wp_check_filetype( $name );
if ( '' === $name || ! is_file( $file ) || ! $type['type'] ) {
wp_die( 'Datei nicht gefunden.', '', array( 'response' => 404 ) );
}
nocache_headers();
header( 'Content-Type: ' . $type['type'] );
header( 'Content-Disposition: attachment; filename="' . $name . '"' );
header( 'Content-Length: ' . filesize( $file ) );
header( 'X-Content-Type-Options: nosniff' );
readfile( $file );
exit;
} );
Die wichtigsten Stellen im Einzelnen:
auth_redirect()leitet nicht angemeldete Besucher zur Anmeldung um und bringt sie danach zur gewünschten Datei zurück.current_user_can( 'read' )erlaubt jede angemeldete Rolle ab Abonnent. Wollen Sie den Kreis enger fassen, prüfen Sie eine eigene Berechtigung oder eine bestimmte Rolle.wp_basename()undsanitize_file_name()entfernen Pfadangaben wie../. Ohne diese Zeile könnte ein angemeldeter Benutzer versuchen, andere Dateien des Servers abzurufen, etwa diewp-config.php.wp_check_filetype()liefert nur für Dateitypen einen Wert, die WordPress kennt und erlaubt. Eine PHP-Datei im Ordner wird dadurch nicht ausgeliefert.nocache_headers()verhindert, dass ein Browser oder Proxy die Datei zwischenspeichert und später an jemand anderen ausliefert.
Verifizieren: Rufen Sie https://www.ihre-domain.de/?download=preisliste-2026.pdf in einem privaten Browserfenster auf. Sie landen auf der Anmeldeseite, nach der Anmeldung startet der Download.
Schritt 4: Schutz gezielt testen
Ein Downloadschutz ist nur so gut wie sein Test. Prüfen Sie jede Richtung einmal bewusst, auch die, die scheitern soll. Ohne Anmeldung genügt curl:
curl -s -o /dev/null -w "%{http_code}\n" https://www.ihre-domain.de/wp-content/uploads/geschuetzt/preisliste-2026.pdf
curl -s -o /dev/null -w "%{http_code} %{redirect_url}\n" "https://www.ihre-domain.de/?download=preisliste-2026.pdf"
Im Test lieferte der erste Aufruf 403 und der zweite eine Weiterleitung 302 auf wp-login.php mit der Zieladresse im Parameter redirect_to. Danach haben wir uns mit einem Testkonto der Rolle Abonnent angemeldet. Die Datei kam mit Status 200 und diesen Kopfzeilen:
HTTP/1.1 200 OK
Cache-Control: no-cache, must-revalidate, max-age=0, no-store, private
Content-Disposition: attachment; filename="preisliste-2026.pdf"
X-Content-Type-Options: nosniff
Content-Type: application/pdf
Anschließend haben wir versucht, mit demselben Konto ?download=../../../wp-config.php, eine PHP-Datei im Ordner und eine nicht vorhandene Datei abzurufen. Alle drei Versuche endeten mit 404, ohne Inhalt preiszugeben.
Verifizieren: Direktaufruf 403, Skript ohne Anmeldung 302 auf die Anmeldeseite, Skript mit Anmeldung 200, Pfadangaben und PHP-Dateien 404.
Schritt 5: Download-Links einbinden und pflegen
Verlinken Sie die Dateien auf einer Seite, die nur angemeldete Benutzer sehen, zum Beispiel einem internen Bereich. Der Link lautet immer /?download=DATEINAME. Die Seite selbst kann öffentlich sein, denn die Prüfung passiert beim Abruf der Datei. Allerdings verraten öffentliche Links die Dateinamen, und Namen wie „preisliste-haendler-2026.pdf“ sagen schon etwas über den Inhalt.
Ab einer gewissen Menge wird die Handarbeit mühsam. Das Plugin Download Monitor, laut Plugin-Verzeichnis auf über 80.000 Websites aktiv, verwaltet Dateien mit Versionen, Zählern und Download-Buttons. Zugriffsbeschränkungen wie Formular-Sperren bietet es teils als kostenpflichtige Erweiterung. Prüfen Sie vor der Wahl, ob der Schutz im Plugin tatsächlich den Direktabruf der Datei sperrt, und testen Sie das mit denselben curl-Aufrufen wie in Schritt 4.
Auch der geschützte Ordner will gepflegt sein. Alte Preislisten sollten verschwinden, Konten ausgeschiedener Partner gelöscht und die Sperre nach jedem Serverumzug erneut getestet werden. Wer Updates, Backups und Server-Schutz nicht selbst im Blick behalten möchte, kann diese Aufgaben abgeben: Die WordPress-Wartung von wordpressupdate.de spielt Updates von WordPress, Plugins und Themes nach einer Kompatibilitätsprüfung ein, legt wöchentlich ein Backup auf externem Speicher ab und richtet die Firewall ein und pflegt sie. Konten beim Mitarbeiterwechsel anzupassen, beschreibt WordPress-Benutzer beim Mitarbeiterwechsel anpassen.
Verifizieren: Die Download-Links auf der internen Seite funktionieren für ein Testkonto, und im Mediathek-Ordner liegen keine Kopien der vertraulichen Dateien mehr.
Typische Fehler
Datei weiterhin öffentlich trotz Passwortseite
Der Passwortschutz von WordPress gilt nur für den Seiteninhalt. Die verlinkte Datei aus der Mediathek lieferte im Test ohne Anmeldung 200. Verschieben Sie solche Dateien in den gesperrten Ordner.
Sperre greift nicht
Liefert der Direktaufruf weiter 200, wertet der Server die .htaccess nicht aus. Das passiert bei nginx immer und bei Apache, wenn AllowOverride für das Verzeichnis ausgeschaltet ist. Setzen Sie die Sperre dann in der Server-Konfiguration oder fragen Sie Ihren Hoster.
Download bricht ab oder Datei ist beschädigt
Gibt ein anderes Plugin vor dem Download bereits Text oder Leerzeilen aus, landet dieser am Anfang der Datei. Prüfen Sie das Must-Use-Plugin auf Leerzeichen vor <?php und testen Sie mit deaktivierten Plugins. Sehr große Dateien können außerdem an Zeitlimits von PHP scheitern.
Datei nicht gefunden trotz richtigem Namen
sanitize_file_name() ersetzt Leerzeichen und Sonderzeichen. Benennen Sie Dateien vor dem Hochladen mit Kleinbuchstaben, Ziffern und Bindestrichen, dann stimmen Link und Dateiname überein.
Häufige Fragen
Reicht ein schwer zu erratender Dateiname?
Nein. Ein zufälliger Name erschwert das Raten, schützt aber nicht vor Weitergabe, Browserverlauf oder Einträgen in Suchmaschinen. Für vertrauliche Unterlagen brauchen Sie eine echte Zugriffsprüfung.
Kann ich einzelne Dateien nur für bestimmte Kunden freigeben?
Ja, mit einer feineren Prüfung im Plugin, etwa über eine eigene Rolle oder Berechtigung. Bei vielen unterschiedlichen Freigaben ist ein Download-Plugin mit Rechteverwaltung meist übersichtlicher.
Sind die Dateien im Backup enthalten?
Der Ordner liegt unter wp-content/uploads und landet damit in den meisten Datei-Backups. Prüfen Sie, dass Ihr Backup-Speicher genauso vertraulich behandelt wird wie die Dateien selbst.
Testumfang
Wir haben alles auf einer Testinstallation mit WordPress 7.1.2 unter Apache durchgespielt, und Sperre sowie Umleitung zur Anmeldung funktionierten wie beschrieben. Auffällig war, dass die Datei ohne die .htaccess sofort wieder öffentlich erreichbar war.
Die nginx-Regel und Caching-Plugins haben wir nicht geprüft. Testen Sie solche Kombinationen deshalb mit den Befehlen aus Schritt 4, bevor Sie echte Unterlagen hochladen.
Fazit
Eine passwortgeschützte Seite schützt keine Dateien. Erst ein gesperrter Ordner und eine Auslieferung, die Anmeldung und Berechtigung prüft, halten vertrauliche Unterlagen wirklich im geschlossenen Kreis, und vier curl-Aufrufe zeigen jederzeit, ob das noch stimmt. Wenn Sie Updates und Backups dieser Website dauerhaft abgeben möchten, übernimmt das die WordPress-Wartung von Marcel Schönfelder.
Weiterführende Anleitungen und Quellen
- Benutzerrollen und Rechte in WordPress sauber vergeben
- WordPress auf nginx härten: sensible Dateien gezielt sperren
- WordPress-Benutzer beim Mitarbeiterwechsel anpassen
- Code Reference: auth_redirect()
- Code Reference: nocache_headers()
- WordPress Advanced Administration: Must Use Plugins
- Make WordPress Core: Changes to attachment pages
- Apache-Dokumentation: mod_authz_core (Require)
- Download Monitor im Plugin-Verzeichnis


