İçeriğe geç
Sunucu ve .htaccess

WordPress'te https Geçişi Sonrası Mixed Content

https geçişinden sonra WordPress mixed content uyarılarını temizleyin: veritabanında kalan http:// adreslerini bulun, güvenle değiştirin ve .htaccess ile https'i zorlayın.

Yayınlandı

Sertifikanız kurulu, site https üzerinden açılıyor ama asma kilit hâlâ görünmemekte direniyor. İşte bu mixed content: sayfanın kendisi https üzerinden geldi, ama içindeki bir şey — bir görsel, bir stil dosyası, bir betik — hâlâ düz http:// üzerinden isteniyor. Bu yazı, o adresleri bulmayı, serileştirilmiş veriyi bozmadan değiştirmeyi, siteurl ve home değerlerini düzeltmeyi ve sorunun geri gelemeyeceği şekilde sunucuda https’i zorlamayı adım adım anlatıyor.

Mixed content aslında nedir

Sertifika kurmak, bağlantının nasıl şifrelendiğini değiştirir. Sayfalarınızın ne istediğini değiştirmez. Geçişten önce bir yazıya, bir bileşene ya da bir tema ayarına yazılmış her http://yoursite.com/wp-content/uploads/logo.png hâlâ veritabanında duruyor ve tarayıcı da onu itaatkâr biçimde güvensiz bir bağlantı üzerinden istiyor.

Tarayıcılar iki kategoriye farklı davranır ve bu ayrım, işin ne kadar acil olduğuna karar verirken önemlidir:

  • Aktif mixed content — betikler, stil dosyaları, iframe’ler, XHR. Doğrudan engellenir. Bir sitenin https geçişinden sonra hiçbir yerde hata mesajı olmadan bozuk görünmesinin sebebi budur: bir stil dosyası sessizce reddedilmiştir.
  • Pasif mixed content — görseller, ses, video. Genellikle yine yüklenir ama asma kilit düşürülür ve bazı tarayıcılar “güvenli değil” göstergesi çıkarır.

İkisi de düzeltmeye değer. Yalnızca ilki bir şeyleri bozar.

Adım 1: hâlâ ne güvensiz, onu bulun

Tarayıcıdan başlayın. Sayfayı açın, geliştirici araçlarını açın ve konsolu okuyun. Engellenen ya da düşürülen her istek orada tam URL’siyle adlandırılır. Bu size neyin güvensiz olduğunu söyler; nerede saklandığını söylemez.

Onun için doğrudan veritabanına bakın. Dışa aktarın ve dökümde arayın:

wp db export dump.sql
grep -o "http://example\.com[^\"']*" dump.sql | sort -u | head -50

WP-CLI yoksa aynı dosyayı mysqldump da üretir:

mysqldump -u USER -p DBNAME > dump.sql

Dönen benzersiz adresleri okuyun. Uploads yolları yazı içeriğine ve metaya işaret eder. Tema varlık yolları genellikle seçeneklere işaret eder. Tanımadığınız bir alan adı taşıyan her şey harici bir gömülü içeriktir ve farklı bir çözüm ister (aşağıda ele alınıyor).

Adım 2: önce siteurl ve home değerlerini düzeltin

siteurl ve home, WordPress’in ürettiği neredeyse her dâhilî URL’yi kurarken kullandığı iki seçenektir. Bunlardan biri hâlâ http:// diyorsa, veritabanının geri kalanı ne kadar temiz olursa olsun WordPress güvensiz adresler yaymaya devam eder.

Kontrol edin:

wp option get siteurl
wp option get home

Ya da sql ile:

SELECT option_name, option_value
FROM wp_options
WHERE option_name IN ('siteurl', 'home');

Bu ikisi serileştirilmiş dizi değil, düz metin değerleridir; dolayısıyla burada doğrudan bir sql güncellemesi gerçekten güvenlidir:

UPDATE wp_options
SET option_value = REPLACE(option_value, 'http://example.com', 'https://example.com')
WHERE option_name IN ('siteurl', 'home');

Buna vakit ayırmadan önce bir tuzak. wp-config.php dosyası WP_HOME ya da WP_SITEURL tanımlıyorsa, bu sabitler veritabanını tamamen geçersiz kılar ve güncellemeniz hiçbir şey yapmamış gibi görünür:

define( 'WP_HOME', 'https://example.com' );
define( 'WP_SITEURL', 'https://example.com' );

Onları orada güncelleyin ya da kaldırıp yönetimi veritabanına bırakın. Bunu ilk sırada kontrol edin — pek çok “değiştirdim ama hiçbir şey olmadı” vakasını bu açıklar.

Adım 3: değiştirme işlemi serileştirmeye duyarlı olmalı

Veritabanındaki geri kalan her şey, asıl riskin bulunduğu yerdir; üstelik bu, çoğu kişinin beklediği risk değildir. Tehlike, değiştirme işleminin bazı adresleri atlaması değildir. Tehlike, metin düzeyinde başarılı olup çevresindeki veriyi yok etmesidir.

WordPress dizileri ve nesneleri php ile serileştirilmiş metin olarak saklar ve bu biçim, içerdiği her dizenin bayt uzunluğunu kaydeder:

a:1:{s:4:"logo";s:38:"http://example.com/img/logo.png";}

Ham bir sql REPLACE ile http:// değerini https:// yaptığınızda metin bir bayt uzar ama bildirilen uzunluk eski değerinde kalır. php uzunluğu okur, o kadar bayt ileri yürür, sonlandırıcıyı beklediği yerde bulamaz ve dizinin tamamını seri durumundan çıkarmayı reddeder. WordPress de temaya ya da eklentiye, sanki ayar hiç kaydedilmemiş gibi davranan bir değer verir.

Belirti bir hata mesajı değildir. Belirti; bileşenlerin kaybolması, özelleştirici ayarlarının sıfırlanması ve sayfa oluşturucu yerleşimlerinin bomboş görünmesidir — üstelik yönetim panelinde bir şeyin ters gittiğine dair hiçbir iz olmadan. Yedek olmadan bundan dönmek gerçekten zahmetlidir, o yüzden bir yedek alın:

wp db export backup-before-https-replace.sql

Ardından, veriyi seri durumundan çıkaran, çözülmüş yapının içinde değiştirmeyi yapan ve uzunlukları düzelterek yeniden serileştiren bir araç kullanın. Önce kuru çalıştırma:

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

Raporu okuyun. Tanımadığınız bir tablo binlerce isabet gösteriyorsa, uygulamadan önce durup bakın. Sonra gerçekten çalıştırın:

wp search-replace 'http://example.com' 'https://example.com' --all-tables --skip-columns=guid --report-changed-only

--skip-columns=guid önemlidir: guid, canlı bir URL değil, besleme okuyucuları için kalıcı bir tanımlayıcıdır; onu yeniden yazmak abonelerin tüm arşivinizi yeni yazı sanmasına yol açabilir. Herhangi bir şey çalıştırmadan önce hangi sütunların düz sql için güvenli, hangilerinin serileştirmeye duyarlı işlem gerektirdiğini görmek istiyorsanız, sorguları WordPress arama ve değiştirme sql aracıyla oluşturun.

Komut satırını kullanamıyorsanız, serileştirilmiş veriyi işlediğini açıkça belirten bir taşıma eklentisi aynı çözme işini yönetim ekranı üzerinden yapar. Bir araç bunu söylemiyorsa, yapmadığını varsayın.

Adım 4: https’i sunucuda zorlayın

Veritabanını temizlemek, sayfalarınızın güvensiz kaynak istemesini durdurur. Bir ziyaretçinin en baştan http:// üzerinden gelmesini durdurmaz. Bu, sunucu düzeyinde bir yönlendirmedir ve Apache üzerinde .htaccess dosyasına aittir:

# BEGIN Force HTTPS
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{HTTPS} !=on
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]
</IfModule>
# END Force HTTPS

Konumla ilgili iki nokta. Bunu # BEGIN WordPress işaretçilerinin üstüne koyun — aralarındaki her şey, biri kalıcı bağlantıları her kaydettiğinde atılır. Ve bu yalnızca mod_rewrite etkinse ve sanal ana makine geçersiz kılmalara izin veriyorsa (AllowOverride All ya da en azından FileInfo) çalışır. nginx üzerinde .htaccess tamamen yok sayılır ve bunun yerine bir server bloğuna girmesi gerekir.

Bu işi bir RedirectMatch göremez. Yalnızca istek yoluyla eşleşir ve mevcut isteğin zaten güvenli olup olmadığını sınamanın hiçbir yolu yoktur; dolayısıyla https isteklerini kendilerine geri yönlendirir. Yukarıdaki koşullu RewriteRule doğru araçtır.

Yönlendirme döngüsü ve neden olduğu

Kuralı ekler eklemez site sonsuza kadar yönlendirmeye başlıyorsa, TLS yukarıda bir yerde sonlanıyor demektir — bir yük dengeleyici, bir ters vekil ya da bir CDN — ve oradan Apache’ye düz http iletiliyordur. Apache güvensiz bir istek görür, https’e yönlendirir, vekil yine http iletir ve iş döner durur.

Bunun yerine iletilen başlığı sınayın:

RewriteCond %{HTTP:X-Forwarded-Proto} !https
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]

Bu kurulumda WordPress’in kendisinde de aynı kör nokta vardır — is_ssl() fonksiyonu $_SERVER['HTTPS'] değerini okur, vekil bunu hiç ayarlamaz, dolayısıyla yönetim adresleri http:// olarak çıkar. Şunu wp-config.php dosyasına, “düzenlemeyi bırakın” satırının üstüne ekleyin:

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

Riski açıkça söylemekte fayda var: X-Forwarded-Proto istemcinin gönderdiği bir başlıktır. Ona güvenmek yalnızca, sizin denetimizdeki bir vekil onu her seferinde üzerine yazıyorsa doğrudur. İnternetten doğrudan erişilebilen bir sunucuda taklit edilebilir.

Veritabanı değiştirmesinin çözemeyecekleri

  • Dosyalara gömülü adresler. functions.php içine, bir alt tema şablonuna ya da satır içi bir varlık yoluna yazılmış hiçbir şey veritabanında değildir. Tema dizinini ayrıca grep’leyin.
  • Kaçış karakterli JSON. Bazı oluşturucular adresleri https:\/\/example.com biçiminde saklar. Normal biçim için yapılan bir arama bunları tamamen ıskalar, dolayısıyla kaçışlı dize için ikinci bir geçiş gerekebilir.
  • Harici kaynaklar. Yalnızca http üzerinden sunulan üçüncü taraf bir betik ya da gömülü içerik sizin tarafınızdan düzeltilemez. Bir https sürümünü bulun ya da onu kaldırın.
  • Önbellekler. Sayfa önbelleği, nesne önbelleği ve CDN kopyaları doğru bir değiştirmeden sonra bile eski işaretlemeyi sunmayı sürdürür. Değiştirme başarısız oldu sonucuna varmadan önce üçünü de temizleyin.

Atlamaya değer bir şey: upgrade-insecure-requests Content Security Policy başlığı, güvensiz istekleri tarayıcıda yeniden yazarak uyarıları susturur. Belirtiyi tedavi eder ve yanlış adresleri veritabanınızda bırakır; bir sonraki dışa aktarma, taşıma ya da besleme onları olduğu gibi taşır. Önce veriyi düzeltin, isterseniz sonra bunu bir emniyet ağı olarak kullanın.

Hâlâ takıldınız mı?

Her adımdan sonra siteurl ve home değerlerini yeniden kontrol edin — eklentiler ve taşıma araçları bazen arkanızdan bunları yeniden yazar. Konsol hâlâ dökümde bulamadığınız güvensiz bir adres bildiriyorsa, sayfa kaynağını görüntüleyip orada arayın: üretilen işaretlemede görünüp veritabanında görünmüyorsa, php tarafında oluşturuluyor demektir ve düzeltilmesi gereken şey onu üreten tema ya da eklentidir.

FAQ

Sorular

SSL sertifikası kurduğum hâlde WordPress sitem neden hâlâ mixed content uyarısı gösteriyor?

Sertifika yalnızca bağlantının nasıl şifrelendiğini değiştirir, sayfalarınızın ne istediğini değil. Eski http:// adresleri veritabanında, yazı içeriğinde, bileşen seçeneklerinde ve tema ayarlarında öylece durur. Tarayıcı sayfayı https üzerinden yükler, bir görselin ya da betiğin düz http üzerinden istendiğini görür ve aksi hâlde güvenli olan bir sayfada mixed content bildirir.

WordPress veritabanımda hâlâ duran http:// adreslerini nasıl bulurum?

Bir sayfayı tarayıcıda açıp geliştirici konsolunu okuyun; güvensiz her istek orada URL'siyle adlandırılır. Ardından veritabanını dışa aktarın ve dökümde alan adınızı http ön ekiyle arayın. Tablo başına isabet saymak, sorunun yazı içeriğinde mi, wp_options tablosunda mı, yoksa hiç beklemediğiniz eklenti tablolarında mı olduğunu söyler.

Mixed content sorununu düz bir sql arama-değiştirme ile çözebilir miyim?

Yalnızca siteurl ve home gibi skaler değerler için. WordPress'in serileştirilmiş dizi olarak sakladığı her şey — ki bu çoğu seçenek ve meta değerini kapsar — içindeki her dizenin bayt uzunluğunu kaydeder. Ham bir değiştirme metni değiştirir ama eski uzunluğu olduğu gibi bırakır; değer artık seri durumundan çıkarılamaz ve ayar sessizce varsayılanına döner.

WordPress'te https'i zorlayan htaccess kuralı nedir?

https değişkenini sınayan bir koşulla korunan bir RewriteRule; kalıcı bağlantıları kaydetmenin onu silmemesi için BEGIN WordPress işaretçilerinin üstüne konur. Bir vekil sunucu ya da CDN arkasında https değişkeni güvenli isteklerde bile off okunur, dolayısıyla bunun yerine X-Forwarded-Proto başlığını sınayın; yoksa kural sonsuza kadar yönlendirir.

https'i zorladıktan sonra sitem neden yönlendirme döngüsüne girdi?

TLS neredeyse kesinlikle bir vekil sunucuda ya da CDN'de sonlanıyor ve oradan Apache'ye düz http iletiliyordur. Yeniden yazma güvensiz bir istek görür, https'e yönlendirir, vekil yine http iletir ve döngü tekrarlanır. Koşulu X-Forwarded-Proto başlığına çevirin ve https sunucu değişkenini wp-config.php içinde ayarlayın.

Mixed content sayfanın tamamını mı bozar, yoksa yalnızca asma kilidi mi?

Kaynağa bağlı. Tarayıcılar betik, stil dosyası ve iframe gibi aktif mixed content öğelerini doğrudan engeller; bu da hiçbir görünür açıklama olmadan yerleşimi ya da işlevselliği bozabilir. Görsel ve video gibi pasif mixed content genellikle yine yüklenir ama asma kilit düşürülür ve ziyaretçiler güvenli değil göstergesi görebilir. İkisi de düzeltmeye değer.