Jak zabezpieczyć plik wp-login.php przed atakami typu brute force

Zabezpieczenie

Ataki typu brute force to dla każdego użytkownika WordPressa chleb powszedni. Praktycznie każda strona oparta na tym CMSie jest mniej lub bardziej intensywnie atakowana przez automaty próbujące zalogować się na konto administratora, korzystając najczęściej z metody słownikowej (używając listy najpopularniejszych haseł). Ataki takie są bardzo charakterystyczne i łatwo je znaleźć w logach serwera – wystarczy zwrócić uwagę na częste żądania wysyłane do pliku wp-login.php, który służy do autoryzacji użytkowników.

Teoretycznie, jeśli stosujemy się do podstawowych zasad bezpieczeństwa, atakujący ma małe szanse na powodzenie. Jednak duża ilość tego typu prób ataków może spowolnić naszą stronę, a w najgorszym razie doprowadzić nawet do całkowitego jej unieruchomienia. Dlatego też dobrze jest zabezpieczyć się i zablokować całkowicie tego typu działania.

Każde żądanie wysyłane do pliku wp-login.php zużywa trochę zasobów serwera. Jeśli korzystamy z hostingu współdzielonego, to w skrajnym przypadku może to doprowadzić do zablokowania naszego konta z powodu przekroczenia limitów wykorzystania zasobów (czasu procesora, zapytań do bazy danych itp.).

Do zablokowania ataków skierowanych na wp-login.php można wykorzystać jedną z dostępnych wtyczek. Kompleksowe rozwiązania, takie jak WordFence czy iThemes Security, robią mnóstwo rzeczy mających poprawić bezpieczeństwo naszej strony. Używanie tego typu wtyczek jest generalnie dobrym pomysłem, ale w tym akurat konkretnym przypadku prostsze sposoby są lepsze.

Najskuteczniejszą metodą ochrony przed skutkami ataków typu brute force jest zablokowanie ich zanim dotrą do naszej strony, czyli na poziomie serwera HTTP (można zrobić to jeszcze wcześniej, ale z przyczyn technicznych najczęściej nie jesteśmy tego w stanie tego wykonać). Wtyczki blokujące ataki brute force są napisane (tak jak i sam WordPress) w PHP, tak więc angażują interpreter tego języka, co powoduje dodatkowe (niepotrzebne) obciążenie serwera.

Większość firm hostingowych korzysta z serwera Apache i na nim skupię się w dalszej części tego wpisu.

Najprostszą metodą na zablokowanie dostępu do pliku wp-login.php jest dodanie takiego wpisu do pliku .htaccess:

Wpis ten blokuje całkowicie wszystkie żądania wysyłane do tego pliku, za wyjątkiem żądań z adresu IP 123.123.123.123 (tutaj należy wpisać własny adres IP, który można sprawdzić na przykład tutaj). Nic oczywiście nie stoi na przeszkodzie, aby odblokować dostęp z kilku adresów – wystarczy dodać kolejne linie allow from.

Tej metody nie ma sensu stosować na stronach, które pozwalają użytkownikom na rejestrację i logowanie.

Problem z tą metodą pojawia się w momencie, gdy nasz adres IP jest zmienny (większość dostawców łącz wymusza co jakiś czas zmianę IP). Ponieważ po zmianie adresu zostaniemy pozbawieni możliwości zalogowania się do panelu administracyjnego strony, konieczne będzie albo wprowadzenie aktualnego IP do pliku .htaccess, albo użycie innej metody.

Powyższy kod blokuje wszystkie wysyłane do pliku wp-login.php żądania typu POST, które nie posiadają nagłówka Referer z adresem w naszej domenie. Automaty najczęściej w ogóle nie przekazują tego nagłówka, tak więc metoda ta w większości przypadków się sprawdzi. Problem polega na tym, że spora część atakujących najpierw wysyła żądanie typu GET (którego tą metodą nie zablokujemy), a dopiero potem POST. Rozwiązaniem jest usunięcie z powyższego kodu linii RewriteCond %{REQUEST_METHOD} POST, co z kolei utrudni nam nieco dostęp do strony logowania (nie będziemy mogli wejść na nią bezpośrednio).

Poza plikiem wp-login.php często atakowany jest również plik xmlrpc.php. Jeśli nie korzystamy z interfejsu XML-RPC, warto całkowicie zablokować dostęp do tego pliku dodając do .htaccess następujący wpis:

Zdjęcie: David Hamilton

Bezpośredni link

  • Sebastian Pisula

    „Problem polega na tym, że spora część atakujących najpierw wysyła żądanie typu GET (którego tą metodą nie zablokujemy), a dopiero potem POST.”

    wynika to z tego, że bot sprawdza czy istnieje wp-login.php? czy w jakim celu?

    • Na pewno nie sprawdza czy plik istnieje, bo automaty walą na oślep (szkoda czasu na takie sprawdzanie). Jedyne co mi przychodzi do głowy, to próba wykorzystania malware SoakSoak (i jego klonów), który zostawia w wp-login.php backdoora reagującego na „komendy” przesyłane metodą GET.

  • Po co sobie tak komplikować sprawę, skoro można po prostu zainstalować Rublon Account Security (http://wordpress.rublon.com) i mieć problem z głowy? :-) Rublon uniemożliwi zalogowanie botom, a my będziemy mogli się logować wygodnie z dowolnego urządzenia. Poza tym podniesiemy bezpieczeństwo dzięki dwuskładnikowym uwierzytelnianiu, które na każdym urządzeniu musimy wykonać tylko raz.

    • Twój post (słusznie zresztą) wpadł do spamu. Zatwierdziłem go tylko dlatego, że chcę na niego odpowiedzieć.

      Domyślam się, że nie przeczytałeś zbyt uważnie tego wpisu – rzuciłeś co najwyżej na niego okiem i uznałeś, że to kolejne dobre miejsce na wepchnięcie reklamy Twojej usługi. Taką masz strategię marketingową – jak widać kiepską, skoro w ciągu 21 miesięcy obecności w repozytorium Twoją wtyczkę pobrano niespełna 13 tysięcy razy (nie wspomnę o znacznie mniejszej liczbie instalacji).

      Możesz powiedzieć, że to nie moja sprawa jak prowadzisz swój biznes. Możesz powiedzieć, że jesteś usatysfakcjonowany z liczby pozyskanych klientów. Możesz powiedzieć, że Twoje nachalne spamowanie przynosi zadowalające efekty.

      Ale nie wciskaj ludziom kitu i nie pisz bzdur.

      Co z tego, że Twoja usługa uniemożliwia zalogowanie botom, skoro w tym wpisie nie ma mowy o samym logowaniu, ale o redukcji obciążenia serwera generowanego przez same próby logowania? Prawda jest taka, że (zakładając brak podatności w innych miejscach, np. dziurawych wtyczkach) przy stosowaniu odpowiednio silnego hasła szanse na udany atak metodą brute force są minimalne (o ile nie żadne). W tym wpisie chodzi głównie o obciążenie, jakie generuje taki atak – a na to Twoje usługa nic nie poradzi.

      Nie neguję sensu korzystania z dwuskładnikowego uwierzytelniania. Ale spamując przynajmniej zadaj sobie trud przeczytania komentowanego tekstu.

      • PiotrPo

        Po co nam rublon skoro możemy zrobić dwuskładnikowe uwierzytelnianie za pomocą htaccess.

        • Wpięcie kolejnego formularza logowania nie wprowadza drugiego składnika, tylko jedynie kolejny etap przy wykorzystaniu identycznej formy potwierdzenia tożsamości (wiedzę w postaci nazwy użytkownika i hasła). Z punktu widzenia bezpieczeństwa osiągniesz ten sam efekt, jeżeli dokleisz nazwę i hasło stosowane w formularzu .htaccess to nazwy i hasła Twojego konta w WordPress. Mógłbyś też wyświetlić pod sobą dwa formularza logowania i wymagać od użytkownika wypełnienia obu. Poziom bezpieczeństwa podniesiesz dopiero, jak wprowadzisz składnik innej formy (np. fizyczny obiekt taki jak telefon albo cechę biometryczną taką jak odcisk palca).

          • PiotrPo

            Jakie zapotrzebowanie takie zabezpieczenie.

      • Bartoszu, w samym tytule Twojego wpisu jak i w pierwszym akapicie piszesz o kwestiach dotyczących logowania. Celem ataku brute force jest uzyskanie danych logowania umożliwiających zalogowanie się do usługi — nie jest to atak DoS, ale może się w taki przekształcić. Zgadza się, że Rublon na dzień dzisiejszy jest jedynie zabezpieczeniem przed atakami brute force i nie pomoże z atakami DoS (możliwe jednak, że w niedalekiej przyszłości będziemy w stanie pomóc i tutaj). Jednak sam wspomniałeś o innych wtyczkach dot. bezpieczeństwa, chroniących przed brute force — zatem uznałem, że warto wspomnieć również o Rublonie. W każdym razie proponuję zmianę tytułu Twojego wpisu na „Jak zabezpieczyć plik wp-login.php przed atakami DoS”, gdyż obecny wprowadza czytelników w błąd.

        PS:
        Niepotrzebnie się wychylasz — obawiam się, że Rublon codziennie wykonuje więcej uwierzytelnień, niż osób zagląda w miesiącu na Twojego bloga… Rublon to nie tylko WordPress.

        • Aha, czyli przeczytałeś tylko tytuł i pierwszy akapit. Pewnie dlatego dziwnie odbierasz poruszany we wpisie temat.

          Proponuję zakończyć tę dyskusję, bo (co wiem z doświadczenia) i tak do niczego ona nie doprowadzi.

          • Przeczytałem całość. Tytuł artykułu porusza jeden temat, aczkolwiek artykuł porusza dwa tematy. Mój komentarz dotyczył pierwszego tematu poruszonego w artykule.

  • Kuba

    Prestashop dla każdej instalacji generuje inny link do panelu admina, np admin318wydjv. Ziezłe, bo hakerzy nie wiedzą co zaatakować. Wprowadzenie czegoś takiego w Wordpressie też się by sprawdziło.

    • nickpiotr

      Admin adminem. Większość ataków wykonywanych jest na wtyczki.

  • Jak zwykle bardzo pomocny wpis do zabespieczenia panelu logowania stosuje .htpasswd
    ale bardzo przydał mi się kod na blokadę xmlrpc.php
    dzięki :)

  • Adam314

    A przeniesienie wp-admin pod inną nazwę? Najprostsze rozwiązanie a boty niech się odbijają od 404.

    • Plik wp-login.php znajduje się w katalogu głównym WordPressa, a nie w katalogu ‚wp-admin’.

      • Kuba

        A zmiana nazwy samego pliku? Zadziałałoby?

  • Adam

    Pracuję na innym CMS-e i miałem kilka lat temu „wjazd”. Oczywiście miałem kopię zapasową i się tym nie przejąłem. Na jakiś czas po prostu skasowałem plik logowania i się chłopcy zniechęcili. ;) Następne wydanie było już poprawione i od tego czasu nie mam kłopotu. Obecne moje hasło ma ponad dwadzieścia znaków i to wystarczy. ;P

  • Tretos

    Przy okazji warto pamiętać przy zabezpieczaniu /wp-admin/ za pomocą .htaccess o regule

    Order allow,deny
    Allow from all
    Satisfy any

    Inaczej przy każdym wywołaniu strony głównej będzie monit o hasło.

  • ForumBukmacherskie

    Witam

    Mam pytane jak zabezpieczyć buddypressa? jak wiemy tam każdy użytkownik loguję się poniekąd do kokpitu tak więc bezpieczeństwo jest jeszcze mniejsze . Jakie podstawowe kroki należy wykonać ?

  • Non

    A zabezpieczenie hasłem poprzez plik .htaccess.?

    • Oczywiście też się sprawdzi.

      • luk

        @toszcze:disqus – Użyłem metody zahasłowania wp-login i jest świetna, ale PSUJE wpisy zabezpieczone hasłem :(
        A mam na stronach np. galerie zdjęć dla innych przeglądających na hasło.
        Czy znasz może jakiś sposób na obejście tego problemu?

        • Krzysiek już Ci na to pytanie odpowiedział pod innym Twoim komentarzem. Tak „z głowy” to nie znam na to żadnego sposobu, bo szczerze mówiąc bardzo rzadko korzystam z zabezpieczania wpisów hasłem.

        • Paweł Knapek

          Sposoby zawsze jakieś można wymyślić.
          Dla metody opartej na mod_rewrite można np. wykluczać z blokowania dodatkowym warunkiem w oparciu o query stringa, czyli np.: RewriteCond %{QUERY_STRING} !action=postpass [NC]
          (nic nie stoi na przeszkodzie by tą regułką rozblokować i inne akcje jak przypominanie hasła czy rejestracja)
          Zaś w przypadku blokady przez dissalow albo autoryzację, można kombinować z warunkowym ustawianiem ENV https://httpd.apache.org/docs/2.4/mod/mod_setenvif.html , a potem dajmy na to: allow from env=cośtam
          Inny, to hak w ten deseń https://pastebin.com/jwPFBDGh
          Jeszcze inny, to podmiana adresu w połaczeniu z kopią pliku wp-login.php pod zmienioną nazwą albo z użyciem symlinka.

  • A czy przypadkiem Jetpack nie korzysta z xmlrpc ? Jeśli go zablokujemy to w takim przypadku korzystanie z Jetpack też będzie niemożliwe. Poprawcie mnie jeśli się mylę

    • Zgadza się. Można dodać do wyjątków adresy IP należące do Automattic – to powinno załatwić sprawę:

      allow from 192.0.64.0/18
      allow from 209.15.0.0/16
      allow from 66.155.0.0/17
      allow from wordpress.com

      Nie wiem czy to wszystkie adresy.

  • A mam pytanie, zauważyłem, iż część prób włamań była z użyciem mojego nicka, zmieniłem swój nick na inny. Ale już po kilku dniach odnotowałem próby ataku na ten nowy. Skąd atakujący mogą go znać, jeśli nie jest widoczny?

    • Twój nick znajduje się w adresie archiwum autora – najprawdopodobniej masz taki link przy każdym wpisie. Dlatego dobrze jest albo usunąć linki do archiwum autora (jeśli nie są Ci potrzebne), albo publikować wpisy używając konta, które nie ma uprawnień administratora.

      • Ok, faktycznie :) A podobno nie istnieją głupie pytania :)
        Link do archiwum autora muszę wyłączyć przez edycję szablonu? Bo w sumie nie jest mi potrzebne, a publikacja z profilu nie mającego uprawnień autora i tak będzie generować kolejne próby włamu

    • Nathalie

      Usuniecie linków nie za wiele da, bo nick łatwo sprawdzić dopisując na koniec domeny ciąg: /?author=1
      Można to wyłączyć w pliku funtions.php za pomocą:

      add_action(‚template_redirect’, ‚bwp_template_redirect’);
      function bwp_template_redirect() {
      if (is_author())
      {
      wp_redirect( home_url() );
      exit;
      }
      }

  • Witajcie,
    pytanie dotyczące metody blokowania IP przez .htaccess. Czy istnieje wersja dla dynamicznego IP? Czy można np. wpisać tylko pierwsze trzy człony numeru: 123.123.123.— i czy to zadziała?

    • Tak, to zadziała.

      • To jeszcze jedno pytanie. W moim pliku .htaccess jest taki wpis:

        # BEGIN WordPress

        RewriteEngine On
        RewriteBase /
        RewriteRule ^index.php$ – [L]
        RewriteCond %{REQUEST_FILENAME} !-f
        RewriteCond %{REQUEST_FILENAME} !-d
        RewriteRule . /index.php [L]

        # END WordPress

        Do czego służy?

  • Adam

    Witam, zabezpieczyłem wp-login.php w powyższy sposób jednak wtyczka sucuri której używam ciągle monituje ataki brute-force czyli dalej następuje interpretacja zapytań pomimo blokady. Blokada działa gdyż sprawdzałem ją na innych adresach IP. W nowszych wersjach wordpressa jest inna możliwość logowania niż przez wp-login?

    • Paweł Knapek

      A ten brutal nie wali przypadkiem w xmlrpc.php ? ;)

      • Adam

        Tego mi akurat wtyczka nie wyświetla. xmlrpc.php mogę zabezpieczyć w identyczny sposób? Z tego co widzę jest jakiś skrypt do zapytań POST ale nie wiem jaka jest jego funkcja w Wordpressie.

        • Paweł Knapek

          Tak, można go również w taki sposób zabezpieczyć.
          XML-RPC najprościej jak można – jest interfejsem komunikacyjnym działającym pod maską. Umożliwia zdalne zarządzanie WP. Jak nie wiesz co to, to i najpewniej z niego nie korzystasz …no chyba, że przypadkiem masz np. zainstalowaną wtyczkę Jetpack albo zarządzasz stroną poprzez jakąś zewnętrzną apkę.

          • Adam

            Problem z brute-force zniknął po zablokowaniu xml-rpc :)

            Dzięki za pomoc.

  • Warto przy tym tylko wspomnieć, że w ten sposób zepsujemy pewną funkcjonalność WordPressa – a mianowicie wpisy zabezpieczone hasłem. Dlaczego? Bo to właśnie wp-login.php obsługuje ten formularz ;)

    • luk

      Bardzo istotna wzmianka! Nawiązując do tego chciałbym zapytać czy znasz jakąś metodę, aby wpisy na hasło działały jednocześnie z tym zabezpieczeniem?
      No chyba, że lepiej zastosować deny na wp-login i zrobić symlinka lub też samo passwd htaccess?

      • Najprościej? Zmodyfikować formularz z hasłem do wpisów – jego obsługa jest dość prosta, a filtry ładnie na wszystko pozwalają.

  • Marek

    Dzięki za kody htaccess. Mam nadzieję, że ukróci to te ataki, których ostatnio mam jakby dużo więcej. Na szczęście w kilku miejscach mam stałe IP ale w razie potrzeby przez FTP zaktualizuję htaccess i wbije się z każdego miejsca :)