Przejdź do treści
Serwer i .htaccess

Reguły bezpieczeństwa .htaccess w WordPress, które naprawdę pomagają

Większość tego, co sprzedaje się jako zabezpieczanie WordPressa przez .htaccess, to wypełniacz. Reguły, które faktycznie zmieniają powierzchnię ataku, są krótkie — oto które są które

Opublikowano

Większość tego, co sprzedaje się jako „bezpieczeństwo .htaccess w WordPress”, to wypełniacz. Reguły, które faktycznie zmieniają powierzchnię ataku, są krótkie: zablokuj wykonywanie PHP wewnątrz wp-content/uploads, zablokuj bezpośredni dostęp do wp-config.php oraz wyłącz listowanie zawartości katalogów. Te popularne — blokowanie xmlrpc.php „żeby powstrzymać ataki brute force”, ukrywanie wersji WordPressa, wklejanie 200-liniowej listy user-agentów złych botów — mieszczą się w skali od marginalnych po czysty teatrzyk. Poniżej wyjaśniam, które są które i dlaczego.

Najpierw jedna sprawa do ustalenia: .htaccess robi cokolwiek tylko na Apache (oraz LiteSpeed, który też go czyta). Na nginx jest całkowicie ignorowany — plik po prostu tam leży, a Ty myślisz, że jesteś zabezpieczony. Jeśli Twój hosting działa na nginx, nic z tego nie ma zastosowania i zamiast tego potrzebujesz bloków server/location. Sprawdź to poleceniem curl -I https://twojastrona.pl i spójrz na nagłówek Server:, zanim spędzisz godzinę na edytowaniu pliku, którego serwer nigdy nie czyta.

Reguła, która naprawdę ma znaczenie: żadnego PHP w /uploads

To ta, którą warto wdrożyć. wp-content/uploads jest z założenia zapisywalny dla wszystkich — każde przesłane medium, każda wtyczka zapisująca plik zapisuje właśnie tutaj. Jeśli atakujący umieści w tym katalogu plik .php (przez podatny mechanizm przesyłania, pole obrazka, które nie weryfikuje typu MIME, przejętą wtyczkę), o tym, czy skończy się na uciążliwości, czy na pełnej kompromitacji z wykonaniem kodu zdalnego, decyduje jedno: czy serwer wykona ten plik przy żądaniu. Zablokuj wykonywanie, a przesłany ładunek stanie się tylko bezczynnym plikiem leżącym na dysku.

Wrzuć to do wp-content/uploads/.htaccess (utwórz plik, jeśli nie istnieje):

<FilesMatch "\.php$">
    Require all denied
</FilesMatch>

To składnia Apache 2.4. Na starszym 2.2 odpowiednikiem jest Order Deny,Allow / Deny from all. Mieszanie obu dialektów w jednym pliku to najczęstsza przyczyna nagłego 500 Internal Server Error po „zabezpieczeniu” — jeśli cała strona pada w momencie zapisu, to niemal zawsze właśnie z tego powodu. Sprawdź swoją wersję poleceniem apachectl -v.

Zabezpiecz wp-config.php

wp-config.php przechowuje dane dostępowe do bazy danych oraz klucze zabezpieczeń. Dopóki PHP działa, bezpośrednie żądanie do niego zwraca pustą stronę — PHP wykonuje plik, zamiast go wyświetlać. Ryzyko tkwi w scenariuszu awarii: jeśli PHP kiedyś się zawiesi, zostanie źle skonfigurowane podczas migracji albo obsługa PHP zostanie wyłączona, Apache poda plik jako zwykły tekst i zrzuci Twoje hasło do bazy każdemu, kto o nie poprosi. Zablokowanie dostępu to tania polisa na wypadek złych pięciu minut:

<Files wp-config.php>
    Require all denied
</Files>

Wyłącz listowanie zawartości katalogów

Jeśli ktoś wejdzie do folderu bez pliku index.php, a Apache ma włączone Options +Indexes, wylistuje jego zawartość — każdy plik kopii zapasowej, każdy zapomniany zrzut SQL. Wyłącz to dla całej witryny:

Options -Indexes

Niska istotność, ale realna, a nic nie kosztuje.

To uczciwy, podstawowy zestaw. Możesz złożyć te reguły — razem z poprawną składnią 2.4 kontra 2.2, żeby nie wywalić strony błędem 500 — za pomocą generatora .htaccess dla WordPress, zamiast kopiować je z posta na forum napisanego dla niewłaściwej wersji Apache.

Czego NIE robić

Blokowanie xmlrpc.php „dla ochrony przed brute force”. To ten wielki mit, który wszyscy powtarzają, i w tej formie jest po prostu błędny. Owszem, metoda system.multicall w XML-RPC historycznie pozwalała atakującemu spakować wiele prób logowania w jedno żądanie — realna amplifikacja. Ale zdecydowanie najczęstszym wektorem brute force są zwykłe żądania POST do wp-login.php, a blokowanie xmlrpc.php nie robi z tym nic. Brute force pokonuje się przez ograniczanie liczby żądań (rate limiting), silne hasła i 2FA — a nie przez ubicie jednego endpointu. Istnieje uzasadniony powód, by wyłączyć XML-RPC: jego funkcja pingback może zostać nadużyta do reflektowanego ataku DDoS, więc jeśli nie korzystasz z Jetpacka, aplikacji mobilnej ani pingbacków, zamknięcie go zmniejsza powierzchnię ataku. Tylko nie wmawiaj sobie, że to Twoja obrona przed brute force, bo nią nie jest.

Ukrywanie wersji WordPressa / usuwanie tagu generatora. Usunięcie readme.html i tagu <meta name="generator"> sprawia wrażenie zabezpieczania. Atakujący rozpozna Twoją wersję z parametrów zapytań przy dołączanych zasobach, znaczników edytora blokowego i tuzina innych oznak w kilka sekund. Nic nie ukrywasz — po prostu dajesz sobie poczucie zajętości.

Gigantyczne listy blokujące złe boty po user-agent i referrerze. User-agent to pojedynczy, łatwy do podrobienia nagłówek HTTP. Takie listy są nieaktualne już w dniu wklejenia, nie blokują nikogo kompetentnego, a Apache przetwarza każde wyrażenie regularne przy każdym żądaniu — płacisz realny podatek wydajnościowy za zero bezpieczeństwa. Odpuść je.

Blokowanie wp-login.php po adresie IP. Świetne, dopóki Twój dostawca internetu nie zmieni Ci adresu i sam nie zablokujesz sobie dostępu do własnego panelu. Sensowne tylko przy naprawdę statycznym IP.

Przekierowania przeciw enumeracji autorów (?author=1). Reguła przepisywania w .htaccess, którą ludzie wklejają na to, jest sama w sobie niekompletna — endpoint REST /wp-json/wp/v2/users nadal wylistuje nazwy użytkowników. Blokowanie jednej ścieżki, podczas gdy druga stoi otworem, to teatrzyk.

Nadal utknąłeś?

Jeśli reguła wywala stronę błędem 500, to kwestia składni — usuń ostatni dodany blok i przeładuj; to od razu go izoluje. Jeśli reguła zdaje się nie robić nic, upewnij się, że faktycznie działasz na Apache i że AllowOverride jest włączone dla danego katalogu (wiele hostingów zarządzanych to ogranicza). Zbuduj plik z pewnego, sprawdzonego szablonu za pomocą generatora .htaccess, zostaw trzy reguły, które mają znaczenie, a resztę odpuść.

FAQ

Pytania

Jak zablokować uruchamianie plików php w katalogu uploads WordPressa?

Utwórz plik .htaccess wewnątrz wp-content/uploads z blokiem FilesMatch dopasowującym pliki .php i dyrektywą Require all denied. Ponieważ katalog uploads jest z założenia zapisywalny dla wszystkich, odcięcie wykonywania sprawia, że złośliwy plik .php, który tam trafi, leży na dysku jako martwy plik zamiast stać się zdalnym wykonaniem kodu.

Czy trzeba blokować bezpośredni dostęp do wp-config.php?

Tak, i nic to nie kosztuje. Dodaj blok Files dla wp-config.php z dyrektywą Require all denied. Gdy PHP działa, bezpośrednie żądanie zwraca po prostu pustą stronę, ale jeśli PHP się wywali, zostanie źle skonfigurowane podczas migracji albo handler zostanie wyłączony, Apache poda ten plik jako zwykły tekst i wysypie twoje dane dostępowe do bazy.

Dlaczego moja witryna pokazała błąd 500 Internal Server Error zaraz po edycji .htaccess?

Prawie zawsze przez pomieszaną składnię Apache. Require all denied to Apache 2.4, natomiast Order Deny,Allow z Deny from all to wersja 2.2, a połączenie obu dialektów w jednym pliku psuje witrynę w chwili zapisu. Sprawdź wersję poleceniem apachectl -v albo usuń ostatni dodany blok i przeładuj.

Czy .htaccess działa na nginx?

Nie. .htaccess robi cokolwiek wyłącznie na Apache oraz na LiteSpeed, który również go czyta. Na nginx plik jest całkowicie ignorowany, więc leży sobie, podczas gdy ty myślisz, że jesteś chroniony. Najpierw uruchom curl -I na swojej witrynie i sprawdź nagłówek Server:, a potem użyj bloków server lub location.

Czy zablokowanie xmlrpc.php powstrzymuje ataki brute force na WordPress?

Nie. Zdecydowanie najczęstszym wektorem brute force są zwykłe żądania POST do wp-login.php, na co blokada xmlrpc.php w ogóle nie działa. Brute force pokonuje się ograniczaniem liczby prób, silnymi hasłami i 2FA. Wyłączenie XML-RPC nadal ma sens, jeśli nie używasz Jetpacka, aplikacji mobilnej ani pingbacków, bo pingback bywa nadużywany do odbijania ataków DDoS.