Reklam gösteren bir blogda beş güvenlik başlığı bugün ekleyebileceğin, risksiz tek satırlık ayarlar: Strict-Transport-Security, X-Content-Type-Options, X-Frame-Options (ya da CSP frame-ancestors), Referrer-Policy ve kısa bir Permissions-Policy. Altıncısı, Content-Security-Policy, reklamlarını durdurabilecek olan. Google AdSense için tek bir CSP türünü destekliyor: nonce tabanlı "katı" politika. Çoğu başlık üretecinin verdiği alan adı listeli politikalar tam da desteklenmeyen tür. Her betiğe nonce eklemeye hazır değilsen ya betikleri hiç kısıtlamayan bir CSP kullan ya da hiç kullanma.
Bu başlıkların hiçbiri AdSense ya da Google Arama şartı değil. Okurlarını ve siteni korurlar; bir tarayıcı eksik olduklarını işaretliyorsa ucuz bir sıkılaştırmayı gösteriyordur, ret sebebini değil.
Hangi başlıklar önemli, hangisi reklamı bozabilir?

Strict-Transport-Security (HSTS) nedir?
Tarayıcıya alan adın için bundan sonra sadece HTTPS kullanmasını söyler. MDN'nin tanımıyla tarayıcıya, sunucuya yalnızca HTTPS ile erişilmesi gerektiğini ("should only be accessed using HTTPS") bildirir; ziyaretçinin sertifika hatalarını geçip devam etmesini de engeller (MDN, Strict-Transport-Security).
Strict-Transport-Security: max-age=31536000
Bu bir yıl. Her sayfanın ve her alt alan adının HTTPS'te çalıştığından emin değilsen kısa başla (bir gün, max-age=86400), siteyi kontrol et, sonra yükselt. HSTS'nin riski reklam değil, sensin: tarayıcı bu başlığı bir kez gördükten sonra bozuk bir sertifika "yine de devam et" bağlantısı olmayan kesin bir hataya dönüşür, max-age dolana kadar. Açmadan önce sertifika yenilemenin sağlam çalıştığından emin ol.
includeSubDomains'i sadece her alt alan adında HTTPS varsa ekle; unuttukların da dahil (mail., eski., magaza.). preload'u hstspreload.org şartlarını okumadan ekleme: en az 31536000 max-age, includeSubDomains ve bütün alt alan adlarında HTTPS. MDN, preload listesinden çıkmanın yavaş olduğunu da belirtiyor.
X-Content-Type-Options: nosniff
X-Content-Type-Options: nosniff
MDN'ye göre istek hedefi stil dosyasıysa ve MIME türü text/css değilse, ya da betikse ve MIME türü bir JavaScript türü değilse isteği engeller (MDN, X-Content-Type-Options). Doğru ayarlanmış bir sunucuda görünür hiçbir şeyi değiştirmez. Biri betiğe benzeyen bir dosya yüklediğinde işe yarar.
X-Frame-Options ve frame-ancestors (clickjacking koruması)
X-Frame-Options: SAMEORIGIN
Content-Security-Policy: frame-ancestors 'self'
Bunlar başka sitelerin senin sayfalarını bir çerçeve içinde gösterip gösteremeyeceğini belirler. Kendi sayfandaki reklam iframe'lerini etkilemez, yani AdSense için güvenli. MDN modern karşılık olarak frame-ancestors'ı gösteriyor ve <meta> etiketiyle verilen X-Frame-Options'ın "has no effect", yani hiçbir etkisi olmadığını söylüyor; sadece HTTP başlığı olarak çalışır (MDN, X-Frame-Options). İkisini birlikte göndermek sorun değil. Başka sitelerin bilerek yerleştirdiği bir widget'ın varsa 'self' yerine o siteleri frame-ancestors'a yaz.
Referrer-Policy
Referrer-Policy: strict-origin-when-cross-origin
Bu zaten tarayıcıların varsayılanı: MDN "the default policy if no policy is specified" diyor (MDN, Referrer-Policy). Link verdiğin siteler tam yolu ve sorgu dizesini değil https://ornek.com/ kısmını görür. Açıkça yazmak çoğunlukla bir eklentinin ya da eski bir ayarın unsafe-url vermesine karşı önlem. Blogda no-referrer'a gitme: link verdiğin siteler ve başka alan adlarındaki kendi analitiğin trafiğin senden geldiğini göremez.
Permissions-Policy
Permissions-Policy: camera=(), microphone=(), geolocation=()
Sayfalarının hiç kullanmadığı tarayıcı özelliklerini, hem sayfan hem içindeki çerçeveler için kapatır (MDN, Permissions-Policy). Emin olduğun özelliklerle sınırlı tut. Başlık üreteçlerinden kopyalanan uzun politikalar fullscreen ya da autoplay gibi gömülü videoların kullandığı özellikleri de kapatır; bir öğleden sonranı YouTube videosunun neden tam ekran olmadığını bulmaya harcarsın.
Content-Security-Policy ve AdSense: Google neyi destekliyor?
Google'ın tam bu konu için bir yardım sayfası var: AdSense reklam kodunu bir İçerik Güvenliği Politikası (İGP) ile entegre etme. Önemli satırlar:
- CSP isteğe bağlı: makale "Yayıncıların İGP'yi kullanmasının zorunlu olmadığını" baştan söylüyor.
- "AdSense reklam kodunun kullandığı alanlar zaman içinde değiştiğinden yalnızca katı İGP'yi (2. seçenek) destekliyoruz." 2. seçenek nonce yaklaşımı; 1. seçenek, yani izin verilen alan adları listesi desteklenmeyen.
- "Önemli: Sitenizin İGP'sini, belgelendirilmiş yönergelerimize uygun olacak şekilde güncellemeniz gerekli. Bunu yapmamanız durumunda sitenizde reklam yayını kesintiye uğrayabilir."
- Örnek politikadan sonra: "Kullanım alanınıza uygunsa daha az kısıtlayıcı bir politika seçebilirsiniz. Daha kısıtlayıcı politikalar, sitenizin işlevinde önceden haber verilmeksizin sorun yaşanmasına neden olabilir."
Google'ın belgelediği politika:
Content-Security-Policy:
object-src 'none';
script-src 'nonce-{random}' 'unsafe-inline' 'unsafe-eval' 'strict-dynamic' https: http:;
base-uri 'none';
report-uri https://your-report-collector.example.com/
{random} her sayfa yüklemesinde yeni üretilen rastgele bir değer ve sayfadaki her <script> etiketinin bunu taşıması gerekiyor; iki AdSense etiketi de dahil (adsbygoogle.js yükleyicisi ve satır içi (adsbygoogle = window.adsbygoogle || []).push({});). 'strict-dynamic' sonra AdSense'in yüklediği betiklerin, alan adlarını listelemene gerek kalmadan çalışmasına izin verir. 'unsafe-inline' ve https: http: kısımları, 'strict-dynamic''i destekleyen tarayıcıların yoksaydığı yedekler. Google Publisher Tag'in CSP sayfasında da kural aynı: "we only support strict CSP".

Alışılmış CSP neden reklamları bozuyor?
Çoğu başlık üretecinden çıkan CSP script-src 'self' https://pagead2.googlesyndication.com ... artı bir frame-src listesi gibi görünür. Test ettiğin gün çalışır. Sonra reklam kodu listende olmayan bir alan adından betik ya da çerçeve yükler, tarayıcı engeller, reklam alanı boş kalır. AdSense sana sebebini söylemez; daha boş reklam alanları ve Refused to load mesajlarıyla dolu bir konsol görürsün. Google'ın uyardığı "önceden haber verilmeksizin" sorun bu.
Blog için üç makul seçenek
CSP yok. Google zorunlu olmadığını söylüyor. Betik enjeksiyonuna karşı korumadan vazgeçersin ve bir tarayıcı bunu eksik olarak listeler.
Betiklere dokunmayan bir CSP. Betiklerin, çerçevelerin ve görsellerin nereden yükleneceğini kısıtlamaz, yani reklam kodunun yoluna çıkmaz, ama yine de işe yarar:
Content-Security-Policy: frame-ancestors 'self'; object-src 'none'; base-uri 'self'; upgrade-insecure-requestsupgrade-insecure-requests, HTTPS'e geçtikten sonra kalanhttp://görselleri de sessizce düzeltir (onları düzgünce bulmak için HTTPS sonrası karışık içerik rehberine bak).Nonce'lu, Google'ın katı CSP'si. Enjekte edilen betiklere karşı gerçek koruma. HTML üretimini sen kontrol ediyorsan pratik: özel bir tema, Next.js, nonce'u şablona basabilen bir statik site üreteci ya da betik etiketlerini yeniden yazan bir sunucu. Kendi satır içi betiklerini basan yirmi eklentili bir WordPress'te her birine nonce eklemek tek bir başlık değil, başlı başına bir proje.
Önce Report-Only ile test et
Hangisini seçersen seç, Google'ın tavsiyesi önce Content-Security-Policy-Report-Only ile başlamak: "Başlık, ihlalleri bildirir ancak bu ihlallerin sayfada bulunmasına izin vermeye devam eder." Yayına al, Chrome'da reklamlı birkaç sayfa aç, Geliştirici Araçları > Console'da [Report Only] mesajlarını izle. Normal trafikle bir hafta boyunca mesaj yoksa (ya da report-uri ayarladıysan rapor toplayıcında), başlığın adını Content-Security-Policy yap.
Kopyala-yapıştır ayarlar
Aşağıdaki örneklerde CSP için 2. seçenek var. Google'ın katı politikasını sadece nonce işini bitirdiysen koy.
nginx
443'ü dinleyen server { } bloğunun içine:
add_header Strict-Transport-Security "max-age=31536000" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-Frame-Options "SAMEORIGIN" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header Permissions-Policy "camera=(), microphone=(), geolocation=()" always;
add_header Content-Security-Policy "frame-ancestors 'self'; object-src 'none'; base-uri 'self'; upgrade-insecure-requests" always;
always, başlıkların hata sayfalarında da gönderilmesini sağlar. Tuzak şu: nginx'in headers modülü belgesine göre add_header yönergeleri, "if and only if there are no add_header directives defined on the current level", yani sadece o seviyede hiç add_header yoksa üst seviyeden miras alınır. Kendi Cache-Control başlığını ekleyen bir location bloğu, o adresler için yukarıdaki altı başlığın hepsini sessizce düşürür. Onları orada tekrarla, her bloğa include ettiğin bir dosyaya koy ya da nginx 1.29.3 ve sonrasında add_header_inherit merge; kullan. sudo nginx -t ile dene, sonra sudo systemctl reload nginx.
Apache ve .htaccess (cPanel'li hostinglerin çoğu)
<IfModule mod_headers.c>
Header always set Strict-Transport-Security "max-age=31536000"
Header always set X-Content-Type-Options "nosniff"
Header always set X-Frame-Options "SAMEORIGIN"
Header always set Referrer-Policy "strict-origin-when-cross-origin"
Header always set Permissions-Policy "camera=(), microphone=(), geolocation=()"
Header always set Content-Security-Policy "frame-ancestors 'self'; object-src 'none'; base-uri 'self'; upgrade-insecure-requests"
</IfModule>
Sitenin kök klasöründeki .htaccess dosyasının en üstüne, WordPress bloğunun üzerine koy. HSTS'nin düz HTTP cevaplarında da gönderilmesi zarar vermez; MDN'ye göre güvensiz HTTP üzerinden gelen başlık yoksayılır. Türkiye'deki paylaşımlı hostinglerde sık görülen LiteSpeed de .htaccess'teki aynı Header satırlarını kabul ediyor. Değişiklikten sonra site 500 hatası verirse ya mod_headers yok ya da bir satırda yazım hatası var: bloğu kaldır ve hostinge sor.
Cloudflare
HSTS için hazır ayarı kullan: SSL/TLS > Edge Certificates > HTTP Strict Transport Security (HSTS). Önce Cloudflare'in HSTS uyarısını oku: açtıktan sonra kayıtları Proxied'dan DNS only'ye çevirme, Cloudflare'i duraklatma, sertifikanın süresini doldurma; yoksa site Max Age süresi boyunca ziyaretçilere kapanır ("your website becomes inaccessible to visitors for the duration of the Max Age Header").
Geri kalanlar için bir Response Header Transform Rule (Cloudflare belgeleri): Rules > Overview > Create rule > Response Header Transform Rule, kuralı tüm gelen isteklere uygula, her başlık için Set static seç, adını ve değerini gir. Bir kural en fazla 30 başlığı değiştirebiliyor. "Set" sunucunun zaten gönderdiği başlığın üzerine yazar, tekrarı önler; "Add" yazmaz. www yönlendirmesini de Cloudflare'de yapıyorsan o kuralların yeri Cloudflare www yönlendirme rehberinde.
Sunucuya erişimi olmayan WordPress
Bazı güvenlik eklentileri ve bazı hostinglerin panelleri bu başlıkları ekleyebiliyor. Tek bir yer seç. Aynı başlığın iki kaynağı (eklenti ve .htaccess, ya da sunucu ve Cloudflare "Add") tekrar eden başlık üretir; iki farklı CSP başlığının ikisi de uygulanır, yani daha kısıtlayıcı birleşim kazanır.
Gerçekte ne gönderdiğini kontrol et
curl -sI https://ornek.com/ | grep -iE "strict-transport|x-content-type|x-frame|referrer-policy|permissions-policy|content-security"
Sadece ana sayfayı değil, bir yazı adresini ve bir görsel ya da CSS dosyasını da kontrol et. nginx miras tuzağı ve önbellek kuralları orada ortaya çıkar. Sonra reklamlı bir sayfa açıp konsolda engellenen istek var mı bak.
Başlıkların düzeltmeyeceği şeyler
Başlıklar bazı saldırıları zorlaştırır. Zaten ele geçirilmiş bir siteyi temizlemez: veritabanına ya da bir tema dosyasına eklenmiş betikler çalışmaya devam eder, çünkü onları senin sunucun sunuyor. O noktadaysan hacklenen site, Güvenli Tarama ve AdSense rehberinden başla. Yönlendirme döngüsüne de başlıklar çare olmaz; o konu yönlendirme zinciri ve döngüsü.
Başlıklarını tek seferde kontrol et
Ücretsiz güvenlik başlıkları kontrolü bir sayfayı çeker ve yukarıdaki her başlık için ne bulduğunu, neyin eksik olduğunu listeler.
Sık sorulan sorular
AdSense güvenlik başlıklarını şart koşuyor mu?
Hayır. Google'ın CSP makalesi bile "Yayıncıların İGP'yi kullanmasının zorunlu olmadığını" söylüyor. Başlıklar okurları korur; onay kontrollerinin parçası değil.
X-Frame-Options DENY reklamlarımın görünmesini engeller mi?
Hayır. Başka sitelerin senin sayfalarını çerçeveleyip çerçeveleyemeyeceğini belirler, senin sayfanın çerçeve içerip içeremeyeceğini değil. SAMEORIGIN daha pratik, çünkü kendi araçlarının bazıları (önizleme, sayfa oluşturucular) sayfalarını çerçeveleyebilir.
CSP'm bir Google alan adı için "Refused to load the script" gösteriyor. Ne yapmalıyım?
Politikan bir izin listesi; Google bunu AdSense için desteklemiyor. Report-Only'ye geç, sonra ya Google'ın belgelediği katı nonce politikasına geç ya da politikadan script-src ve frame-src'yi çıkar.
HSTS max-age ne kadar olmalı?
Her şey HTTPS'te çalışınca bir yıl (31536000) yaygın. Emin değilsen bir gün ya da bir haftayla başla, çünkü tarayıcı en son gördüğü değeri süresi bitene kadar uygular.
Bu başlıkları meta etiketiyle verebilir miyim?
Sadece CSP'yi, o da kısmen. HSTS, X-Frame-Options ve frame-ancestors <meta> ile çalışmaz; HTTP yanıt başlığı olmaları gerekir.
Eskimiş ya da yanlış bir şey mi gördün? Bize yaz, düzeltelim.
Bu rehberi İngilizce oku →Kendi sitende kontrol et. Ücretsiz, kayıt yok.
Bunun için ücretsiz araçlar
Ücretsiz tarama
Kendi siteni kontrol et
Ücretsiz tarama ilk 50 sayfayı okur; puanını ve bulduğu tüm sorunları gösterir.