Güvenlik başlıkları ne yapar, ne yapmaz
Güvenlik başlığı, tarayıcıya sayfanıza varsayılandan daha sıkı davranmasını söyleyen bir yanıt başlığıdır: yalnızca HTTPS kullan, dosya türü tahmin etme, başka sitelerin çerçevelerine girme, Referer ile daha az bilgi paylaş, kamerayı kapalı tut ve yalnızca onaylanan script'leri çalıştır.
Bunlar derinlemesine savunmadır. Hiçbiri açığı olan bir uygulamayı düzeltmez: SQL injection ya da bozuk bir giriş akışı, kusursuz bir başlık setiyle de aynı ölçüde bozuktur. Yaptıkları, tarayıcının sınırlayabildiği hataların zararını küçültmektir: cross-site scripting, clickjacking, protokol düşürme ve referrer üzerinden sızan veri. Bunu her ziyaretçi için, birkaç yüz bayt karşılığında yaparlar.
Ayrıca yalnızca tarayıcılarda çalışırlar. Bir API istemcisi, bir tarayıcı botu ya da saldırganın script'i hepsini yok sayar; bu yüzden ilk savunma hattı bir WAF ve uygulama kodunun kendisi olarak kalır.
Strict-Transport-Security (HSTS)
Strict-Transport-Security, tarayıcıya hostname'iniz için HTTPS kullanmasını ve bunu max-age saniye boyunca hatırlamasını söyler; böylece elle yazılmış bir http:// adresi bile cihazdan düz metin olarak çıkmaz. Sitedeki her URL zaten HTTPS üzerinden çalışıyorsa, en az emekle en büyük etkiyi bu başlık verir.
Güvenli başlangıç max-age=31536000'dir: bir yıl, yalnızca bu hostname. includeSubDomains ve preload daha geniş bir alana uzanır ve geri alınması zordur. HSTS rehberi, her birinin sizi neye bağladığını, başlığın nasıl doğrulanacağını ve nasıl geri alınacağını anlatıyor.
CDN.com.tr'de HSTS, Yayınlama Kuralları'nda hesap bazlı bir preset'tir; onun için başlık satırı yazmanız gerekmez. HTTPS yanıtlarında tam olarak max-age=31536000 gönderir, düz HTTP'de hiçbir şey göndermez.
X-Content-Type-Options: nosniff
Tarayıcılar eskiden Content-Type başlığı yanlış göründüğünde dosyanın türünü içeriğinden tahmin ederdi. MIME sniffing denen bu tahmin, script'e benzeyen yüklenmiş bir dosyanın script olarak çalışmasına yol açıyordu. X-Content-Type-Options: nosniff tahmini kapatır: stil dosyası text/css olarak, script de bir JavaScript türüyle gelmelidir, yoksa tarayıcı reddeder.
Tek değeri nosniff'tir ve başlık HTML olsun olmasın her yanıtta güvenlidir. Önce tek bir şeyi kontrol edin: sunucunuz dosyaları doğru etiketliyor mu? text/plain olarak sunulan bir script, başlık eklendiği anda yüklenmez; istediğiniz davranış da tam olarak budur.
X-Frame-Options ve frame-ancestors: sayfanızı kim çerçeveleyebilir
Clickjacking, sayfanızı başka bir sitede görünmez bir çerçeveye yükler ve oradaki bir düğmeyi sizinkiyle hizalar; ziyaretçi "Oynat"a bastığını sanırken "Hesabı sil"e basar. Savunma, tarayıcıya sayfanızı kimin çerçeveye koyabileceğini söylemektir.
X-Frame-Options'ın iki işe yarar değeri vardır: kimse için DENY, kendi origin'inizdeki sayfalar için SAMEORIGIN. Eski ALLOW-FROM değerini güncel tarayıcılar yok sayar. Bir site listesine izin vermek için CSP direktifi frame-ancestors kullanılır, örneğin frame-ancestors 'self' https://partner.example.
Bir yanıt ikisini birden taşıdığında, frame-ancestors'ı anlayan tarayıcılar onu izler ve X-Frame-Options'ı yok sayar. İkisini birlikte göndermek yaygın ve zararsızdır, eski başlık eski tarayıcıları kapsar; yeter ki ikisi aynı şeyi söylesin. Bir sınır: frame-ancestors yalnızca HTTP başlığı olarak çalışır, <meta> etiketinde asla.
Referrer-Policy: her tıklamayla ne gider
Ziyaretçi bir bağlantıya tıkladığında ya da sayfanız başka bir siteden görsel, script veya font yüklediğinde, tarayıcı sayfanızın adresini Referer başlığında gönderebilir. Tam URL'ler sanıldığından fazlasını sızdırır: arama terimleri, sipariş numaraları, şifre sıfırlama bağlantısındaki token.
Mantıklı varsayılan strict-origin-when-cross-origin'dir: kendi sitenizin içinde tam URL, başka sitelere yalnızca origin (https://example.com/), HTTPS bir sayfadan düz HTTP'ye giderken hiçbir şey. Sayfa bir şey söylemediğinde güncel tarayıcılar zaten bunu ya da daha sıkısını uygular; açıkça ayarlamak, tarayıcıların varsayılanı ne olursa olsun davranışı sabitler. Hassas URL'ler taşıyan bir uygulamada no-referrer hiçbir şey göndermez; bedeli, diğer sitelerin analitiğinde yönlendirme verisinin kaybolmasıdır.
Permissions-Policy: kullanmadığınızı kapatın
Permissions-Policy, sayfanızın ve içindeki çerçevelerin hangi güçlü tarayıcı özelliklerini kullanabileceğine karar verir: kamera, mikrofon, konum, ödeme, USB ve diğerleri. Boş liste () bir özelliği herkes için kapatır, (self) yalnızca kendi origin'inize izin verir; gerçekten ihtiyaç duyan gömülü içeriklerin origin'lerini de adıyla yazabilirsiniz.
Bir kurumsal site ya da mağaza bunların neredeyse hiçbirine ihtiyaç duymaz; camera=(), microphone=(), geolocation=() makul bir başlangıçtır, gömdüklerinizi gözden geçirdikçe ekleyin. Kazanç sınırlamadır: ele geçirilmiş bir üçüncü taraf script ya da reklam çerçevesi ziyaretçiden kamerasını isteyemez. Başlığı Chromium tabanlı tarayıcılar uygular; onu diğer kontrollerin yerine değil, üstüne eklenen bir sıkılaştırma olarak görün.
Content-Security-Policy: güçlü, ama plan ister
Content Security Policy, tarayıcıya script'lerin, stillerin, görsellerin, fontların, bağlantıların ve çerçevelerin nereden gelebileceğini ve satır içi kodun çalışıp çalışamayacağını söyler. İyi kurulduğunda cross-site scripting hatalarının çoğunu "saldırgan kullanıcılarınızın oturumunda kod çalıştırıyor" olmaktan çıkarıp "tarayıcı bir script'i engelledi ve raporladı" hâline getirir.
Sayfa bozan başlık da odur. Satır içi <script> blokları, onclick öznitelikleri, başka script'ler enjekte eden bir etiket yöneticisi, kimsenin hatırlamadığı bir analitik adresi: her birine izin vermek ya da yeniden yazmak gerekir. Bu yüzden iki adımda yayın. Önce politikayı Content-Security-Policy-Report-Only olarak gönderin: hiçbir şey engellenmez, her ihlal konsolda ve bir report-to ya da report-uri adresi tanımladıysanız raporlarınızda görünür. Raporların gösterdiğini düzeltin ya da izin verin, sonra aynı politikayı Content-Security-Policy olarak gönderin.
Aşağıdaki politika sıkı ama okunabilir. Kaldıramadığınız satır içi script'ler için her yanıtta rastgele bir nonce üretin ve onu hem politikaya hem <script> etiketine yazın. 'strict-dynamic' ile güvenilen bir script'in yüklediği script'ler de güvenilir sayılır; böylece etiket yöneticileri dokundukları her alan adını listelemeden çalışabilir. Script'ler için 'unsafe-inline''dan kaçının: politikanın var oluş nedeni olan korumanın çoğunu kapatır.
Sıkı bir başlangıç politikası, report-only modunda
Content-Security-Policy-Report-Only: default-src 'self'; script-src 'self'; style-src 'self'; img-src 'self' data:; font-src 'self'; connect-src 'self'; object-src 'none'; base-uri 'self'; form-action 'self'; frame-ancestors 'self'; upgrade-insecure-requests
Kopyalanabilir güvenli değerler
Çoğu site bu setle başlayıp yalnızca CSP kaynaklarını ve izin listesini uyarlayabilir. Sıra önemli değildir; önemli olan her başlığın bir kez görünmesidir.
X-XSS-Protection bilerek yok. Güncel tarayıcıların kaldırdığı bir filtreyi yönetiyordu ve eski tarayıcılarda filtrenin kendisi kötüye kullanılabiliyordu; hiç göndermeyin ya da X-XSS-Protection: 0 gönderin. Expect-CT de benzer bir nedenle artık geçersizdir, o da çıkabilir.
Bir HTML sayfası için yanıt başlıkları
Strict-Transport-Security: max-age=31536000
X-Content-Type-Options: nosniff
X-Frame-Options: SAMEORIGIN
Referrer-Policy: strict-origin-when-cross-origin
Permissions-Policy: camera=(), microphone=(), geolocation=()
Content-Security-Policy-Report-Only: default-src 'self'; object-src 'none'; base-uri 'self'; frame-ancestors 'self'
CDN.com.tr'de bu başlıkları ayarlamak
HSTS'nin yukarıda anlatılan kendi preset'i var. Diğer tek değerli başlıklar bir dağıtım kuralına yazılır: Yayınlama Kuralları'nda sayfalarınızı sunan kuralı (genellikle /) düzenleyin ve Özel başlıklar alanına her satıra bir tane olacak şekilde Başlık-Adı değer yazın (sekmeli kural sayfasında: Başlıklar → Yanıta başlık ekle). Boşluk içeren değer çift tırnak içine yazılır.
Tam bir Content-Security-Policy oraya yazılamaz. Direktifleri noktalı virgülle ayrılır; panel ve edge başlık satırında ; kabul etmez, çünkü noktalı virgül edge'in kendi yapılandırma direktifini bitirir. Tek bir direktifte noktalı virgül olmadığı için yalnız frame-ancestors edge'de çalışır. Tam politikanın yeri origin sunucunuzdur: web sunucusu ya da uygulama, ki orada istek başına bir nonce da taşıyabilir. HTML'de <meta http-equiv="Content-Security-Policy"> etiketi de çalışır; yalnız frame-ancestors, report-uri ve sandbox'ı tarayıcılar meta etiketinde yok sayar.
Kuralla eklenen başlıklar, kural yayınlandığı anda başarılı ve yönlendirme yanıtlarına (2xx ve 3xx), önbellekten verilenler dahil, uygulanır; hata sayfalarında da görünmesi gereken bir başlığın yeri origin'dir. Origin sunucunuzun gönderdiği başlıklar önbellekteki her kopyayla birlikte saklanır; onları değiştirdikten sonra etkilenen sayfalar için CDN önbelleğini temizleyin. Origin sunucunuz bu başlıklardan birini zaten gönderiyorsa, aynı kuralda Başlıkları Gizle listesinden seçin; yoksa ziyaretçiye iki kopya gider.
Sayfalarınızı sunan kuralda Özel başlıklar
X-Content-Type-Options nosniff
X-Frame-Options SAMEORIGIN
Referrer-Policy strict-origin-when-cross-origin
Permissions-Policy "camera=(), microphone=(), geolocation=()"
Content-Security-Policy "frame-ancestors 'self'"
Nasıl test edilir
curl ile başlayın; sunucunun tam olarak ne gönderdiğini gösterir. Bir sayfaya, bir statik dosyaya ve var olmayan bir sayfaya bakın: tek bir yerde ayarlanan başlıklar çoğu zaman diğer ikisini kaçırır.
Sonra tarayıcının geliştirici araçlarını açın. Network sekmesi başlıkları tarayıcının aldığı hâliyle gösterir; Console her CSP ihlalini ve reddedilen her çerçeveyi, buna yol açan direktifle birlikte raporlar. Mozilla HTTP Observatory gibi çevrimiçi tarayıcılar tüm seti puanlar ve her bulguyu açıklar; ikinci bir görüş olarak işe yarar.
Son olarak varlığı değil davranışı test edin: sayfayı başka bir origin'deki bir iframe'e gömün ve tarayıcının reddettiğini görün; zorunlu kılmadan önce report-only politikayla Console'u birkaç gün izleyin.
curl -sI https://www.example.com/ | grep -i -E \
'strict-transport|x-content-type|x-frame|referrer-policy|permissions-policy|content-security'
# a static file and a missing page, too
curl -sI https://www.example.com/assets/app.css | grep -i x-content-type
curl -sI https://www.example.com/no-such-page | grep -i -E 'x-frame|content-security'
Güvenlik başlıkları hakkında sık sorulanlar
Her web sitesi hangi güvenlik başlıklarını göndermeli?
Sitenin tamamı HTTPS üzerinden çalışıyorsa HSTS; X-Content-Type-Options: nosniff; X-Frame-Options: SAMEORIGIN ya da CSP frame-ancestors; Referrer-Policy: strict-origin-when-cross-origin; ve kullanmadığınız özellikleri kapatan bir Permissions-Policy. Content-Security-Policy'yi report-only denemesinden sonra ekleyin.
X-Frame-Options artık kullanılmıyor mu?
Kaldırılmadı, yerini daha iyisi aldı. CSP frame-ancestors aynı işi daha fazla kontrolle yapar ve onu destekleyen tarayıcılar ikisi birlikte geldiğinde X-Frame-Options'ı yok sayar. Yanında SAMEORIGIN ya da DENY göndermek eski tarayıcıları korumaya devam eder; ölen yalnızca ALLOW-FROM'dur.
X-XSS-Protection göndermeye devam etmeli miyim?
Hayır. Yönettiği filtre güncel tarayıcılardan kaldırıldı, eski tarayıcılarda ise sayfaya karşı kötüye kullanılabiliyordu. Hiç göndermeyin ya da 0 gönderin; onun yerine Content-Security-Policy'ye güvenin.
Content-Security-Policy'yi CDN.com.tr üzerinden ayarlayabilir miyim?
Tek bir direktif, evet: örneğin dağıtım kuralının Özel başlıklar alanında frame-ancestors 'self'. Tam bir politika direktifler arasında noktalı virgül ister ve edge kuralları bunu kabul etmez; onu web sunucunuzda ya da uygulamanızda ayarlayın, ya da frame-ancestors, report-uri ve sandbox dışındaki her şey için bir meta etiketiyle.
Güvenlik başlıkları SEO'yu ya da hızı etkiler mi?
Ölçülebilir biçimde hayır. Birkaç yüz bayt eklerler; HTTP/2 ve HTTP/3 tekrarlanan başlıkları sıkıştırır. Belgelenmiş bir sıralama faktörü değildirler. Tek SEO riski, kendi script'lerinizi engelleyip sayfanın görüntülenmesini bozan bir CSP'dir; report-only adımı bunu yakalar.
Görsellerin, CSS ve JavaScript dosyalarının da bu başlıklara ihtiyacı var mı?
nosniff ve HSTS her yanıtta işe yarar. Geri kalanlar, yani CSP, çerçeve koruması, Referrer-Policy ve Permissions-Policy belgeler üzerinde çalışır; önemli olan HTML sayfalarıdır. Hepsine göndermenin zararı yoktur.