REST-API von WordPress absichern: Gastzugriffe einschränken, Formulare und Editor erhalten
Die WordPress-REST-API für Gäste per Freigabeliste einschränken, ohne Block-Editor, oEmbed und Kontaktformulare zu zerstören, und externe Dienste sicher über Anwendungspasswörter anbinden. Im Labor getestet.
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

Die REST-API ist heute das Rückgrat von WordPress: Der Block-Editor, viele Formular-Plugins und externe Apps sprechen über /wp-json/ mit der Website. In der Grundeinstellung beantwortet sie auch Anfragen von Gästen, liefert öffentliche Beiträge, Seiten und eine Liste aller Routen. Schreibende Zugriffe sind ohne Anmeldung zwar gesperrt, dennoch lohnt es sich, die Angriffsfläche zu verkleinern. Diese Anleitung zeigt, was die REST-API ohne Anmeldung preisgibt, wie Sie sie mit einer Freigabeliste auf angemeldete Benutzer beschränken, ohne Formulare und Einbettungen zu zerstören, und wie externe Dienste über Anwendungspasswörter sicher zugreifen. Alle Schritte liefen im Labor mit WordPress 7.1.2 und Contact Form 7.
Voraussetzungen
- WordPress: getestet mit WordPress 7.1.2. Anwendungspasswörter gibt es seit WordPress 5.6.
- PHP: PHP 8.0 oder neuer für das Beispiel, weil es
str_starts_with()nutzt. Im Test lief PHP 8.4. - HTTPS: Anwendungspasswörter stehen nur über HTTPS zur Verfügung, außer in einer lokalen Entwicklungsumgebung. Im Test meldete
wp_is_application_passwords_available()ohne HTTPS in der Umgebung „production“false. - Zugriff: Backend mit der Rolle Administrator, Dateizugriff per SFTP oder SSH, optional WP-CLI.
- Permalinks: Die Beispiele nutzen
/wp-json/. Bei der Einstellung „Einfach“ unter Einstellungen > Permalinks lautet der Pfad/?rest_route=/. - Backup: eine aktuelle Sicherung. Eine fehlerhafte Regel kann Editor oder Formulare lahmlegen.
Schritt 1: Bestandsaufnahme der öffentlichen REST-API
Rufen Sie zuerst den Index der API ohne Anmeldung ab. Er listet alle Namensräume, also die Bereiche, die WordPress und Plugins registriert haben:
curl -s https://www.example.de/wp-json/ | python3 -c "import sys,json; j=json.load(sys.stdin); print(len(j['routes']), j['namespaces'])"
Im Test mit Contact Form 7 lautete die Ausgabe sinngemäß: 139 Routen in den Namensräumen oembed/1.0, contact-form-7/v1, wp/v2, wp-site-health/v1, wp-block-editor/v1 und wp-abilities/v1. Jede Route prüft selbst, ob der Aufrufer berechtigt ist. Ohne Anmeldung lieferte /wp/v2/posts veröffentlichte Beiträge, /wp/v2/settings antwortete mit rest_forbidden und Status 401, ein POST auf /wp/v2/posts mit rest_cannot_create. Die Grundeinstellung ist also nicht offen für Schreibzugriffe. Das Risiko liegt bei Plugins, deren Routen die Berechtigung fehlerhaft prüfen, und bei Informationen wie Benutzerlisten.
Notieren Sie, welche Namensräume Besucher ohne Anmeldung wirklich brauchen. Typisch sind oembed/1.0 für das Einbetten Ihrer Beiträge auf anderen Websites und der Namensraum des Formular-Plugins, weil viele Formulare per JavaScript an die REST-API senden.
Verifizieren: Sie haben eine Liste der Namensräume und wissen für jeden, ob Gäste ihn benötigen.
Schritt 2: Entscheiden, was eingeschränkt wird
Es gibt drei Stufen, die sich in Aufwand und Nebenwirkungen unterscheiden:
| Stufe | Wirkung | Nebenwirkung |
|---|---|---|
Einzelne Routen entfernen (rest_endpoints) | nur bestimmte Routen verschwinden, etwa Benutzer | gering, gilt aber auch für angemeldete Benutzer, wenn nicht unterschieden |
Gäste mit Freigabeliste sperren (rest_authentication_errors) | Gäste erreichen nur freigegebene Namensräume | Freigaben müssen gepflegt werden, wenn Plugins dazukommen |
| REST-API ganz abschalten | keine Antworten mehr | Block-Editor, viele Plugins und Apps funktionieren nicht mehr |
Die dritte Stufe scheidet für praktisch jede aktuelle Website aus. Für Unternehmenswebsites, die keine öffentliche API anbieten, ist die zweite Stufe ein guter Kompromiss. Die gezielte Sperre der Benutzer-Routen beschreibt die Anleitung Benutzer-Enumeration in WordPress verhindern. Diese Anleitung setzt die zweite Stufe um.
Verifizieren: Die gewählte Stufe passt zu Ihren Diensten. Wenn eine Headless-Frontend-Anwendung oder eine App öffentlich Inhalte über die REST-API lädt, gehört deren Namensraum auf die Freigabeliste.
Schritt 3: Must-Use-Plugin mit Freigabeliste anlegen
Der Filter rest_authentication_errors läuft bei jeder REST-Anfrage, bevor eine Route ausgeführt wird. Gibt er einen Fehler zurück, bricht WordPress die Anfrage ab. Legen Sie die Datei wp-content/mu-plugins/rest-schutz.php an:
<?php
/**
* Plugin Name: REST-API einschränken
*/
defined( 'ABSPATH' ) || exit;
add_filter( 'rest_authentication_errors', function ( $result ) {
// Ergebnis anderer Prüfungen nicht überschreiben.
if ( true === $result || is_wp_error( $result ) ) {
return $result;
}
if ( is_user_logged_in() ) {
return $result;
}
// Namensräume, die Gäste erreichen dürfen.
$frei = array( '/oembed/1.0', '/contact-form-7/v1' );
$route = untrailingslashit( $GLOBALS['wp']->query_vars['rest_route'] ?? '' );
foreach ( $frei as $prefix ) {
if ( str_starts_with( $route, $prefix ) ) {
return $result;
}
}
return new WP_Error( 'rest_not_logged_in', 'Anmeldung erforderlich.', array( 'status' => 401 ) );
} );
Warum so aufgebaut: Die erste Prüfung reicht Ergebnisse anderer Authentifizierungen unverändert durch, wie es die Entwicklerdokumentation für diesen Filter empfiehlt. Die Prüfung is_user_logged_in() lässt angemeldete Benutzer durch, das umfasst die Anmeldung per Cookie mit gültigem Nonce und per Anwendungspasswort. Die Route lesen Sie aus der Abfragevariable rest_route, die WordPress sowohl bei /wp-json/ als auch bei ?rest_route= setzt. Passen Sie die Liste $frei an Ihre Plugins an. Die Funktion str_starts_with() gibt es erst ab PHP 8.0.
Verifizieren: php -l wp-content/mu-plugins/rest-schutz.php meldet No syntax errors detected, und die Startseite lädt mit Status 200.
Schritt 4: Sperre und Freigaben testen
Testen Sie jetzt ohne Anmeldung, jeweils mit Ihrer Adresse:
curl -s https://www.example.de/wp-json/
curl -s https://www.example.de/wp-json/wp/v2/posts
curl -s "https://www.example.de/?rest_route=/wp/v2/users"
curl -s -o /dev/null -w "%{http_code}\n" "https://www.example.de/wp-json/oembed/1.0/embed?url=https://www.example.de/ein-beitrag/"
Im Test lieferten die ersten drei Aufrufe:
{"code":"rest_not_logged_in","message":"Anmeldung erforderlich.","data":{"status":401}}
Der oEmbed-Aufruf antwortete mit 200. Senden Sie zusätzlich ein Testformular über die Website. Im Labor nahm der Endpunkt von Contact Form 7 die Formulardaten trotz Sperre an und antwortete mit "status":"mail_failed", weil das Labor bewusst keine Mails verschickt. Entscheidend ist, dass keine 401-Antwort kam. Auf einer echten Website erscheint die Bestätigungsmeldung des Formulars.
Verifizieren: Gesperrte Routen liefern rest_not_logged_in mit Status 401, freigegebene Namensräume antworten normal, und Kontaktformulare lassen sich absenden.
Schritt 5: Editor und angemeldete Zugriffe prüfen
Öffnen Sie im Backend einen Beitrag im Block-Editor, ändern Sie etwas und speichern Sie. Der Editor sendet bei jeder Anfrage ein Nonce im Header X-WP-Nonce mit. WordPress wertet das Anmelde-Cookie in der REST-API nur zusammen mit diesem Nonce aus, als Schutz gegen Cross-Site-Request-Forgery. Im Test lieferte /wp/v2/users/me mit Cookie und Nonce Status 200. Mit Cookie, aber ohne Nonce kam dagegen der Fehlercode rest_not_logged_in mit Status 401, und zwar mit der Standardmeldung von WordPress statt der Meldung aus der eigenen Regel. Das ist gewollt und kein Fehler der Regel.
Verifizieren: Speichern im Block-Editor funktioniert, Medien lassen sich hochladen, und die Browserkonsole zeigt keine Antworten mit Status 401 von /wp-json/.
Schritt 6: Externe Dienste mit Anwendungspasswörtern anbinden
Dienste, die von außen auf die REST-API zugreifen, etwa ein Warenwirtschaftssystem oder ein Automatisierungswerkzeug, melden sich mit einem Anwendungspasswort an. Es wird pro Dienst vergeben, lässt sich einzeln widerrufen und berechtigt nicht zur Anmeldung im Backend. Legen Sie es unter Benutzer > Profil im Abschnitt „Anwendungspasswörter“ an: Tragen Sie unter „Name des neuen Anwendungspassworts“ den Dienst ein und klicken Sie auf „Anwendungspasswort hinzufügen“. Per WP-CLI geht es so:
wp user application-password create dienst-konto warenwirtschaft --porcelain
WordPress zeigt das Passwort nur einmal. Legen Sie für jeden Dienst ein eigenes Konto mit der kleinsten passenden Rolle an, nicht Ihr Administratorkonto. Der Dienst sendet Kontoname und Anwendungspasswort per HTTP Basic Auth:
curl -s -u "dienst-konto:xxxx xxxx xxxx xxxx xxxx xxxx" https://www.example.de/wp-json/wp/v2/users/me
Im Test lieferte ein gültiges Anwendungspasswort trotz Sperre Status 200, ein falsches Passwort die Antwort rest_not_logged_in. Widerrufen Sie Passwörter für Dienste, die Sie nicht mehr nutzen, im selben Abschnitt des Profils.
Jedes neue Plugin mit eigenem Namensraum ist ein Anlass, die Freigabeliste zu prüfen. Solche Kontrollen gehören zur laufenden Pflege wie Updates und Backups. Wer das nicht selbst im Kalender halten möchte, kann es abgeben: Die WordPress-Wartung von wordpressupdate.de übernimmt Updates mit Kompatibilitätsprüfung, wöchentliche Backups auf externen Speicher und die Wartung der Firewall.
Verifizieren: Der externe Dienst arbeitet mit seinem Anwendungspasswort, und wp user application-password list dienst-konto zeigt nur Passwörter, die Sie zuordnen können.
Typische Fehler
- Kontaktformular hängt oder meldet einen Fehler: Der Namensraum des Formular-Plugins fehlt in
$frei. Ermitteln Sie ihn im Browser über die Entwicklerwerkzeuge im Reiter „Netzwerk“ beim Absenden und ergänzen Sie ihn. - Abschnitt „Anwendungspasswörter“ fehlt im Profil: Die Website läuft ohne HTTPS, oder ein Plugin hat die Funktion abgeschaltet. Stellen Sie auf HTTPS um.
- Externer Dienst erhält trotz korrektem Passwort 401: Manche Server geben den Header
Authorizationnicht an PHP weiter. Die Standard-.htaccessvon WordPress enthält dafür eine Regel mitHTTP_AUTHORIZATION. Prüfen Sie, ob sie vorhanden ist undmod_rewriteläuft. /wp-json/liefert die Startseite statt JSON: Die Permalinks stehen auf „Einfach“. Nutzen Sie/?rest_route=/oder stellen Sie die Permalinks um. Im Test trat genau das vor der Umstellung auf.- Kritischer Fehler nach dem Hochladen: PHP älter als 8.0 kennt
str_starts_with()nicht. Aktualisieren Sie PHP oder ersetzen Sie die Prüfung durch0 === strpos( $route, $prefix ).
Häufige Fragen
Reicht es nicht, die REST-API mit einem Plugin abzuschalten?
Eine vollständige Abschaltung legt den Block-Editor lahm, weil er selbst über die REST-API arbeitet. Brauchbare Plugins müssen deshalb ebenfalls Ausnahmen für angemeldete Benutzer machen. Eine eigene Regel mit wenigen Zeilen ist nachvollziehbar, und Sie wissen genau, welche Namensräume offen sind.
Ist die Sperre für Suchmaschinen ein Problem?
Nein. Suchmaschinen lesen die HTML-Seiten und die Sitemap, nicht die REST-API. Der Link-Header mit der API-Adresse bleibt bestehen, führt Gäste aber nur zur Fehlermeldung.
Schützt das vor Lücken in Plugins?
Teilweise. Lücken in REST-Routen eines Plugins sind für Gäste nicht mehr erreichbar, solange der Namensraum nicht freigegeben ist. Lücken im freigegebenen Formular-Plugin oder außerhalb der REST-API bleiben bestehen. Updates sind weiterhin der wichtigste Schutz.
Testumfang
Auf einer Testinstanz mit WordPress 7.1.2 haben wir geprüft, ob die Gastsperre der REST-API über /wp-json/ und über den Umweg per Parameter greift. Dabei haben wir besonders darauf geachtet, dass oEmbed und Contact Form 7 trotz Sperre freigegeben bleiben.
Andere Formular-Plugins und Seiten hinter Proxy oder CDN haben wir nicht getestet. Wenn Sie so etwas nutzen, probieren Sie die Sperre bitte zuerst auf einer Kopie Ihrer Seite aus.
Fazit
Eine Freigabeliste im Filter rest_authentication_errors verkleinert die öffentliche REST-API auf das, was Besucher brauchen, während Editor und angemeldete Dienste normal weiterarbeiten. Die Pflege der Liste gehört zu jedem neuen Plugin dazu. Wer diese Pflege zusammen mit Updates und Backups abgeben möchte, findet das bei der WordPress-Wartung von Marcel Schönfelder.
Weiterführende Anleitungen und Quellen
- Benutzer-Enumeration in WordPress verhindern
- XML-RPC in WordPress deaktivieren oder einschränken
- WordPress-Sicherheitsheader setzen
- REST-API-Handbuch: Häufige Fragen (Zugriff einschränken)
- REST-API-Handbuch: Authentifizierung
- Code-Referenz: rest_authentication_errors
- WP-CLI-Handbuch: wp user application-password


