Certyfikat SSL zwykle przypomina o sobie tylko wtedy, gdy przestaje działać. Klient dzwoni, że przeglądarka pokazuje czerwony ekran z ostrzeżeniem, sklep traci zamówienia, a w konsoli przeglądarki pojawiają się dziesiątki komunikatów o mixed content. W tym wpisie zebrałem błędy związane z certyfikatami i HTTPS, które najczęściej naprawiam, razem z tym, jak szybko ustalić przyczynę i jak zapobiec ich powrotowi.
Od czego zaczynam diagnozę
Komunikat w przeglądarce mówi, w którą stronę szukać, ale nie zawsze pokazuje pełny obraz. Dlatego zawsze sprawdzam certyfikat bezpośrednio z poziomu terminala:
openssl s_client -connect twojadomena.pl:443 -servername twojadomena.pl -showcerts
curl -vI https://twojadomena.pl/
Pierwsze polecenie pokazuje, jaki certyfikat zwraca serwer, dla jakich domen został wystawiony, do kiedy jest ważny i czy serwer wysyła pełny łańcuch certyfikatów. Drugie pokazuje cały przebieg połączenia razem z przekierowaniami. Jeśli nie mam dostępu do terminala, korzystam z publicznych testów SSL, które sprawdzają to samo i dodatkowo oceniają konfigurację serwera.
Najczęstsze błędy w przeglądarce i ich przyczyny
- Certyfikat wygasł (w Chrome
NET::ERR_CERT_DATE_INVALID). Najczęściej przestało działać automatyczne odnawianie, np. po zmianie hostingu, przeniesieniu DNS albo wyłączeniu zadania cron. Rzadziej winny jest zły zegar na komputerze użytkownika, co łatwo rozpoznać, bo problem dotyczy wtedy tylko jednej osoby. - Certyfikat nie pasuje do domeny (
NET::ERR_CERT_COMMON_NAME_INVALID). Certyfikat obejmujetwojadomena.pl, a użytkownik wchodzi nawww.twojadomena.pllub na subdomenę, której nie ma na liście. Rozwiązaniem jest certyfikat obejmujący wszystkie używane nazwy albo certyfikat typu wildcard dla subdomen. - Niezaufany wystawca (
NET::ERR_CERT_AUTHORITY_INVALID, w FirefoksieSEC_ERROR_UNKNOWN_ISSUER). Albo na serwerze jest certyfikat samopodpisany, np. pozostałość po instalacji, albo serwer nie wysyła certyfikatów pośrednich. Ten drugi przypadek jest podstępny, bo strona działa w jednej przeglądarce, a w innej, w aplikacji mobilnej lub w integracji API już nie. - Błąd protokołu (
ERR_SSL_PROTOCOL_ERROR,ERR_SSL_VERSION_OR_CIPHER_MISMATCH). Serwer oferuje przestarzałe wersje TLS lub nie ma certyfikatu przypisanego do danej domeny. Na serwerach z wieloma stronami zdarza się, że nowa domena trafia do konfiguracji bez certyfikatu i serwer odpowiada certyfikatem innej strony albo nie odpowiada wcale. - Zbyt wiele przekierowań (
ERR_TOO_MANY_REDIRECTS). Typowy scenariusz to wymuszenie HTTPS na serwerze połączone z proxy lub CDN, które łączy się z serwerem przez HTTP. Serwer widzi „niezabezpieczone” żądanie i przekierowuje je w kółko. Rozwiązaniem jest zwykle poprawne odczytanie nagłówkaX-Forwarded-Proto, które przerywa pętlę przekierowań.
Przy CDN i proxy zwracam też uwagę na tryb szyfrowania. Tryb, w którym przeglądarka łączy się z CDN przez HTTPS, ale CDN z serwerem już przez HTTP, daje kłódkę w przeglądarce, ale ruch między CDN a serwerem pozostaje nieszyfrowany i często kończy się wspomnianą pętlą. Ustawiam pełne szyfrowanie z weryfikacją certyfikatu również na serwerze źródłowym.
Odnawianie i problemy po stronie DNS
Certyfikaty mają coraz krótszy okres ważności. Certyfikaty Let's Encrypt są ważne 90 dni, a maksymalny okres ważności płatnych certyfikatów jest stopniowo skracany przez branżowe wymagania wobec wystawców. W praktyce oznacza to, że ręczne odnawianie przestaje mieć sens. Wszędzie, gdzie mogę, ustawiam automatyczne odnawianie i osobne monitorowanie daty wygaśnięcia, bo nie każdy wystawca wysyła już przypomnienia e-mailem.
Gdy automatyczne odnawianie zawodzi, przyczyna często leży w DNS:
- domena wskazuje już na inny serwer, więc weryfikacja trafia w złe miejsce,
- rekord CAA nie pozwala danemu wystawcy wystawić certyfikatu,
- przy certyfikacie wildcard brakuje uprawnień do automatycznego dodania rekordu
_acme-challenge.
Każdy z tych przypadków rozwiązuje się poprawną konfiguracją rekordów DNS, a nie ponowną instalacją certyfikatu.
Mixed content, czyli kłódka z zastrzeżeniem
Mixed content pojawia się, gdy strona działa przez HTTPS, ale ładuje część zasobów przez HTTP. Przeglądarki traktują to dwojako. Skrypty, arkusze stylów i ramki ładowane przez HTTP są blokowane, przez co strona może stracić wygląd albo działające formularze. Obrazy, dźwięk i wideo przeglądarka próbuje pobrać przez HTTPS, a jeśli to się nie uda, nie wyświetla ich.
Źródła problemu prawie zawsze są te same:
- Pełne adresy z
http://zapisane w bazie danych, np. w treściach wpisów, ustawieniach motywu i konfiguracji wtyczek. Tak dzieje się po przejściu strony z HTTP na HTTPS bez zmiany zapisanych adresów. - Adresy wpisane na sztywno w szablonie, np. do czcionek, skryptów czy logo.
- Zewnętrzne zasoby bez HTTPS, np. stare widgety, liczniki czy obrazy z innych serwisów.
Konsola narzędzi deweloperskich pokazuje problem na jednej podstronie, ale do sprawdzenia całego serwisu najczęściej używam Screaming Frog SEO Spider. Po crawlu wersji HTTPS zakładka Security pokazuje strony z mixed content, linki prowadzące do adresów HTTP i formularze wysyłające dane bez szyfrowania. Eksport Bulk Export → Security → Mixed Content daje gotową listę: na której podstronie i jaki zasób jest ładowany przez HTTP. Przy setkach podstron to jedyny rozsądny sposób, żeby niczego nie pominąć.
W WordPressie adresy w bazie zamieniam narzędziem WP-CLI, zawsze najpierw w trybie testowym i po wykonaniu kopii zapasowej:
wp search-replace 'http://twojadomena.pl' 'https://twojadomena.pl' --all-tables --dry-run
Nagłówek Content-Security-Policy: upgrade-insecure-requests każe przeglądarce automatycznie zamieniać żądania HTTP na HTTPS.
Traktuję go jako zabezpieczenie na czas porządków, a nie zamiennik poprawienia adresów, bo nie pomoże przy zasobach, które w ogóle nie są
dostępne przez HTTPS.
Co sprawdzam po naprawie
- Wszystkie wersje adresu, czyli
http://,https://, z www i bez, kończą się jednym przekierowaniem 301 na docelową wersję HTTPS. Reguły ustawiam na serwerze, np. w pliku .htaccess, a nie we wtyczkach. - Ponowny crawl w Screaming Frogu nie pokazuje mixed content ani linków wewnętrznych do adresów HTTP, a raport łańcuchów przekierowań jest pusty. Dodatkowo sprawdzam konsolę przeglądarki na kilku typach podstron, bo crawler nie zawsze wykona skrypty tak jak przeglądarka.
- Linki kanoniczne, linki wewnętrzne i mapa strony XML wskazują adresy z HTTPS, żeby wyszukiwarka nie musiała przechodzić przez przekierowania.
- Data wygaśnięcia jest monitorowana, a automatyczne odnawianie przetestowane, np. poleceniem w trybie testowym udostępnianym przez klienta ACME.
Dopiero gdy wszystko działa stabilnie przez jakiś czas, włączam nagłówek HSTS, który każe przeglądarkom łączyć się wyłącznie przez HTTPS. Włączony zbyt wcześnie utrwala problemy, bo użytkownik nie obejdzie błędu certyfikatu nawet ręcznie, a zmiana działa u niego do końca okresu podanego w nagłówku.