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ść.