Plik .htaccess jest jednym z mechanizmów konfiguracyjnych serwera Apache HTTP Server. Pozwala zmieniać wybrane ustawienia serwera na poziomie konkretnego katalogu bez konieczności edytowania głównej konfiguracji Apache.
Odpowiednio przygotowany .htaccess może stanowić dodatkową warstwę ochrony witryny. Za jego pomocą można między innymi ograniczać dostęp do wrażliwych plików, wyłączać listowanie katalogów, wymuszać HTTPS, dodawać nagłówki bezpieczeństwa czy blokować określone typy żądań.
Trzeba jednak pamiętać, że .htaccess nie zastępuje prawidłowo zabezpieczonej aplikacji, aktualnego oprogramowania, firewalla ani WAF. Reguły na poziomie Apache należy traktować jako jeden z elementów wielowarstwowego zabezpieczenia serwisu.
Poniżej przedstawiam przykłady dyrektyw, które mogą przydać się podczas zabezpieczania strony.
1. Ograniczenie informacji ujawnianych przez Apache
ServerSignature Off
ServerTokens Prod
Celem tych ustawień jest ograniczenie informacji o serwerze ujawnianych użytkownikowi. ServerSignature Off wyłącza podpis Apache między innymi na generowanych przez serwer stronach błędów, natomiast ServerTokens Prod ogranicza informacje przesyłane w nagłówku Server.
Warto pamiętać, że możliwość zastosowania tych dyrektyw bezpośrednio w .htaccess zależy od konkretnej konfiguracji Apache. Część ustawień może wymagać dostępu do głównego pliku konfiguracyjnego serwera.
2. Zablokowanie dostępu do pliku .htaccess
Sam plik .htaccess nie powinien być dostępny publicznie. Można dodatkowo ograniczyć możliwość jego odczytania:
<Files ".htaccess">
Require all denied
</Files>
Podobną zasadę można zastosować wobec innych plików zawierających konfigurację lub dane, które nie powinny być dostępne przez przeglądarkę.
3. Ochrona wrażliwych plików
W katalogu strony mogą znajdować się pliki zawierające konfigurację, dane dostępowe, informacje o zależnościach czy kopie zapasowe.
Przykładowa reguła:
<FilesMatch "^(\.env|composer\.(json|lock)|wp-config\.php)$">
Require all denied
</FilesMatch>
Można w ten sposób ograniczyć dostęp między innymi do .env, composer.json, composer.lock czy wp-config.php.
Należy przy tym pamiętać, że katalogi takie jak .git wymagają osobnego podejścia. Najlepszym rozwiązaniem jest niedopuszczanie do ich publikowania w katalogu dostępnym z internetu.
4. Ochrona przed MIME sniffingiem
Warto dodać nagłówek:
Header always set X-Content-Type-Options "nosniff"
Informuje on przeglądarkę, że powinna respektować zadeklarowany typ MIME zasobu zamiast próbować samodzielnie interpretować jego zawartość.
Jest to proste zabezpieczenie, które warto stosować w większości współczesnych witryn.
5. Content Security Policy
Jednym z najważniejszych nagłówków bezpieczeństwa jest Content-Security-Policy (CSP).
Przykład:
Header always set Content-Security-Policy "default-src 'self';"
CSP pozwala określić, z jakich źródeł strona może pobierać skrypty, style, obrazy, fonty, ramki i inne zasoby.
Nie istnieje jednak jedna uniwersalna polityka CSP odpowiednia dla każdej witryny. Konfigurację należy dostosować do zasobów faktycznie wykorzystywanych przez stronę.
Nieprzemyślane zastosowanie bardzo restrykcyjnego CSP może spowodować, że część serwisu przestanie działać.
6. Ochrona przed clickjackingiem
Jednym ze sposobów ograniczenia możliwości osadzania strony w ramkach jest:
Header always set X-Frame-Options "DENY"
Jeżeli witryna powinna mieć możliwość wyświetlania własnych podstron w iframe, można rozważyć:
Header always set X-Frame-Options "SAMEORIGIN"
W nowoczesnych konfiguracjach warto również wykorzystać dyrektywę frame-ancestors w ramach Content Security Policy, ponieważ daje ona większą kontrolę nad tym, kto może osadzać stronę.
7. Referrer-Policy
Kolejnym przydatnym nagłówkiem jest:
Header always set Referrer-Policy "strict-origin-when-cross-origin"
Pozwala on kontrolować zakres informacji przekazywanych w nagłówku Referer podczas przechodzenia użytkownika pomiędzy stronami.
Może to ograniczyć niepotrzebne ujawnianie pełnych adresów URL zewnętrznym witrynom.
8. Permissions Policy
Można również kontrolować dostęp strony do wybranych funkcji przeglądarki:
Header always set Permissions-Policy "camera=(), microphone=(), geolocation=()"
W tym przykładzie wyłączony zostaje dostęp do kamery, mikrofonu oraz geolokalizacji.
Politykę należy oczywiście dopasować do funkcjonalności witryny.
9. Wyłączenie listowania katalogów
Jedna z najprostszych i najbardziej przydatnych reguł:
Options -Indexes
Jeżeli w katalogu nie znajduje się plik indeksowy, Apache nie wyświetli automatycznie listy znajdujących się w nim plików.
Zapobiega to przypadkowemu ujawnieniu struktury katalogów oraz znajdujących się w nich zasobów.
10. Wymuszenie HTTPS
Jeżeli witryna posiada prawidłowo skonfigurowany certyfikat TLS, ruch HTTP można przekierować na HTTPS:
RewriteEngine On
RewriteCond %{HTTPS} !=on
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]
Dzięki temu użytkownik korzystający z nieszyfrowanego adresu HTTP zostanie przekierowany na jego szyfrowany odpowiednik.
W środowiskach wykorzystujących reverse proxy, load balancer lub CDN reguła może wymagać modyfikacji, ponieważ Apache nie zawsze bezpośrednio obsługuje połączenie TLS.
11. HTTP Strict Transport Security – HSTS
Po prawidłowym wdrożeniu HTTPS można rozważyć HSTS:
Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains"
Nagłówek informuje obsługującą HSTS przeglądarkę, że z daną domeną powinna łączyć się wyłącznie za pomocą HTTPS.
Opcję:
preload
należy dodawać świadomie. Szczególnie includeSubDomains i preload wymagają upewnienia się, że wszystkie odpowiednie subdomeny prawidłowo obsługują HTTPS. Nieprzemyślane wdrożenie HSTS może spowodować problemy z dostępnością usług.
12. Blokowanie wybranych rozszerzeń plików
Publiczny dostęp do kopii zapasowych, logów czy plików konfiguracyjnych można ograniczyć:
<FilesMatch "\.(bak|conf|ini|log|sql|swp)$">
Require all denied
</FilesMatch>
Jest to szczególnie przydatne jako dodatkowa ochrona przed przypadkowym opublikowaniem plików, które nie powinny znaleźć się w publicznie dostępnym katalogu.
Najlepszą praktyką pozostaje jednak przechowywanie takich danych poza katalogiem publicznym serwera WWW.
13. Ochrona pliku wp-config.php w WordPressie
W przypadku WordPressa można jawnie zablokować dostęp do wp-config.php:
<Files "wp-config.php">
Require all denied
</Files>
Plik ten zawiera istotne informacje konfiguracyjne WordPressa i nie powinien być bezpośrednio dostępny przez HTTP.
14. Ograniczenie dostępu do xmlrpc.php
Jeżeli dana instalacja WordPressa nie wykorzystuje XML-RPC, można zablokować dostęp:
<Files "xmlrpc.php">
Require all denied
</Files>
Nie należy jednak robić tego automatycznie w każdej instalacji. Niektóre integracje i funkcje mogą korzystać z XML-RPC, dlatego wcześniej warto sprawdzić, czy jego wyłączenie nie wpłynie na działanie serwisu.
15. Ograniczenie dostępu do wp-login.php na podstawie IP
Jeżeli administrator posiada stały adres IP, dostęp do panelu logowania można dodatkowo ograniczyć:
<Files "wp-login.php">
Require ip 192.0.2.10
</Files>
Rozwiązanie może być bardzo skuteczne w określonych środowiskach, ale jest niepraktyczne dla administratorów korzystających z dynamicznego IP lub logujących się z różnych sieci.
16. Blokowanie adresów IP
Apache 2.4 umożliwia blokowanie konkretnych adresów:
<RequireAll>
Require all granted
Require not ip 192.0.2.100
</RequireAll>
Możliwe jest również ograniczenie dostępu wyłącznie do określonych adresów:
Require ip 192.0.2.100 192.0.2.101
Mechanizm ten sprawdza się na przykład w przypadku paneli administracyjnych, środowisk testowych czy wewnętrznych narzędzi.
17. Ograniczenie metod HTTP
Jeżeli aplikacja nie korzysta z określonych metod HTTP, można rozważyć ich ograniczenie.
Przykładowo:
<LimitExcept GET POST HEAD>
Require all denied
</LimitExcept>
Nie należy jednak blokować metod bez wcześniejszego sprawdzenia sposobu działania aplikacji.
Interfejsy REST API, WebDAV i inne rozwiązania mogą wykorzystywać między innymi PUT, PATCH, DELETE lub OPTIONS. Ich globalne zablokowanie może więc uszkodzić część funkcjonalności witryny.
18. Wyłączenie metody TRACE
Jeżeli konfiguracja serwera na to pozwala, warto wyłączyć TRACE:
TraceEnable Off
Dyrektywa ta zazwyczaj należy jednak do konfiguracji serwera lub VirtualHost, a nie do .htaccess. Jest to dobry przykład ustawienia bezpieczeństwa, którego nie zawsze można wdrożyć na poziomie pojedynczej witryny.
19. Ograniczenie wielkości żądania
Apache pozwala określić maksymalną wielkość danych przesyłanych w żądaniu:
LimitRequestBody 10485760
W powyższym przykładzie limit wynosi około 10 MB.
Wartość należy dopasować do charakteru witryny. Jeżeli użytkownicy przesyłają większe pliki, zbyt niski limit uniemożliwi prawidłowe działanie formularzy lub systemu uploadu.
20. Ochrona katalogu z przesyłanymi plikami
Jeżeli aplikacja umożliwia użytkownikom przesyłanie plików, jednym z kluczowych zabezpieczeń jest uniemożliwienie wykonywania kodu znajdującego się w katalogu uploadów.
Przykładowy .htaccess umieszczony w takim katalogu może zawierać reguły blokujące niepożądane rozszerzenia:
<FilesMatch "\.(php|phtml|phar)$">
Require all denied
</FilesMatch>
Samo filtrowanie rozszerzeń nie powinno być jednak jedynym zabezpieczeniem mechanizmu uploadu. Aplikacja powinna również kontrolować typ i zawartość pliku, generować bezpieczne nazwy oraz – jeśli to możliwe – przechowywać przesyłane dane poza katalogiem wykonywalnym.
21. Blokowanie hotlinkowania
.htaccess może również ograniczać osadzanie zasobów witryny na zewnętrznych stronach:
RewriteEngine On
RewriteCond %{HTTP_REFERER} !^$
RewriteCond %{HTTP_REFERER} !^https?://(www\.)?example\.com/ [NC]
RewriteRule \.(jpg|jpeg|png|gif|webp)$ - [F,L,NC]
Rozwiązanie może ograniczyć wykorzystywanie transferu przez zewnętrzne witryny osadzające obrazy bezpośrednio z naszego serwera.
Nie jest to jednak zabezpieczenie kryptograficzne – nagłówek Referer może być nieobecny lub zmodyfikowany.
22. Blokowanie podejrzanych User-Agentów
Możliwe jest również blokowanie określonych klientów na podstawie User-Agent:
RewriteEngine On
RewriteCond %{HTTP_USER_AGENT} (BadBot|EvilScanner) [NC]
RewriteRule ^ - [F,L]
Takie rozwiązanie może ograniczyć ruch generowany przez niektóre automaty, ale nie stanowi skutecznego zabezpieczenia przed zaawansowanymi botami. User-Agent można bardzo łatwo zmienić.
Do poważniejszej ochrony przed botami lepiej wykorzystać firewall, WAF, system rate limiting lub rozwiązania działające przed serwerem WWW.
23. Reguły przeciwko SQL Injection – czy warto?
W internecie można znaleźć wiele reguł .htaccess próbujących wykrywać SQL Injection na podstawie zawartości QUERY_STRING, np. wyszukujących słowa SELECT, UNION czy znaki charakterystyczne dla zapytań SQL.
Takie rozwiązania należy stosować z dużą ostrożnością.
Filtrowanie adresów URL w .htaccess nie jest właściwym sposobem zabezpieczania aplikacji przed SQL Injection. Może powodować fałszywe alarmy, blokować prawidłowe zapytania, a jednocześnie nie zapewnia pełnej ochrony.
Podstawową metodą ochrony przed SQL Injection powinny być parametryzowane zapytania do bazy danych, odpowiednia walidacja danych oraz prawidłowo zaprojektowana aplikacja. Dodatkową warstwę ochrony może zapewniać WAF.
24. Czy .htaccess ochroni stronę przed XSS?
Podobna zasada dotyczy Cross-Site Scripting.
Nie należy zakładać, że pojedyncza dyrektywa w .htaccess rozwiązuje problem XSS. Ochrona powinna przede wszystkim wynikać z prawidłowego kodowania danych wyjściowych, walidacji danych wejściowych i bezpiecznej konstrukcji aplikacji.
Dodatkową warstwą ochrony może być odpowiednio przygotowana Content Security Policy.
Historyczny nagłówek:
X-XSS-Protection
nie powinien być obecnie traktowany jako podstawowe zabezpieczenie przed XSS. We współczesnych aplikacjach zdecydowanie większe znaczenie ma prawidłowe zabezpieczenie kodu oraz dobrze skonfigurowany CSP.
25. Cookies – HttpOnly, Secure i SameSite
Często spotykanym przykładem jest globalne modyfikowanie nagłówka Set-Cookie z poziomu .htaccess w celu dodania:
HttpOnly
Secure
SameSite=Strict
Takie podejście nie zawsze jest dobrym rozwiązaniem.
Atrybuty bezpieczeństwa powinny być ustawiane indywidualnie dla ciasteczek przez aplikację, ponieważ różne cookies mogą wymagać odmiennej konfiguracji.
HttpOnly jest szczególnie ważne dla ciasteczek sesyjnych, Secure wymusza ich przesyłanie przez HTTPS, natomiast SameSite ogranicza sposób wysyłania cookies w kontekście żądań pochodzących z innych witryn.
Ustawienie SameSite=Strict dla wszystkich cookies może jednak spowodować problemy z logowaniem, płatnościami lub integracjami z zewnętrznymi usługami.
26. Czy .htaccess może zabezpieczyć przed DDoS?
Możliwości .htaccess w zakresie ochrony przed atakami DDoS są bardzo ograniczone.
Można blokować konkretne adresy IP lub określone rodzaje żądań, jednak przy rzeczywistym ataku wolumetrycznym żądanie zazwyczaj dociera już do infrastruktury serwera.
Skuteczniejsza ochrona przed DDoS powinna działać wcześniej – na poziomie dostawcy hostingu, reverse proxy, CDN, firewalla lub wyspecjalizowanej usługi ochronnej.
27. Konfiguracja TLS
W konfiguracjach Apache można spotkać ustawienia takie jak:
SSLProtocol -all +TLSv1.2 +TLSv1.3
czy konfigurację zestawów szyfrów.
Nie są to jednak typowe ustawienia przeznaczone do .htaccess. Parametry protokołów TLS najlepiej konfigurować na poziomie serwera lub VirtualHosta.
Jeżeli korzystamy z hostingu współdzielonego, za konfigurację TLS często odpowiada bezpośrednio dostawca hostingu.
28. Dyrektywa Directory a plik .htaccess
Popularnym błędem jest umieszczanie w .htaccess konstrukcji:
<Directory "/path/to/private_folder">
...
</Directory>
Sekcja <Directory> jest przeznaczona do głównej konfiguracji Apache i konfiguracji VirtualHost, a nie do pliku .htaccess.
Jeżeli chcemy chronić konkretny katalog przy użyciu .htaccess, reguły dostępu należy umieścić bezpośrednio w .htaccess znajdującym się w odpowiednim katalogu lub zastosować inne mechanizmy dostępne na danym hostingu.
29. Stara i nowa składnia Apache
W wielu poradnikach nadal można znaleźć reguły:
Order Allow,Deny
Deny from all
Są one charakterystyczne dla starszych konfiguracji Apache 2.2 i mechanizmów zgodności.
W przypadku Apache 2.4 preferowana jest składnia oparta na Require, np.:
Require all denied
lub:
Require all granted
Przy tworzeniu nowych konfiguracji warto korzystać z aktualnej składni i zawsze sprawdzić wersję Apache działającą na serwerze.
30. Czy wszystkie zabezpieczenia warto umieścić w .htaccess?
Nie. To jedna z najważniejszych zasad.
Nie istnieje uniwersalny „bezpieczny .htaccess”, który można skopiować do każdej strony. Konfiguracja powinna być dostosowana do:
- wersji Apache,
- dostępnych modułów,
- konfiguracji hostingu,
- używanego CMS-a lub frameworka,
- funkcjonalności aplikacji,
- sposobu obsługi HTTPS,
- wykorzystywanego CDN lub reverse proxy,
- mechanizmów logowania i API,
- rodzaju przesyłanych przez użytkowników danych.
Część zabezpieczeń powinna znajdować się w .htaccess, inne w kodzie aplikacji, jeszcze inne w konfiguracji Apache, PHP, WAF, firewalla lub infrastruktury sieciowej.
.htaccess jako dodatkowa warstwa bezpieczeństwa
Dobrze skonfigurowany .htaccess może znacząco pomóc w ograniczeniu powierzchni potencjalnego ataku. Szczególnie przydatne jest blokowanie dostępu do wrażliwych plików, wyłączenie indeksowania katalogów, prawidłowe przekierowanie na HTTPS oraz zastosowanie odpowiednich nagłówków bezpieczeństwa.
Nie należy jednak traktować .htaccess jako kompletnego systemu ochrony strony.
Bezpieczeństwo witryny powinno opierać się na kilku warstwach: aktualnym oprogramowaniu, bezpiecznym kodzie aplikacji, właściwych uprawnieniach plików, poprawnej konfiguracji serwera, HTTPS, kopiach zapasowych, monitoringu oraz – tam, gdzie jest to uzasadnione – firewallu i WAF.
Przed wprowadzeniem zmian w .htaccess warto również wykonać kopię aktualnego pliku. Błąd składni lub zastosowanie dyrektywy niedostępnej na danym hostingu może doprowadzić do błędu 500 Internal Server Error albo utraty części funkcjonalności strony.
Dlatego każdą zmianę najlepiej wdrażać pojedynczo, sprawdzać jej działanie i dopiero po testach pozostawiać ją w środowisku produkcyjnym.
