Bir sitenin güvenlik başlıklarını beş dakikada denetleyin
Tek bir curl komutu, bir sitenin tarayıcıya hangi güvenlik kurallarını verdiğini gösteriyor. Neye bakacağınızı bilirseniz eksikleri hemen görürsünüz.
- 5 dk okuma
- 6 kaynak
Kısaca
- Güvenlik başlıkları, sunucunun tarayıcıya "bu sayfada neye izin var" dediği kurallar; curl -I ya da tarayıcının geliştirici araçlarıyla okunur.
- Rehberde en önemli yedi başlığı bu sitenin gerçek ayarları üzerinden tek tek anlatıyoruz.
Bir web sayfası açtığınızda sunucu size yalnızca sayfanın kendisini göndermez. Sayfanın önüne, tarayıcıya nasıl davranması gerektiğini söyleyen kısa notlar ekler. Bunlara HTTP başlıkları deniyor ve bir kısmı doğrudan güvenlikle ilgili: hangi scriptlerin çalışabileceği, sayfanın başka bir sitenin içine gömülüp gömülemeyeceği, bağlantının her zaman şifreli olup olmayacağı. Bu başlıkları okumak için özel bir araca gerek yok. Bu rehberde, bu sitenin kendi başlıklarını örnek alarak neye bakmanız gerektiğini anlatıyoruz.
Başlıklar her sitede aynı şekilde çalışır ve aynı yöntemle denetlenir. Ama bizim ayarlarımız olağandan sıkı, çünkü bu site hiç JavaScript kullanmıyor. Script kullanan bir sitede neyin değiştiğini ve başlıkların farklı sunuculara nasıl yazıldığını yazının sonunda bulabilirsiniz.
1. Başlıkları görün
Terminalde tek bir komut yeter:
curl -sI https://kirmiziekip.com
-I yalnızca başlıkları ister, sayfanın içeriğini indirmez. -s de ilerleme çubuğunu gizler. Karşınıza alt alta dizilmiş satırlar çıkar. Her satır Ad: değer biçimindedir. Güvenlikle ilgili olanları aşağıdaki görselde işaretledik.

Terminal kullanmıyorsanız aynı bilgiye tarayıcıdan da ulaşırsınız. Sayfada F12’ye basıp Ağ (Network) sekmesini açın, sayfayı yenileyin, listedeki ilk satıra tıklayın ve Yanıt Başlıkları (Response Headers) bölümüne bakın. İki yöntem aynı sonucu verir, ama tarayıcıdaki görünüm bir farkı da yakalar: bazı altyapılar yalnızca gerçek tarayıcılara ek bir şey gönderebilir. Bu sitede bunu bizzat yaşadık, aşağıda anlatıyoruz.
2. Her başlık neyi engelliyor?
Başlıkların her biri belirli bir saldırı türüne karşı bir kilit gibi çalışıyor. Hangisinin neye karşı olduğunu bilirseniz, eksik olanın sitenizi neye açık bıraktığını da anlarsınız.

Listede bir de “olmaması gereken” başlık var: X-XSS-Protection. Eski tarayıcılardaki bir filtreyi açıyordu. Modern tarayıcılar bu filtreyi kaldırdı, bazı durumlarda kendisi açık oluşturduğu için de artık önerilmiyor. Bir sitede hâlâ bu başlığı görüyorsanız, ayarların uzun süredir gözden geçirilmediğinin işareti olabilir.
3. En önemlisi, Content-Security-Policy
CSP, sayfanın nereden ne yükleyebileceğini tek tek sayan bir izin listesi. Bu sitenin CSP’si mümkün olan en sıkı başlangıçla açılıyor: default-src 'none', yani “hiçbir şeye izin yok”. Sonra yalnızca gerçekten gereken kapılar açılıyor. Görseller, stiller ve yazı tipleri sadece sitenin kendi adresinden yüklenebiliyor. Script için ise hiçbir kapı açılmıyor.
Bunu yapabilmemizin sebebi, siteyi kurarken baştan verdiğimiz bir karar: sayfalarda tek satır JavaScript olmayacak. Menüden açık ve koyu temaya kadar her şey HTML ve CSS ile çözüldü, tarayıcıya yalnızca hazır sayfa gidiyor. Script olmayınca CSP’de scripte izin vermek için de bir sebep kalmıyor. Bu karar bize bazı şeylerden vazgeçmeyi göze aldırdı: ziyaretçi sayacı, yorum kutusu, gömülü videolar yok. Karşılığında da sayfaya dışarıdan sokulan bir script, ne kadar zararsız görünürse görünsün, çalışamıyor.

Bu sıkılığın işe yaradığını bu hafta gördük. Cloudflare’in ziyaretçi ölçüm özelliği, biz farkında olmadan sayfalara kendi scriptini eklemeye başlamıştı. curl ile yaptığımız kontrol bunu göstermedi, çünkü Cloudflare scripti yalnızca gerçek tarayıcılara ekliyordu. Sitemize göz atan bir arkadaşımız, tarayıcı konsolunda gördüğü hatayı haber verdi. Hata, CSP’nin o scripti engellediğini söylüyordu. Yani farkında olmadığımız bir script bile sayfada çalışamamıştı. Özelliği kapattık, CSP ise işini zaten yapmıştı.

Kendi sitenizde CSP’yi kurarken 'unsafe-inline' ve 'unsafe-eval' ifadelerinden mümkün olduğunca uzak durun. Bu ikisi CSP’nin XSS’e karşı sağladığı korumanın büyük kısmını boşa çıkarır. Mevcut bir sitede birden sıkı bir CSP açmak bir şeyleri bozabilir. Önce aynı kuralı Content-Security-Policy-Report-Only başlığıyla yayınlayıp konsolda nelerin engelleneceğini görmek daha güvenli bir yol.
4. Strict-Transport-Security ile şifresiz bağlantıyı kapatın
HSTS, tarayıcıya “bu siteye bundan sonra yalnızca HTTPS ile bağlan” der. Böylece biri sizi araya girip şifresiz bağlantıya düşürmeye çalışsa bile tarayıcı buna izin vermez. Bu sitede değer şöyle:
max-age=63072000; includeSubDomains; preload

İki uyarı var. includeSubDomains bütün alt alan adlarınızı kapsar. HTTPS’i olmayan eski bir alt alan adınız varsa ona erişilemez hale gelir. preload ise tek başına bir şey yapmaz. Sitenin tarayıcılara gömülü listeye girmesi için hstspreload.org üzerinden ayrıca başvuru gerekir. Listeye girmek kolay, çıkmak ise aylar sürebilir. O yüzden bu adımı bütün alt alan adlarınızın HTTPS’e hazır olduğundan emin olduktan sonra atın.
5. Geri kalanları tek bakışta kontrol edin
Kalan başlıkların ayarı daha basit ve çoğu sitede neredeyse aynı. Aşağıdaki tablo, bu sitede kullandığımız değerleri ve aynı değerin hangi durumda değişmesi gerektiğini gösteriyor.

Sitenizi başka bir siteye gömülü göstermeniz gerekiyorsa, örneğin bir ödeme ya da harita aracı içinde, X-Frame-Options ve CSP’deki frame-ancestors değerini buna göre gevşetmeniz gerekir. Kamera ya da konum kullanan bir uygulamanız varsa Permissions-Policy içinde yalnızca o izni kendi adresinize açın.
Hızlı bir dış göz
Başlıkları elle okuduktan sonra bir de dışarıdan bakın. Mozilla’nın HTTP Observatory aracına alan adınızı yazdığınızda başlıklarınızı tarayıp bir not verir ve eksikleri listeler. O notu bir hedef değil, bir hatırlatma listesi olarak kullanın. Asıl önemli olan, her başlığın sizin sitenizde neden orada olduğunu bilmeniz.
Kendi sitenizde
Başlıkların nereye yazılacağı sitenizi hangi sunucunun yayınladığına bağlı. Mantık hep aynı: başlık adı ve değeri. Aşağıda en yaygın dört yer için X-Content-Type-Options başlığının nasıl ekleneceği var, diğerleri de aynı kalıpla yazılır.
- nginx: sunucu ayar dosyasına
add_header X-Content-Type-Options "nosniff" always; - Apache:
.htaccessya da sunucu ayarınaHeader always set X-Content-Type-Options "nosniff" - Cloudflare Pages: sitenin köküne konan
_headersdosyasına,/*satırının altınaX-Content-Type-Options: nosniff(bu site böyle yapılandırıldı) - WordPress: hosting panelindeki başlık ayarları ya da bir güvenlik eklentisi. Hangisini kullanırsanız kullanın, sonucu
curl -Iile kontrol edin. Eklentiler bazen ayarı kaydedip başlığı göndermeyebiliyor.
Asıl fark CSP’de çıkar. Sitenizde analiz aracı, reklam, sohbet kutusu ya da jQuery gibi bir kütüphane varsa, bizim default-src 'none' başlangıcımızı kopyalamak sitenizi bozar. Böyle bir sitede şu sırayla ilerlemek daha güvenli:
- Kuralı önce
Content-Security-Policy-Report-Onlybaşlığıyla yayınlayın. Bu başlık hiçbir şeyi engellemez, yalnızca engelleyeceklerini konsolda gösterir. - Konsolda hangi adreslerden script, stil ve görsel yüklendiğini not edin. Her biri için ilgili kurala yalnızca o adresi ekleyin, örneğin
script-src 'self' https://analiz.ornek.com. - Sayfanın içine gömülü scriptler varsa
'unsafe-inline'eklemek yerine onları ayrı dosyaya taşıyın ya da nonce veya hash kullanın. - Konsolda uyarı kalmayınca başlığın adını
Content-Security-Policyolarak değiştirip kuralı devreye alın.
Listeye eklediğiniz her adres, o adresin sahibine sitenizde kod çalıştırma izni demek. CSP’yi kurarken kaç tane üçüncü taraf scripte gerçekten ihtiyacınız olduğunu da sorgulamış olursunuz. Bizim kararımızın arkasında da biraz bu soru vardı.
Kaynaklar
- MDN, HTTP başlıkları başvuru kaynağıdeveloper.mozilla.org (başka siteye gider)
- MDN, Content-Security-Policydeveloper.mozilla.org (başka siteye gider)
- MDN, Strict-Transport-Securitydeveloper.mozilla.org (başka siteye gider)
- OWASP Secure Headers Projectowasp.org (başka siteye gider)
- HSTS Preload listesihstspreload.org (başka siteye gider)
- Mozilla HTTP Observatorydeveloper.mozilla.org (başka siteye gider)