Ein sechszeiliges Beispiel aus der WordPress-Dokumentation liefert zwar einen funktionierenden REST-API-Endpunkt, ist jedoch nicht für den Produktivbetrieb geeignet. Ein typisches Szenario: Ein Entwickler registriert einen Endpunkt, der auf jede Anfrage 200 KB JSON zurückgibt, ohne Authentifizierung und ohne Beschränkungen. Nach einer Woche überflutet ein Bot den Endpunkt stündlich mit mehreren Zehntausend Anfragen, die Website wird langsamer, und die Ressourcenobergrenze des Webhostings wird erreicht.
Dieser Artikel richtet sich an Entwickler: Worauf sollten Sie achten, wenn Sie einen eigenen Endpunkt erstellen, und wie sollten Sie bestehende Endpunkte überprüfen?
Die beiden Zeilen, die in den meisten Beispielen ausgelassen werden
Ein Endpunkt wird mit der Funktion register_rest_route() registriert: Namensraum, Route, HTTP-Methode, der callback, der die Antwort generiert, sowie der permission_callback.
- „
permission_callback“ legt fest, wer den Endpunkt aufrufen darf. Ist der Wert „__return_true“, ist der Endpunkt öffentlich und kann von jedem über das Internet aufgerufen werden. Seit WordPress 5.5 wird eine Warnung angezeigt, wenn dieser Wert fehlt. - „
args“ beschreibt, welche Parameter akzeptiert werden. Mithilfe von Typ (type), Pflichtangabe (required), Bereinigung (sanitize_callback) und Validierung (validate_callback) lehnt WordPress fehlerhafte Eingaben bereits ab, bevor der Code ausgeführt wird. Ohne diese Maßnahmen gelangt jedoch alles bis zurcallback-Funktion.
Überblick über die vorhandenen Endpunkte
Alle nicht standardmäßigen Endpunkte der Website sowie deren Berechtigungsprüfung werden von WP-CLI aufgelistet (über die Terminal-Oberfläche des cPanel-Hostings oder per SSH):
cd ~/public_html
wp eval 'foreach ( rest_get_server()->get_routes() as $route => $handlers ) { if ( preg_match( "#^/(wp|oembed|wp-site-health|wp-block-editor)/#", $route ) || "/" === $route ) continue; foreach ( $handlers as $h ) { $p = $h["permission_callback"] ?? null; echo $route, " [", implode( ",", array_keys( $h["methods"] ) ), "] ", is_string( $p ) ? $p : ( $p ? "closure" : "NINCS" ), "\n"; } }'
Wo „__return_true“ steht, ist der Endpunkt öffentlich. Überprüfen Sie, was zurückgegeben wird:
curl -s "https://pelda.hu/wp-json/sajat/v1/adatok" | head -c 1000
Wenn die Adressen unter /wp-json/ einen 404-Fehler zurückgeben, sind die direkten Verweise auf die einfache Form eingestellt; verwenden Sie in diesem Fall das Format https://pelda.hu/?rest_route=/sajat/v1/adatok. Wenn die Antwort E-Mail-Adressen, interne IDs oder den Inhalt von Entwürfen anzeigt, gibt der Endpunkt Daten preis und muss unverzüglich korrigiert werden. Die Grundlagen von WP-CLI werden im Artikel zur Verwendung von WP-CLI beschrieben.
Endpunkt für den Produktivbetrieb
add_action( 'rest_api_init', function () {
register_rest_route( 'sajat/v1', '/termekek/(?P<id>\d+)', array(
'methods' => WP_REST_Server::READABLE, // GET
'callback' => 'sajat_termek_lekerdezese',
'permission_callback' => 'sajat_olvashatja',
'args' => array(
'id' => array(
'required' => true,
'type' => 'integer',
'minimum' => 1,
'sanitize_callback' => 'absint',
),
),
) );
} );
function sajat_olvashatja( WP_REST_Request $request ) {
// Bejelentkezett felhasználó (süti + nonce vagy alkalmazásjelszó).
if ( current_user_can( 'read' ) ) {
return true;
}
// Szerver-szerver kapcsolat API-kulccsal.
$kulcs = $request->get_header( 'X-API-Key' );
if ( $kulcs && defined( 'SAJAT_API_KULCS' ) && hash_equals( SAJAT_API_KULCS, $kulcs ) ) {
return true;
}
return new WP_Error( 'rest_forbidden', 'Hitelesítés szükséges.', array( 'status' => 401 ) );
}
function sajat_termek_lekerdezese( WP_REST_Request $request ) {
$termek = get_post( $request['id'] );
if ( ! $termek || 'publish' !== $termek->post_status ) {
return new WP_Error( 'nincs_ilyen', 'Nincs ilyen termék.', array( 'status' => 404 ) );
}
return rest_ensure_response( array(
'id' => $termek->ID,
'cim' => get_the_title( $termek ),
) );
}
Einige Regeln hinter dem Beispiel:
- Geben Sie nur das zurück, was benötigt wird. Nicht das gesamte
WP_Post-Objekt, sondern die erforderlichen Felder und ausschließlich den veröffentlichten Inhalt. - Der API-Schlüssel sollte nicht in die Datenbank, sondern in die Datei „
wp-config.php“ (define( 'SAJAT_API_KULCS', '…' );) eingegeben werden und mit der Funktion „hash_equals()“ verglichen werden, nicht mit „==“. - Bei redaktionellen Endpunkten (beispielsweise den Daten der eigenen Blöcke des Block-Editors) sollte die Berechtigung an die entsprechende Fähigkeit gebunden sein:
current_user_can( 'edit_post', $id ), niemals__return_true. sanitize_callbackundvalidate_callback: Ersteres bereinigt die Eingabe (absint,sanitize_text_field), Letzteres lehnt sie ab, wenn sie ungültig ist. Für eine einfache Typüberprüfung reicht auch dasargs-Schema (type,minimum,enum,format) aus.
Authentifizierung
- Das eigene JavaScript der Website (angemeldeter Benutzer) authentifiziert sich mit dem Nonce „
wp_rest“: Senden Sie den Wert von „wp_create_nonce( 'wp_rest' )“ im Header „X-WP-Nonce“. - Externe Anwendungen, mobile Apps oder Anwendungen auf anderen Servern, die sich über ein App-Passwort authentifizieren: Erstellen Sie dieses in Ihrem Benutzerprofil (Benutzer › Profil, Abschnitt „App-Passwörter“) und senden Sie es mit der „Basic“-Authentifizierung. Das App-Passwort kann separat widerrufen werden und ist nicht mit dem Anmeldepasswort identisch.
Öffentliche Endpunkte: Cache und Beschränkungen
Sollte der Endpunkt absichtlich öffentlich zugänglich sein, schützen Sie ihn vor Überlastung.
Caching. WordPress speichert REST-Antworten nicht im Cache. Wenn der Inhalt nur wenige Minuten lang gültig ist, teilen Sie dies dem CDN und dem Browser mit:
$valasz = rest_ensure_response( $adatok );
$valasz->header( 'Cache-Control', 'public, max-age=300' );
return $valasz;
Das Ergebnis einer rechenintensiven Abfrage können Sie auch als temporäre Daten auf dem Server speichern (mit set_transient()), sodass häufige Anfragen nicht erneut ausgeführt werden.
Anfragebegrenzung. WordPress schränkt nicht ein, wie oft ein Endpunkt aufgerufen werden darf. Am effektivsten ist eine CDN- oder Firewall-Regel (beispielsweise die Cloudflare-Regel zur Begrenzung der Anfragen für die Route zum Endpunkt), da übermäßige Anfragen auf diese Weise gar nicht erst das Hosting erreichen. In PHP kann ein einfacher Zähler pro IP-Adresse am Anfang der Funktion „permission_callback“ eingesetzt werden:
function sajat_kereskorlat() {
$kulcs = 'kk_' . md5( $_SERVER['REMOTE_ADDR'] ?? '' );
$db = (int) get_transient( $kulcs );
if ( $db >= 60 ) {
return new WP_Error( 'rest_tul_sok_keres', 'Túl sok kérés.', array( 'status' => 429 ) );
}
set_transient( $kulcs, $db + 1, MINUTE_IN_SECONDS );
return true;
}
Pro IP-Adresse sind 60 Anfragen pro Minute zulässig. Befindet sich die Website hinter einem CDN, kann „REMOTE_ADDR“ die Adresse des CDNs sein; in diesem Fall entnehmen Sie bitte die Adresse des Besuchers aus dem vom CDN gesendeten Header (beispielsweise dem „CF-Connecting-IP“-Header von Cloudflare), jedoch nur, wenn die Anfrage tatsächlich vom CDN stammt.
Dokumentation
Die Funktion register_rest_route() akzeptiert auch einen schema-Parameter, der die Antwort im JSON-Schema beschreibt. WordPress gibt diesen bei einer OPTIONS-Anfrage an diesen Endpunkt zurück, und sowohl OpenAPI-Exporter als auch Postman können ihn verarbeiten.
Testen
curl -s -o /dev/null -w "%{http_code}\n" "https://pelda.hu/wp-json/sajat/v1/termekek/123"
curl -s -H "X-API-Key: a-sajat-kulcsa" "https://pelda.hu/wp-json/sajat/v1/termekek/123"
curl -s "https://pelda.hu/wp-json/sajat/v1/termekek/abc"
Ohne Schlüssel lautet die Antwort „401“, mit Schlüssel werden die Produktdaten angezeigt, bei ungültiger Kennung lautet die Antwort „404“ oder „400“. Testen Sie dies vor der Inbetriebnahme auf einer Staging-Kopie, und falls Sie zur Fehlersuche Protokolle benötigen, hilft Ihnen der Artikel zum WordPress-Fehlerbehebungsmodus weiter. Die allgemeinen Sicherheitseinstellungen von WordPress werden in einem separaten Artikel zusammengefasst.