Hardening WordPressa — jak ustawić instalację, żeby włamanie było trudniejsze i mniej bolało.
Hardening to ustawienia, nie kod: kto może zapisywać pliki, jakie uprawnienia ma użytkownik bazy, kto w WordPressie może co zrobić, czego nie wystawiać do sieci i jak się przygotować na dzień, w którym i tak ktoś wejdzie. WordPress opisuje to w rozdziale Hardening WordPress podręcznika administracji; role i uprawnienia — w osobnym artykule. Nie ma tam „linii bazowej schematu bazy”: o bazie jest tylko tyle, że jej użytkownik potrzebuje czterech uprawnień, a cała macierz ról leży w jednej opcji. Poniżej całość i to, co z niej widzimy na stronach klientów — z zewnątrz skanerem i od środka wtyczką.
Źródło: Hardening WordPress (akt. 07.01.2026), Roles and Capabilities (akt. 02.09.2026), uprawnienia ról z kodu rdzenia; odczyt 26.09.2026. Opisy są naszym opracowaniem. Dane: sonda exposure skanera LAB247, 20–26.09.2026. Pozostałe standardy serii: WP Secure Coding (kod), Bazy podatności (aktualizacje), OWASP Top 10 (A02 Security Misconfiguration).
- Role domyślne
- 5od 1 do 50 uprawnień
- Uprawnienia bazy do pracy
- 4SELECT · INSERT · UPDATE · DELETE
- Strony z odchyleniem
- 127 / 20661,7 % · z zewnątrz
- debug.log publiczny
- 19stron · waga pilna
Skala = wszystkie 206 stron. 127 ma co najmniej jedno odchylenie, 113 coś poważniejszego niż publiczny wp-cron albo readme. Najczęstsze wysokie to zdradzanie loginów (REST, ?author) i otwarte XML-RPC — razem dają atakującemu login i szybki kanał do zgadywania hasła.
| Zmniejszanie ryzyka | „Bezpieczeństwo to zmniejszanie ryzyka, nie jego eliminacja” — dobór zabezpieczeń do tego, co chronisz. |
|---|---|
| Ograniczanie dostępu | Mniej punktów wejścia: panel, XML-RPC, rejestracja, edytor plików, zbędne wtyczki. |
| Izolacja | Włamanie w jedno miejsce nie ma otwierać reszty: osobna baza i użytkownik bazy na stronę, zapis tylko tam, gdzie konieczny. |
| Przygotowanie | Kopie i plan odtworzenia, zanim coś się stanie — wykrycie włamania bywa spóźnione o tygodnie. |
| Zaufane źródła | Wtyczki i motywy tylko z wordpress.org albo od znanych firm; kod z nieznanych źródeł to najprostsza droga do infekcji. |
| Podział odpowiedzialności | Hosting odpowiada za serwer i sieć, właściciel strony za aplikację: WordPress, wtyczki, konta, hasła. |
| Miejsce | Zapis | Uwaga |
|---|---|---|
| / (katalog główny) | zapis tylko właściciel konta | .htaccess — wyjątek, gdy WordPress sam pisze reguły przepisywania |
| /wp-admin/, /wp-includes/ | zapis tylko właściciel konta | rdzeń; zmiana pliku tu = sygnał włamania |
| /wp-content/ | zapis właściciel + proces serwera | tu trafiają przesłane pliki i kopie |
| /wp-content/themes/ | zapis właściciel (+ serwer tylko dla edytora motywów) | lepiej wyłączyć edytor: DISALLOW_FILE_EDIT |
| /wp-content/plugins/ | zapis tylko właściciel konta | |
| Katalogi / pliki | 755 / 644 | tak ustawia je sama aktualizacja automatyczna |
| wp-config.php | 400 albo 440 | czyta tylko właściciel i serwer; można przenieść poziom wyżej, poza katalog publiczny (podręcznik: sporne) |
| Codzienna praca | Użytkownik bazy potrzebuje tylko SELECT, INSERT, UPDATE, DELETE. |
|---|---|
| DROP, ALTER, GRANT | Teoretycznie do odebrania — ale podręcznik NIE zaleca: duże aktualizacje (3.7 → 3.8) zmieniają schemat i bez tych uprawnień się sypią. Małe (3.8 → 3.8.1) zwykle nie. |
| Jedna strona, jedna baza | Osobna baza i osobny użytkownik dla każdej strony — włamanie w jedną nie czyta drugiej. |
| Serwer MySQL | Wyłączyć, czego nie używasz — np. zdalne połączenia TCP. |
| Prefiks tabel | Domyślne wp_ zakłada wiele gotowych ataków SQL injection; zmiana zatrzymuje część z nich. Podręcznik zalicza to do zaciemniania, nie do obrony głównej. |
| Role w bazie | Cała macierz ról i uprawnień leży w jednej opcji {prefiks}user_roles w tabeli opcji. Kto może pisać do opcji, może dać subskrybentowi uprawnienia administratora. |
| Rola | Uprawnień | Dochodzi względem roli niżej |
|---|---|---|
| Subscriber | 1 | read |
| Contributor | 3 | edit_posts, delete_posts |
| Author | 7 | publish_posts, upload_files, edit/delete_published_posts |
| Editor | 26 | cudze i prywatne wpisy i strony, strony, kategorie, moderacja, unfiltered_html |
| Administrator | 50 | wtyczki, motywy, użytkownicy, ustawienia (manage_options), edycja plików, import/eksport, aktualizacje |
| Uprawnienie | Dlaczego „niebezpieczne” u niewłaściwej roli |
|---|---|
| unfiltered_html | Wstawianie dowolnego HTML i JavaScriptu — domyślnie Editor i Administrator. U niższej roli = stored XSS z definicji. |
| upload_files | Wgrywanie plików — od Author. Z luką w filtrze typów = wgranie PHP. |
| edit_users · promote_users · create_users | Tworzenie kont i nadawanie ról — kto ma, ten sam się awansuje. |
| manage_options | Wszystkie ustawienia, w tym default_role i users_can_register. |
| install_plugins · edit_plugins · edit_themes · edit_files | Wykonanie dowolnego kodu na serwerze. DISALLOW_FILE_EDIT odbiera trzy ostatnie wszystkim. |
| default_role + users_can_register | Otwarta rejestracja z rolą domyślną „administrator” = każdy zakłada konto administratora. Klasyczny skutek luki w update_option. |
„Naruszenie” w sensie dokumentu źródłowego = rola z uprawnieniem spoza swojego domyślnego zestawu. Wzorzec jest w tabeli wyżej; sieć (Super Admin) i uprawnienia dodawane przez wtyczki (np. sklepu) to osobne zestawy.
| Aktualizacje | Tylko z wordpress.org; automatyczne od 3.7. Po wydaniu łatki „informacja potrzebna do ataku jest prawie na pewno publiczna”. |
|---|---|
| Hasła | Z generatora, nie z nazwy firmy ani słownika; logowanie dwuetapowe jako dodatkowa warstwa. |
| Transfer plików | SFTP zamiast FTP — hasło i pliki szyfrowane w drodze. |
| wp-admin | Druga warstwa hasła po stronie serwera (uwaga: może zepsuć admin-ajax.php) i HTTPS dla całego panelu. |
| wp-includes | Reguły .htaccess blokujące bezpośrednie wywołanie plików tylko do dołączania (poza blokiem # BEGIN WordPress). |
| wp-config.php | Uprawnienia 400/440, <Files "wp-config.php"> Require all denied, ewentualnie poziom wyżej. |
| DISALLOW_FILE_EDIT | define( 'DISALLOW_FILE_EDIT', true ); — znika edytor motywów i wtyczek. Nie zatrzyma wgrania pliku, ale utnie część ataków. |
| Konto „admin” | Nie używać loginów admin/webmaster; istniejące przemianować. |
| Wtyczki | Aktualne, zbędne usunięte; ostrożnie z wtyczkami z prawem zapisu i takimi, które wykonują dowolny kod PHP. |
| Kopie | Regularnie baza i pliki; szyfrowane, z niezależnym skrótem, na nośniku tylko do odczytu. Przykład z podręcznika: włamanie 1 maja wykryte 12 maja — potrzebna kopia sprzed 1 maja. |
|---|---|
| Logi | Do analizy po fakcie i wykrywania XSS, RFI/LFI, przechodzenia katalogów, zgadywania haseł. Log serwera ma IP i czas, ale nie login. |
| Zmiany plików | Pilnować zmienionych i nowych plików, z alarmem i możliwością cofnięcia; monitor uruchomiony jako root, wyciszony na czas aktualizacji, najlepiej tylko pliki wykonywalne (.php). |
| Z zewnątrz | Niezależny monitor strony z sieci — wykrywa podmianę treści i wstrzyknięty malware, gdy strona sama tego nie zgłosi. |
| Zalecenie | Kto | Jak |
|---|---|---|
| Aktualny rdzeń, wtyczki, motywy | oba | Skaner: wersje z zewnątrz → luki (Bazy podatności). Wtyczka: pełna lista wtyczek z wersjami w komunikacie dobowym. |
| Konta administratorów | wtyczka | Nowy administrator, odebrana rola, zmiana e-maila lub hasła, logowanie z nowego adresu, sesja bez logowania — zdarzenia krytyczne od razu. |
| Zmiany plików | wtyczka | wp-config.php (także poziom wyżej), .htaccess, pliki .php w katalogu głównym (do 200), mu-plugins (do 50) — porównanie skrótów co godzinę. |
| Ograniczenie punktów wejścia | skaner | XML-RPC, lista kont przez REST, login przez ?author, otwarta rejestracja — sonda exposure (RYS. 1). |
| Pliki, których nie powinno być w sieci | skaner | debug.log, kopie wp-config, .env, .git, zrzuty bazy, archiwa, phpinfo, adminer — 25 ścieżek. |
| Monitor z zewnątrz | skaner | Dostępność, treść, infekcja, Safe Browsing, DNS, SSL — co 15 min do kilku godzin zależnie od kohorty. |
| Uprawnienia ról (macierz) | nikt | Wtyczka pilnuje roli administratora (do 0.12 wysyłała też listę administratorów z 2FA, sesjami i hasłami aplikacji). Czy subskrybent nie dostał unfiltered_html albo manage_options — nie sprawdzała żadna wersja. |
| default_role, DISALLOW_FILE_EDIT, WP_DEBUG | wtyczka | Wtyczka do 0.12 (dziś 4 z 5 stron) wysyła w migawce blok `posture`: 11 flag — disallow_file_edit/mods, disable_wp_cron, wp_debug (+display, +log), users_can_register, default_role, auto_update_core, automatic_updater_disabled, force_ssl_admin. Prefiksu tabel nie. Wersja 0.13 migawkę wycina (TAB. 9). |
| Uprawnienia plików i bazy | nikt | Chmod, użytkownik MySQL, osobne bazy — sprawa hostingu; widać je dopiero przy dostępie SSH (Agenci AI w trybie ssh). |
| Kopie | nikt | Nie wiemy, czy klient ma kopię i czy da się ją odtworzyć. |
| Odchylenie | Stron | Udział | W rozdziale | Dlaczego ważne |
|---|---|---|---|---|
| wp-cron.php publiczny exposure_wpcron | 118 | 57,3 % | nie | Zadania uruchamiane z każdego wejścia — cron systemowy zamiast wywołań z sieci. (niska) |
| readme.html exposure_readme | 117 | 56,8 % | nie | Ujawnia, że to WordPress (i bywa, że wersję) — zaciemnianie, pomocnicze. (niska) |
| lista kont przez REST exposure_users_enum | 92 | 44,7 % | nie | /wp/v2/users oddaje loginy — połowa pary do zgadywania haseł. (wysoka) |
| login przez ?author=1 exposure_author_enum | 82 | 39,8 % | tak | Przekierowanie zdradza login administratora; podręcznik: nie „admin”, konto przemianować. (wysoka) |
| XML-RPC odpowiada exposure_xmlrpc | 79 | 38,3 % | nie | system.multicall = setki prób hasła w jednym żądaniu; zasada ograniczania punktów wejścia. (wysoka) |
| debug.log publiczny exposure_debug_log | 19 | 9,2 % | nie | Dziennik błędów PHP z wp-content — ścieżki, zapytania, czasem dane. Logować poza katalog publiczny. (pilna) |
| listing katalogu uploads exposure_directory_listing | 4 | 1,9 % | nie | Serwer pokazuje spis plików — wyłączyć indeksowanie katalogów. (normalna) |
| composer.json / package.json exposure_dev_manifest | 2 | 1 % | nie | Lista zależności i wersji — nie wdrażać plików deweloperskich. (niska) |
| otwarta rejestracja open_registration | 1 | 0,5 % | nie | Każdy może założyć konto z rolą domyślną — groźne, gdy rola domyślna jest za wysoka. (normalna) |
68 stron bez żadnego znaleziska, 11 z wynikiem niemiarodajnym (serwer odpowiada 200 na każdą ścieżkę). Na żadnej stronie w ostatnim odczycie nie było: .env, .git/HEAD, wp-config.php.bak / ~, phpinfo.php, adminer.php, backup.zip / .sql, .htaccess.bak, .DS_Store.
| Co | Stan | Jak |
|---|---|---|
| Sonda exposure | działa | 25 ścieżek z zabezpieczeniem przed fałszywym 200 (losowa ścieżka-kanarek). Wynik exposure_* idzie do Wskaźnika; debug.log i kopie konfiguracji z dowodem tylko jako skrót, bez treści. |
| Administratorzy i pliki krytyczne | działa | Wtyczka Creato Ping: zdarzenia kont administratorów i zmiany plików krytycznych — krytyczne od razu, rutyna raz na dobę. |
| Sonda exposure bez własnego rytmu | dług | Dispatcher nie zleca jej osobno — wchodzi tylko w paczce security_pelny (karta sondy, 22.09). Rytm zależy od paczki, nie od potrzeby. |
| Linia bazowa od środka po 0.13 | dług | Migawka 0.5–0.12 niosła posture (11 flag) i users (administratorzy, 2FA, rejestracja, rola domyślna); findingi agent_posture_* liczą się tylko do statystyk. 0.13 („szczupła wtyczka”, decyzja 26.09, alfa na 1 stronie) wycina migawkę w całości — po wdrożeniu na flotę tych flag nie będzie. Do decyzji: czy kilka wraca do komunikatu dobowego. Macierzy ról (TAB. 4) nie porównywała żadna wersja — to byłoby „wykrywanie naruszeń” z dokumentu źródłowego. |
| Uprawnienia plików i bazy | nie robimy | Wymaga dostępu do serwera klienta. Agenci AI w trybie ssh mogliby to odczytać, ale nie mają takiego zadania. |
| Brak odpowiedzi to nie zabezpieczenie | 403 z WAF-u dla skanera wygląda jak „nie wystawione”, choć może być zablokowane tylko dla nas. |
| Zaciemnianie to nie obrona | Prefiks tabel, ukryty readme, przemianowany admin — podręcznik sam nazywa to pomocniczym. Nie zastąpią aktualizacji i haseł. |
| Nie wszystko jest w podręczniku | Z dziewięciu rodzajów odchyleń rozdział Hardening wprost dotyczy jednego (login administratora). Resztę sprawdzamy z praktyki; oznaczone w TAB. 8. |
| Hardening ≠ bezpieczny kod | Dobrze ustawiona instalacja z dziurawą wtyczką dalej jest podatna — to osobne standardy serii (WP Secure Coding, Bazy podatności). |
| Hosting poza zasięgiem | Uprawnienia plików, użytkownik MySQL, PHP i serwer WWW ustawia hosting klienta. My możemy je zmierzyć, nie wymusić. |
- Nazwa
- „WordPress Database Schema Hardening Baseline” nie istnieje jako dokument. Podręcznik, na który wskazuje, to „Hardening WordPress” (Advanced Administration) — o bazie mówi tylko uprawnienia użytkownika MySQL i prefiks; RBAC to osobny artykuł o rolach.
- Role
- Liczba uprawnień ról z kodu rdzenia (schema.php, funkcje populate_roles_160…300, trunk 26.09.2026), bez przestarzałych level_0…level_10 i bez uprawnień meta. Po instalacji wtyczki mogą je zmieniać.
- Skaner
- Ostatni odczyt sondy exposure każdej z 206 stron, 20–26.09.2026, z bazy skanera tylko do odczytu. „Z odchyleniem” = co najmniej jedno znalezisko poza exposure_scan_unreliable.
- Wagi
- Waga znaleziska (niska / normalna / wysoka / pilna) z polityki skanera, nie z podręcznika — podręcznik wag nie nadaje.