secaudit.eu
Zabezpieczenia

WordPress HTTPS: mixed content i przekierowania

WordPress HTTPS bez błędów: darmowy certyfikat, bezpieczna zamiana adresów w WP-CLI, jedno przekierowanie 301, pętle za proxy, mixed content i kontrola ważności.

Autorka: , AngelForce OÜ 7 min czytania

Także po: English Deutsch Français Español Italiano Português Türkçe

Większość problemów z HTTPS w WordPressie wynika z niedokończonej migracji, a nie z braku certyfikatu. Certyfikat jest zainstalowany, na stronie głównej widać kłódkę. Ale wpisy na blogu mają ikonę ostrzeżenia, w treściach nadal tkwią stare linki http://, a odwiedzający, który wpisze example.com, przechodzi dwa lub trzy przekierowania, zanim trafi na właściwą stronę. Ten poradnik porządkuje tę sytuację w bezpiecznej kolejności.

WordPress HTTPS: certyfikat to dopiero pierwszy krok

Najpierw pomiar. Te dwa polecenia pokazują, przez co przechodzi przeglądarka odwiedzającego:

curl -sI http://example.com
curl -sIL http://example.com | grep -iE '^(HTTP|location)'

Pierwsze polecenie pokazuje kod statusu i nagłówek Location pierwszej odpowiedzi. Drugie podąża za każdym przekierowaniem. Jeśli przed końcowym 200 widać więcej niż jedno 301, mamy łańcuch przekierowań. Następnie warto otworzyć stronę w przeglądarce, nacisnąć F12 i zajrzeć do konsoli. Tam pojawiają się ostrzeżenia o mixed content.

Dobrze też wiedzieć, co HTTPS robi, a czego nie. Szyfruje ruch między przeglądarką a serwerem i chroni go przed zmianą w trakcie przesyłania. To jeden ze środków wymienionych w art. 32 ust. 1 lit. a RODO, czyli szyfrowanie, i dotyczy haseł logowania, formularzy kontaktowych oraz danych z kasy. HTTPS nic natomiast nie mówi o tym, czy sama witryna jest bezpieczna. Strona z ważnym certyfikatem może nadal działać na podatnej wtyczce, zawierać złośliwe oprogramowanie albo mieć konto administratora zabezpieczone hasłem password123. Jak szyfrowanie wpisuje się w pozostałe środki bezpieczeństwa, opisuje artykuł Art. 32 RODO w WordPressie.

Diagram: trzy adresy wejściowe HTTP i www przekierowują jednym przekierowaniem 301 na jeden kanoniczny adres HTTPS
Każdy stary wariant adresu powinien trafiać na kanoniczny adres HTTPS jednym skokiem

Darmowy certyfikat od hostingodawcy lub przez ACME

Większość paneli hostingowych w UE oferuje darmowy certyfikat Let's Encrypt pod jednym przełącznikiem, zwykle w sekcji „SSL/TLS" lub „Bezpieczeństwo". Po jego włączeniu trzeba sprawdzić, czy certyfikat obejmuje zarówno example.com, jak i www.example.com. Certyfikat wystawiony tylko na jedną nazwę powoduje błędy w przeglądarce przy drugiej, nawet jeśli ta druga tylko przekierowuje.

Na własnym serwerze potrzebny jest klient ACME. Najpopularniejszy jest Certbot, który konfiguruje też automatyczne odnawianie:

sudo certbot --nginx -d example.com -d www.example.com
sudo certbot renew --dry-run

Przy Apache zamiast --nginx należy użyć --apache. Próba --dry-run sprawdza, czy odnowienie rzeczywiście zadziała. Jeśli zawodzi teraz, zawiedzie także przy najbliższym prawdziwym odnowieniu.

Za kłódkę nie trzeba płacić: certyfikat z weryfikacją domeny jest darmowy. Płatne certyfikaty mają sens przy umowach wsparcia lub szczególnych wymaganiach co do weryfikacji. Pod względem szyfrowania darmowy certyfikat jest równie mocny.

Kopia zapasowa, a potem zmiana adresu WordPressa i adresu witryny

Przed jakąkolwiek zmianą należy wykonać kopię zapasową bazy danych. Kolejne kroki przepisują tysiące wierszy, a kopia to przycisk „cofnij". Jak robić kopie, na których można polegać, opisuje artykuł Kopie zapasowe WordPressa, które da się przywrócić. W WP-CLI wystarczy jedna linia:

wp db export before-https.sql

Następnie w Ustawienia > Ogólne trzeba zmienić Adres WordPressa (URL) i Adres witryny (URL) z http:// na https://. Jeśli WordPress jest zainstalowany w podkatalogu, ścieżkę należy zachować. To samo można zrobić z wiersza poleceń:

wp option update home 'https://example.com'
wp option update siteurl 'https://example.com'

Jeśli oba pola są wyszarzone, w wp-config.php zdefiniowano WP_HOME i WP_SITEURL. Wartości trzeba wtedy zmienić tam, bo ustawienia w panelu ich nie nadpiszą.

Gdy po zmianie nie można się zalogować, np. dlatego że certyfikat jeszcze nie działa, należy tymczasowo zdefiniować w wp-config.php WP_HOME i WP_SITEURL ze starym adresem http:// (albo przywrócić je, jeśli już tam są), lub wykonać oba polecenia wp option update ze starymi wartościami. Najpierw trzeba naprawić certyfikat, potem spróbować jeszcze raz.

Wpisy, menu, widżety i opcje motywu zawierają jeszcze setki linków http://example.com. Nie należy poprawiać ich surowym zapytaniem SQL REPLACE. WordPress i wiele wtyczek zapisuje ustawienia jako serializowane dane PHP, które przechowują długość każdego ciągu znaków, na przykład s:22:"http://example.com/img". Dodanie litery „s" wydłuża ciąg o jeden znak. Zapisana długość przestaje się zgadzać, PHP nie potrafi odczytać wartości, a widżety, układy kreatora stron lub ustawienia motywu po cichu znikają.

[wp search-replace](https://developer.wordpress.org/cli/commands/search-replace/) deserializuje dane, zamienia tekst i serializuje je ponownie z poprawnymi długościami. Zawsze najpierw należy uruchomić próbę:

wp search-replace 'http://example.com' 'https://example.com' --all-tables --skip-columns=guid --dry-run

Trzeba przejrzeć liczby zmian w poszczególnych tabelach. Jeśli wyglądają rozsądnie, uruchamia się to samo polecenie bez --dry-run. Kilka uwag:

  • --skip-columns=guid pomija identyfikatory GUID wpisów. To identyfikatory, nie linki, i zgodnie z konwencją się ich nie zmienia.
  • --all-tables obejmuje każdą tabelę w bazie. Jeśli baza jest współdzielona z inną witryną lub aplikacją, lepiej użyć --all-tables-with-prefix.
  • Jeśli kanoniczny host to wersja bez www, trzeba wykonać drugą zamianę z http://www.example.com na https://example.com.
  • Niektóre kreatory stron zapisują JSON z ukośnikami poprzedzonymi znakiem ucieczki (http:\/\/example.com), których zwykłe wyszukiwanie nie znajdzie. Warto uruchomić próbę również dla tej postaci albo użyć własnego narzędzia kreatora do zamiany adresów.

Potem trzeba wyczyścić wszystkie pamięci podręczne: wp cache flush, wtyczkę cache stron, cache serwera i CDN. Jeśli kreator stron to umożliwia, należy też wygenerować ponownie jego pliki CSS. Bez dostępu SSH to samo zadanie wykona wtyczka do wyszukiwania i zamiany obsługująca dane serializowane, np. Better Search Replace. Po zakończeniu pracy trzeba ją usunąć.

Jedno przekierowanie 301 na kanoniczny host HTTPS

Należy wybrać jeden kanoniczny adres, z www lub bez, i konsekwentnie go się trzymać. Każdy inny wariant powinien trafiać bezpośrednio na ten adres jednym przekierowaniem 301. Łańcuch typu http → https → www → docelowy spowalnia każdą pierwszą wizytę, marnuje budżet indeksowania wyszukiwarek i utrudnia znalezienie błędów.

Apache, wpisane w .htaccess powyżej bloku # BEGIN WordPress:

RewriteEngine On
RewriteCond %{HTTPS} off [OR]
RewriteCond %{HTTP_HOST} ^www\.example\.com$ [NC]
RewriteRule ^ https://example.com%{REQUEST_URI} [L,R=301]

nginx:

server {
    listen 80;
    listen [::]:80;
    server_name example.com www.example.com;
    return 301 https://example.com$request_uri;
}

server {
    listen 443 ssl;
    listen [::]:443 ssl;
    server_name www.example.com;
    ssl_certificate     /etc/letsencrypt/live/example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
    return 301 https://example.com$request_uri;
}

Przekierowanie powinno być skonfigurowane w jednym miejscu. Jeśli przekierowują jednocześnie wtyczka, .htaccess i CDN, powstają łańcuchy lub pętle. Trzeba wybrać serwer albo CDN, a pozostałe przekierowania usunąć.

Pętle przekierowań za CDN lub reverse proxy

Klasyczna pętla to tryb SSL „Flexible" w Cloudflare. Przeglądarka łączy się z Cloudflare przez HTTPS, ale Cloudflare z serwerem już zwykłym HTTP. Serwer widzi HTTP, przekierowuje na HTTPS i cykl się powtarza. Rozwiązanie: zainstalować certyfikat na serwerze i w ustawieniach SSL/TLS w Cloudflare wybrać tryb Full (strict). Ruch do serwera jest wtedy szyfrowany, a certyfikat serwera jest weryfikowany.

Inne proxy i load balancery przekazują oryginalny schemat w nagłówku X-Forwarded-Proto. WordPress domyślnie go nie odczytuje. Poniższy kod należy wstawić w wp-config.php nad linią „stop editing":

if ( isset( $_SERVER['HTTP_X_FORWARDED_PROTO'] ) && $_SERVER['HTTP_X_FORWARDED_PROTO'] === 'https' ) {
    $_SERVER['HTTPS'] = 'on';
}

FORCE_SSL_ADMIN i strona logowania

define( 'FORCE_SSL_ADMIN', true );

Ta stała sprawia, że WordPress udostępnia stronę logowania i panel administracyjny wyłącznie przez HTTPS. Hasła i ciasteczka administratora nigdy nie są wysyłane bez szyfrowania, nawet jeśli ktoś otworzy starą zakładkę z adresem http://. To siatka bezpieczeństwa, a nie sposób na przekierowanie. Dla stron publicznych nic nie zmienia. Inne ustawienia wp-config.php opisuje artykuł Utwardzanie wp-config.php: 10 ustawień do sprawdzenia.

Pozostały mixed content: szukanie w narzędziach deweloperskich

Mixed content oznacza, że strona HTTPS ładuje zasób przez HTTP. Przeglądarki blokują niezabezpieczone skrypty i ramki, a przy obrazach ostrzegają lub podmieniają protokół, dlatego znika kłódka. Należy otworzyć DevTools na dotkniętej stronie. Konsola wypisuje każde niezabezpieczone żądanie wraz z adresem URL. W przeglądarkach opartych na Chromium wpisanie scheme:http w filtrze karty Network pokazuje je wszystkie naraz.

Po poprawnej zamianie adresów pozostałe przyczyny leżą zwykle poza bazą danych. Typowe źródła to adresy wpisane na stałe w plikach motywu, widżety Custom HTML, własny CSS (background: url(http://...)), pliki CSS kreatora stron i stare osadzenia zewnętrznych usług. Aby znaleźć je w motywie:

grep -rn "http://" wp-content/themes/your-theme/
wp db search 'http://example.com'

Problem trzeba naprawić u źródła. Wtyczki przepisujące adresy przy każdym ładowaniu strony ukrywają problem, zamiast go usuwać, i przestają działać po dezaktywacji. Dyrektywa CSP upgrade-insecure-requests może posłużyć jako tymczasowy pomost na czas porządków. Opisuje ją artykuł Nagłówki bezpieczeństwa WordPressa.

Warto sprawdzić więcej niż stronę główną. Trzeba przetestować kasę, formularz kontaktowy, stronę logowania, wpis na blogu, archiwum kategorii i każdą stronę docelową zbudowaną na innym szablonie.

Monitorowanie ważności certyfikatu, a potem HSTS

Automatyczne odnawianie może zawieść bez niczyjej wiedzy. Typowe przyczyny to zmiana DNS, przejście na nowy CDN albo reguła zapory lub przekierowania blokująca /.well-known/acme-challenge/. Należy skonfigurować zewnętrzny monitoring, który sprawdza certyfikat i ostrzega co najmniej dwa tygodnie przed wygaśnięciem. Wiele usług monitorujących dostępność ma taką funkcję. Datę ważności można też odczytać samodzielnie:

echo | openssl s_client -connect example.com:443 -servername example.com 2>/dev/null | openssl x509 -noout -enddate

HSTS (RFC 6797) wprowadza się na końcu. Nakazuje przeglądarkom używać wyłącznie HTTPS, więc wadliwy certyfikat staje się dla odwiedzających twardym błędem, a przy includeSubDomains dotyczy to także każdej zapomnianej subdomeny działającej tylko po HTTP. Włączać go należy dopiero wtedy, gdy działają wszystkie subdomeny i przekierowania, zaczynając od krótkiego max-age. Wartości i ostrzeżenie dotyczące preload opisuje artykuł Nagłówki bezpieczeństwa WordPressa.

Wtyczka audytowa z secaudit.eu sprawdza ustawienia utwardzania i konfiguracji, a także integralność plików i nieaktualne wtyczki. Po migracji daje to zapis stanu witryny, który można zachować na potrzeby dokumentacji. → secaudit.eu

Następny krok: wykonać test skoków curl -sIL dla wszystkich czterech wariantów (http, http://www, https://www, https). Potem otworzyć pięć najważniejszych stron z włączoną konsolą DevTools. Migracja jest zakończona, gdy każdy wariant daje co najwyżej jedno 301, kanoniczny adres HTTPS odpowiada bezpośrednio kodem 200, a w konsoli nie ma komunikatów o mixed content.

FAQ

Czy darmowy certyfikat wystarczy dla sklepu internetowego?

Tak. Darmowy certyfikat z weryfikacją domeny szyfruje ruch równie mocno jak płatny. Bezpieczeństwo sklepu zależy od wtyczek, aktualizacji, logowania i konfiguracji płatności, a nie od ceny certyfikatu.

Dlaczego kłódka znika tylko na niektórych stronach?

Te strony ładują co najmniej jeden zasób przez HTTP. Zwykle jest to obraz, skrypt lub osadzenie z widżetu, szablonu albo sekcji kreatora stron, których inne strony nie używają. Konsola DevTools na takiej stronie pokazuje dokładny adres URL.

Czy HTTPS sprawia, że moja strona jest zgodna z RODO?

Nie. HTTPS to jeden środek techniczny z art. 32, czyli szyfrowanie w trakcie przesyłania. RODO oczekuje też zabezpieczenia samych systemów, przywracania danych po incydentach, regularnego testowania środków i dokumentowania tego wszystkiego.

Ten artykuł ma charakter ogólnej informacji i nie stanowi porady prawnej.

Sprawdź swoją stronę

Security Audit & Compliance to wtyczka WordPress od secaudit.eu: wyszukuje złośliwe oprogramowanie, ukryty spam, zmienione pliki rdzenia i podatny kod oraz przypisuje wyniki do art. 32 RODO, art. 21 NIS2 i OWASP Top 10.

Zobacz, co sprawdza wtyczka
Melike Görel

Melike Görel pisze poradniki secaudit.eu o bezpieczeństwie WordPressa i zgodności z przepisami UE dla AngelForce OÜ — firmy programistycznej z Tallinna, która stoi za secaudit.eu.

Przygotowano z pomocą AI i sprawdzono przed publikacją. Ten artykuł ma charakter ogólnoinformacyjny i nie stanowi porady prawnej.