Dokumentacja
Włącz HSTS
Włącz HSTS
Przekierowanie z http:// na https:// chroni odwiedzających dopiero po pierwszym żądaniu, a to pierwsze żądanie idzie bez szyfrowania. W publicznej sieci Wi-Fi ktoś może je przechwycić i zatrzymać odwiedzającego na fałszywej wersji Twojej strony pod http://. HSTS (HTTP Strict Transport Security) zamyka tę lukę: jeden nagłówek odpowiedzi każe przeglądarce przez określony czas używać dla Twojej domeny HTTPS i w ogóle nie próbować już http://.
Nagłówek nic nie kosztuje i respektuje go każda nowoczesna przeglądarka. Lista kontrolna strony oczekuje go z max-age co najmniej 180 dni.
Jak wygląda nagłówek
Strict-Transport-Security: max-age=31536000; includeSubDomains
| Część | Znaczenie |
|---|---|
max-age |
przez ile sekund przeglądarka pamięta, że ma używać HTTPS. Lista kontrolna wymaga co najmniej 15552000 (180 dni); rok to 31536000. |
includeSubDomains |
reguła obejmuje też wszystkie subdomeny: shop.example.com, mail.example.com, intranet.example.com … |
preload |
prośba o wbudowanie w przeglądarki (zobacz ostrzeżenie poniżej). Opcjonalne. |
Przeglądarki przyjmują nagłówek tylko przez HTTPS; w odpowiedziach na http:// go ignorują. Najpierw upewnij się, że przekierowanie z HTTP na HTTPS działa.
Ostrzeżenie: HSTS to obietnica, której przeglądarka będzie Cię trzymać. Dopóki trwa
max-age, przeglądarka odwiedzającego nie otworzy strony przez zwykły HTTP ani z błędem certyfikatu, a przycisku "kontynuuj mimo to" nie ma. Zanim dodaszincludeSubDomains, upewnij się, że każda subdomena ma ważny certyfikat, także stare, które działają tylko nahttp://.
Zacznij nisko, potem podnieś
- Zacznij od
max-age=300(pięć minut) i sprawdź stronę oraz jej subdomeny. - Na kilka dni podnieś do
86400(jeden dzień). - Potem ustaw
31536000(rok).
Jeśli przy krótkiej wartości coś się zepsuje, możesz usunąć nagłówek, a przeglądarki zapomną go w kilka minut. Przy roku pamiętają go przez rok.
O preload
Słowo preload i lista na hstspreload.org wbudowują Twoją domenę w Chrome, Firefox, Safari i Edge, więc nawet pierwsza wizyta używa HTTPS. Lista wymaga max-age co najmniej 31536000, includeSubDomains i preload. Usunięcie z listy trwa miesiącami i dociera tylko do odwiedzających z zaktualizowanymi przeglądarkami. Dodaj preload tylko wtedy, gdy masz pewność, że cała domena ze wszystkimi subdomenami zostanie na HTTPS na zawsze.
Sprawdź sam
Zamiast example.com wpisz swoją stronę:
curl -sI https://example.com | grep -i '^strict-transport-security'
curl -sI https://example.com/no-such-page | grep -i '^strict-transport-security'
Po naprawie: obie linie wypisują nagłówek z max-age=15552000 lub więcej. Drugie polecenie sprawdza, czy mają go też strony błędów; w przykładach dla nginx i Apache poniżej odpowiada za to always.
Jak to naprawić
Ustaw nagłówek w jednym miejscu, jak najbliżej odwiedzającego: CDN lub serwer WWW obejmuje każdą odpowiedź, także obrazy i strony z pamięci podręcznej. Wybierz to, do czego masz dostęp.
WordPress
Jeśli możesz, ustaw nagłówek w panelu hostingu lub w .htaccess (zobacz te zakładki): wtedy obejmuje też strony z pamięci podręcznej i pliki, które nigdy nie docierają do PHP.
Jeśli masz tylko dostęp do panelu WordPressa, dodaj to darmową wtyczką Code Snippets (Snippets → Add New, uruchamiaj wszędzie) albo w functions.php motywu potomnego:
// HSTS na każdej stronie, którą WordPress generuje przez HTTPS.
add_action('send_headers', function () {
if (is_ssl()) {
header('Strict-Transport-Security: max-age=31536000; includeSubDomains');
}
});
Potem wyczyść pamięć podręczną stron. Strony serwowane prosto z cache (WP Rocket, LiteSpeed Cache) mogą nadal nie mieć nagłówka; jeśli sprawdzenie curl pokaże jego brak, użyj zakładki dla serwera.
cPanel
Hosting współdzielony z cPanelem zwykle nie ma przełącznika HSTS, ale .htaccess działa. Dodaj to do .htaccess w katalogu głównym strony (File Manager, z włączonym Show Hidden Files):
<IfModule mod_headers.c>
Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains"
</IfModule>
Przeglądarki ignorują nagłówek w odpowiedziach na http://, więc tam nie szkodzi; liczy się, żeby był w każdej odpowiedzi na https://.
Plesk
- Otwórz Websites & Domains → example.com → SSL/TLS Certificates.
- Włącz HSTS i ustaw max-age na co najmniej 6 miesięcy (lepiej rok). Include subdomains zaznacz dopiero po ich sprawdzeniu, a Preload zostaw wyłączone, chyba że naprawdę tego chcesz.
Jeśli Twoja wersja Pleska nie ma tam przełącznika HSTS, dodaj nagłówek w Websites & Domains → example.com → Apache & nginx Settings, w Additional nginx directives:
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
nginx
W bloku server dla HTTPS Twojej strony (/etc/nginx/sites-available/example.com na Debianie i Ubuntu, /etc/nginx/conf.d/example.com.conf na Rocky, Alma i CentOS):
server {
listen 443 ssl;
server_name example.com;
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
}
Bez always nginx nie dodaje nagłówka do odpowiedzi z błędem. Pułapka: blok location, który ma własne add_header, nie dziedziczy żadnego nagłówka z bloku server, więc powtórz tam tę linię.
sudo nginx -t && sudo systemctl reload nginx
Apache i LiteSpeed
Z dostępem do serwera (Apache). W <VirtualHost *:443> Twojej strony (/etc/apache2/sites-available/example.com-le-ssl.conf lub podobny na Debianie i Ubuntu, /etc/httpd/conf.d/ na Rocky, Alma i CentOS):
Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains"
Wymaga mod_headers (na Debianie i Ubuntu: sudo a2enmod headers).
sudo apachectl configtest && sudo systemctl reload apache2
(Na Rocky, Alma i CentOS httpd zamiast apache2.)
Bez dostępu do serwera (hosting współdzielony, LiteSpeed). Użyj linii .htaccess z zakładki cPanel; LiteSpeed czyta je tak samo.
Cloudflare
- Otwórz domenę i przejdź do SSL/TLS → Edge Certificates.
- W HTTP Strict Transport Security (HSTS) kliknij Enable HSTS i potwierdź ostrzeżenie.
- Ustaw Max Age Header na 6 months lub 12 months. Apply HSTS policy to subdomains włącz dopiero po sprawdzeniu subdomen; Preload zostaw wyłączone, chyba że naprawdę tego chcesz.
- Save.
Cloudflare dodaje nagłówek do każdej odpowiedzi, którą serwuje. Jeśli Twój serwer też go wysyła, sprawdź curl, czy wynikiem jest jeden nagłówek z wartością, którą chcesz.
Node.js i Next.js
Next.js (własny hosting), w next.config.js:
module.exports = {
async headers() {
return [{
source: '/:path*',
headers: [
{ key: 'Strict-Transport-Security', value: 'max-age=31536000; includeSubDomains' },
],
}];
},
};
Na Vercelu własne domeny dostają nagłówek HSTS od platformy; zanim dodasz własny, sprawdź curl.
Express: pakiet helmet domyślnie wysyła Strict-Transport-Security z rocznym max-age (app.use(helmet())). Jeśli przed aplikacją stoi nginx, wystarczy ustawienie tam (zakładka nginx).
Laravel
Utwórz middleware, na przykład app/Http/Middleware/StrictTransportSecurity.php:
namespace App\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\Response;
class StrictTransportSecurity
{
public function handle(Request $request, Closure $next): Response
{
$response = $next($request);
if ($request->isSecure()) {
$response->headers->set('Strict-Transport-Security', 'max-age=31536000; includeSubDomains');
}
return $response;
}
}
Zarejestruj go w bootstrap/app.php:
->withMiddleware(function (Middleware $middleware) {
$middleware->append(\App\Http\Middleware\StrictTransportSecurity::class);
})
Za load balancerem lub proxy isSecure() jest prawdziwe tylko wtedy, gdy Laravel ufa proxy ($middleware->trustProxies(at: '*') lub adres IP Twojego proxy). Inaczej nagłówek nigdy się nie pojawi.
IIS i ASP.NET
W pliku web.config strony:
<configuration>
<system.webServer>
<httpProtocol>
<customHeaders>
<add name="Strict-Transport-Security" value="max-age=31536000; includeSubDomains" />
</customHeaders>
</httpProtocol>
</system.webServer>
</configuration>
W ASP.NET Core app.UseHsts() domyślnie wysyła tylko 30 dni, czyli mniej niż 180 wymagane przez listę kontrolną. Ustaw wiek jawnie:
builder.Services.AddHsts(options =>
{
options.MaxAge = TimeSpan.FromDays(365);
options.IncludeSubDomains = true;
});
Platformy hostowane
Na Shopify, Wix, Squarespace i Webflow nagłówki odpowiedzi ustawia platforma. Jeśli HSTS brakuje albo jest krótszy niż 180 dni, po Twojej stronie nie ma na to ustawienia; możesz zapytać wsparcie platformy albo postawić stronę za Cloudflare i ustawić go tam.
Potwierdź poprawkę
Uruchom ponownie polecenia curl z sekcji Sprawdź sam, potem otwórz cel w PulseKeeper i kliknij Sprawdź teraz na zakładce Lista kontrolna. Pozycja pokazuje znalezione max-age w dniach.