Menu
Szybki wybór
Hosting Domeny VPS SSL Kalkulator Porównania FAQ
Aktywne kody
Wszystkie kody rabatowe

WordPress REST API — zabezpieczenie i optymalizacja

Opublikowano: 9 kwietnia 2026 · Kategoria: WordPress / Bezpieczeństwo

WordPress REST API (dostępne pod /wp-json/) to potężne narzędzie dla headless WordPress, aplikacji mobilnych i integracji z zewnętrznymi serwisami. Niestety to też jeden z najpopularniejszych wektorów ataków — ujawnia listę użytkowników, umożliwia brute-force i jest używane przez boty do skanowania podatności. Oto jak go zabezpieczyć bez psucia funkcjonalności.

Czym jest WP REST API i dlaczego to attack surface?

REST API WordPress zostało wprowadzone w wersji 4.4 i jest aktywne domyślnie na każdej instalacji. Dostępne endpointy możesz sprawdzić:

# Sprawdź dostępne endpointy
curl https://twoja-domena.pl/wp-json/

# Endpointy użytkowników (potencjalnie wrażliwe)
curl https://twoja-domena.pl/wp-json/wp/v2/users

# Posty i strony publiczne
curl https://twoja-domena.pl/wp-json/wp/v2/posts
curl https://twoja-domena.pl/wp-json/wp/v2/pages

Endpoint /wp/v2/users domyślnie zwraca loginy wszystkich użytkowników z opublikowanymi postami — to gotowa lista do ataków brute-force na wp-login.php.

Blokada user enumeration przez REST API

Dodaj do functions.php aktywnego motywu (lub lepiej — do własnej wtyczki mu-plugins):

<?php
/**
 * Blokada user enumeration przez REST API i przez ?author=N
 * Dodaj do: /wp-content/mu-plugins/security-hardening.php
 */

// 1. Ukryj endpoint /wp/v2/users dla niezalogowanych
add_filter( 'rest_endpoints', function( $endpoints ) {
    if ( ! is_user_logged_in() ) {
        unset( $endpoints['/wp/v2/users'] );
        unset( $endpoints['/wp/v2/users/(?P<id>[\d]+)'] );
    }
    return $endpoints;
} );

// 2. Blokada ?author=N redirect (ujawnia login przez URL)
add_action( 'template_redirect', function() {
    if ( isset( $_GET['author'] ) && ! is_user_logged_in() ) {
        wp_die( 'Forbidden', 'Forbidden', [ 'response' => 403 ] );
    }
} );

// 3. Usuń login z REST API responses
add_filter( 'rest_prepare_user', function( $response ) {
    if ( ! is_user_logged_in() ) {
        $data = $response->get_data();
        unset( $data['slug'] );   // login ukryty w slug
        $response->set_data( $data );
    }
    return $response;
} );

Wyłączenie REST API dla niezalogowanych (selektywne)

Całkowite wyłączenie REST API może zepsuć wtyczki. Bezpieczniejsze podejście — blokada tylko wrażliwych namespace:

<?php
// Blokada dostępu do REST API dla niezalogowanych
// (zostawia publiczne endpointy dla WooCommerce, CF7 itp.)
add_filter( 'rest_authentication_errors', function( $result ) {
    if ( ! empty( $result ) ) {
        return $result;
    }
    if ( ! is_user_logged_in() ) {
        $route = $GLOBALS['wp']->query_vars['rest_route'] ?? '';
        // Blokuj TYLKO wrażliwe namespace
        $blocked = [ '/wp/v2/users', '/wp/v2/settings' ];
        foreach ( $blocked as $path ) {
            if ( str_starts_with( $route, $path ) ) {
                return new WP_Error(
                    'rest_forbidden',
                    'Dostęp zabroniony.',
                    [ 'status' => 403 ]
                );
            }
        }
    }
    return $result;
} );

Rate limiting w Nginx dla /wp-json/

Dodaj rate limiting dla endpointu REST API w konfiguracji Nginx:

# /etc/nginx/nginx.conf (w bloku http {})
limit_req_zone $binary_remote_addr zone=wp_rest:10m rate=10r/s;
limit_req_zone $binary_remote_addr zone=wp_login:10m rate=1r/s;
# /etc/nginx/sites-available/twoja-domena.conf
server {
    # ...

    # Rate limiting dla REST API (10 req/s, burst 20)
    location /wp-json/ {
        limit_req zone=wp_rest burst=20 nodelay;
        limit_req_status 429;
        try_files $uri $uri/ /index.php$is_args$args;
    }

    # Rate limiting dla wp-login.php (1 req/s, bez burst)
    location = /wp-login.php {
        limit_req zone=wp_login;
        limit_req_status 429;
        fastcgi_pass unix:/run/php/php8.2-fpm.sock;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    }
}

JWT Authentication dla REST API

JWT (JSON Web Token) umożliwia bezstanowe uwierzytelnianie dla aplikacji zewnętrznych. Zainstaluj wtyczkę JWT Auth for WP REST API:

# wp-config.php — dodaj klucz JWT
define( 'JWT_AUTH_SECRET_KEY', 'twoj-dlugi-tajny-klucz-min-32-znaki' );
define( 'JWT_AUTH_CORS_ENABLE', true );
# Krok 1: Pobierz token JWT
curl -X POST https://twoja-domena.pl/wp-json/jwt-auth/v1/token \
  -H "Content-Type: application/json" \
  -d '{"username":"admin","password":"haslo"}'

# Odpowiedź:
# { "token": "eyJ0eXAiOiJKV1QiLC...", "user_email": "...", "user_display_name": "..." }

# Krok 2: Użyj tokena do autoryzowanych zapytań
curl -X GET https://twoja-domena.pl/wp-json/wp/v2/users \
  -H "Authorization: Bearer eyJ0eXAiOiJKV1QiLC..."

Application Passwords (WordPress 5.6+)

Wbudowana alternatywa dla JWT — bez dodatkowej wtyczki. Generujesz hasło per aplikacja w profilu użytkownika (Użytkownicy → Twój profil → Hasła aplikacji):

# Użycie Application Password (Basic Auth)
# Format: "username:application_password" zakodowany w base64
curl -X GET https://twoja-domena.pl/wp-json/wp/v2/users/me \
  -H "Authorization: Basic $(echo -n 'admin:xxxx xxxx xxxx xxxx' | base64)"

# Lub wprost (mniej bezpieczne — hasło w historii bash)
curl -u "admin:xxxx xxxx xxxx xxxx" \
  https://twoja-domena.pl/wp-json/wp/v2/posts

Uwaga: Application Passwords wymagają HTTPS — WordPress automatycznie odrzuca żądania przez HTTP.

Fail2ban — blokada brute-force przez REST API

# /etc/fail2ban/filter.d/wordpress-rest.conf
[Definition]
failregex = ^<HOST> .* "POST /wp-json/jwt-auth/v1/token.*" (401|403|429)
            ^<HOST> .* "GET /wp-json/wp/v2/users.*" (403|429)
ignoreregex =
# /etc/fail2ban/jail.local
[wordpress-rest]
enabled  = true
filter   = wordpress-rest
logpath  = /var/log/nginx/access.log
maxretry = 5
findtime = 300
bantime  = 3600
# Restart i weryfikacja fail2ban
systemctl restart fail2ban
fail2ban-client status wordpress-rest

Nagłówki CORS

Jeśli REST API jest używane przez aplikację frontendową z innej domeny, skonfiguruj CORS w Nginx (zamiast polegać na domyślnych ustawieniach WordPress):

location /wp-json/ {
    # Ogranicz CORS do zaufanych domen
    add_header Access-Control-Allow-Origin "https://twoja-app.pl" always;
    add_header Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS" always;
    add_header Access-Control-Allow-Headers "Authorization, Content-Type" always;

    if ($request_method = OPTIONS) {
        return 204;
    }

    try_files $uri $uri/ /index.php$is_args$args;
}

Najczęstsze pytania

Czy wyłączenie REST API dla niezalogowanych zepsuje moją stronę? +
Zależy od wtyczek. Niektóre wtyczki (np. Contact Form 7, WooCommerce, Elementor) używają REST API nawet dla niezalogowanych użytkowników. Dlatego zamiast blokować wszystkie endpointy, zablokuj tylko wrażliwe namespace (wp/v2/users) i ogranicz dostęp przez rate limiting. Przetestuj stronę po każdej zmianie — włącz debug mode i sprawdź konsolę błędów przeglądarki.
Czym różni się JWT od Application Passwords w WordPress? +
Application Passwords (WordPress 5.6+) to wbudowana funkcja — generujesz hasło per aplikacja w profilu użytkownika. Wymaga Basic Auth (username:app_password w nagłówku). JWT Authentication to standard tokenów: klient loguje się raz i dostaje token ważny przez określony czas (np. 24h), który dołącza do każdego żądania. JWT wymaga wtyczki (np. JWT Auth for WP REST API). Application Passwords są prostsze do użycia, JWT lepszy dla mobile apps i SPAs.
Jak sprawdzić czy moja strona jest podatna na user enumeration przez REST API? +
Wejdź w przeglądarce na: twoja-domena.pl/wp-json/wp/v2/users — jeśli zwróci listę użytkowników z login, name, id to jesteś podatny. Attacker może użyć tej listy do brute-force logowania. Poprawka: add_filter("rest_endpoints") + usunięcie endpointu users lub zwracanie pustej tablicy dla niezalogowanych. Sprawdź też ?author=1 redirect który ujawnia login przez URL.
Czy rate limiting Nginx chroni przed atakami DDoS na REST API? +
Częściowo. Nginx limit_req_zone skutecznie blokuje proste brute-force i scraping (do ~1000 req/s per IP). Przy prawdziwym DDoS z tysięcy IP potrzebna jest ochrona na poziomie sieci (Cloudflare, dostawca VPS). Dobrym uzupełnieniem jest fail2ban który blokuje IP po X błędach 429/403 w logach Nginx — automatycznie dodaje regułę iptables.

Sprawdź oferty pasujące do tego scenariusza

Poniżej masz szybkie przejścia do ofert i stron z kodami rabatowymi tam, gdzie są dostępne.