Ofiste bir öğle arasıydı, kahvemi alıp oturdum. Müşterilerden biri, “Sitede her şey yolundaydı, bir ayar yaptım, şimdi bazı sayfalar yüklenmiyor” dedi. İlk bakışta performans meselesi sandım ama bir şey gözüme takıldı: karışık içerik uyarıları, bazı sayfalar embed çalıştırırken beyaz ekran, arada bir tarayıcıdan sert uyarılar. Tanıdık geldi mi? Genelde bu karmaşanın ortasında dört küçük cümle saklanır: HSTS, CSP, X-Frame-Options ve X-Content-Type-Options. Hepsi de birer HTTP güvenlik başlığı. Ufak header’lar, büyük etkiler.
Bu yazıda sana bir geliştirici arkadaşına anlatır gibi yaklaşacağım. “Ne işe yarar, nerede ters köşe yapar, nasıl güvenle uygularsın” hepsini örneklerle konuşalım. Mesela HSTS ile ilk açılışta minik bir değerle başlamak neden akıllıca, CSP’yi neden hemen sıkı hale getirmemek gerekir, X-Frame-Options ile hangi sayfanın iframe içinde kalması gerektiğini nasıl belirleriz gibi soruların yanıtlarını birlikte arayacağız. Arada gerçek hayattan senaryolarla destekleyeceğim, küçük kod parçacıkları da ekleyeceğim. Hazırsan başlayalım.
İçindekiler
- 1 Kafadaki Sis Dağılsın: Güvenlik Başlığı Dediğin Nedir?
- 2 HSTS: “Hep HTTPS Kullan” Demenin İnce Yolu
- 3 CSP: Tarayıcıya “Şu Kaynaktan Script Al, Diğerini Çalıştırma” Demek
- 4 X-Frame-Options ve Clickjacking: Penceremi Kimse Taşımayacak
- 5 X-Content-Type-Options: “Türünü Tahmin Etme, Ben Söylerim”
- 6 Sahaya Sürmek: Nginx, Apache, .htaccess, cPanel ve Cloudflare İle Adım Adım
- 7 Doğrulama, Test ve Kademeli Yayın: Kırmadan Sertleştir
- 8 Kapanış: Küçük Başlıklar, Büyük Etki
Kafadaki Sis Dağılsın: Güvenlik Başlığı Dediğin Nedir?
Tarayıcıyı bir misafir gibi düşün. Siteni açtığında ona bazı kurallar söylersin: “Şu kapıdan gir, şu odaya bak, şunlara izin var, şunlara yok.” İşte HTTP güvenlik başlıkları tam bu kuralları yazdığın küçük notlar. Sunucudan tarayıcıya giden yanıtın tepesine iliştiriliyorlar ve tarayıcı bu notlara göre davranıyor.
Mesela, “Sadece güvenli bağlantı kullan” dersen HSTS devreye giriyor. “Şu alanlar dışında script çalıştırma” dediğinde CSP konuşuyor. “Ben başka bir sitenin içine gömülmek istemiyorum” diyeceğin zaman X-Frame-Options’ı kullanıyorsun. “İçeriğin türünü tahmin etmeye çalışma” dediğinde ise X-Content-Type-Options sözü alıyor. Dört başlık, dört net kural. Ne kadar net olursan, tarayıcı o kadar iyi anlıyor.
İşin güzel tarafı, hepsi küçük ayarlar. Fakat etkisi büyük. Yanlış uygulandığında ise beklenmedik kilitlenmeler olabilir. O yüzden bu başlıkları pizza hamuru gibi düşün; önce yumuşak başla, kıvamı buldukça sertleşsin. Böyle yaklaşınca hem güvenliği artırır, hem de üretimde sürpriz yaşamazsın.
HSTS: “Hep HTTPS Kullan” Demenin İnce Yolu
HSTS (HTTP Strict-Transport-Security), tarayıcıya “Bu siteye yalnızca HTTPS ile gel, başka yolu unut” deme şekli. Pratikte ne sağlar? Ziyaretçin bir kez HTTPS ile girdi mi, bir sonraki gelişinde tarayıcı HTTP’yi aklından bile geçirmez. Ortadaki adam saldırılarına karşı sağlam bir kilit, karışık içerik uyarılarını azaltan bir pratik ve yönlendirme trafiğini sadeleştiren bir dokunuş.
Burada en kritik konu max-age ve includeSubDomains. İlk denemede çok uzun bir süre verme. Küçük bir değerle başla, sorun yoksa kademeli yükselt. Alt alan adların bu kurala hazır değilse includeSubDomains ekleme, yoksa bir test alt alanı beklenmedik şekilde kilitlenebilir. Hazırlık tamamsa, sonra ekle. Bu işi aceleye getirmeyince sihir gibi çalışıyor.
HSTS nasıl eklenir?
Nginx kullanıyorsan sunucu bloğunda şöyle bir satır işini görür:
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
Apache için ya sanal host config’e ya da .htaccess’e ekleyebilirsin:
Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
“Preload” ne peki? Kısaca, büyük tarayıcıların listesine adını yazdırmak gibi. Böylece daha ilk ziyarette bile tarayıcı seni sadece HTTPS ile düşünür. Başvuru süreci için HSTS preload listesine başvuru sayfasını ziyaret edebilirsin. Ama tekrar hatırlatayım: preload kararı geri dönüşü zor bir adım; subdomain’lerin ve yönlendirmelerin tam oturduğundan emin ol.
Bu arada güvenlik sadece başlıkla olmaz; ağa inen katmanda da iş var. Saldırı yüzeyini daraltmak için güvenlik duvarının neden kritik bir katman olduğuna dair pratik notlara göz atmanı öneririm. HSTS, firewall ve iyi yapılandırılmış TLS birleşince, giriş kapısı çok daha sağlam olur.
CSP: Tarayıcıya “Şu Kaynaktan Script Al, Diğerini Çalıştırma” Demek
CSP (Content-Security-Policy), belki de en etkili ama ilk kurulumda en nazlı başlık. Çünkü sayfadaki kaynakların nereden, nasıl yükleneceğini tek tek tanımlıyorsun. Yanlış yapılandırırsan beklenmedik şekilde butonlar çalışmaz, bir widget kaybolur, hatta analitik script’in bile yüklenmez. O yüzden CSP’yi bir günde sıkılaştırmaya çalışmak yerine, adım adım, ölçerek ilerlemek akıllıca.
Ben genelde “Report-Only” ile başlıyorum. Yani kuralları yazıyorum ama tarayıcıya şimdilik sadece raporla demiş oluyorum. Böylece neyin kırılacağını üretimde görüp notasını alıyorum. Sonra kuralları netleştirip gerçek moda (enforcement) geçiriyorum. Mesela şöyle düşünebilirsin: İlk olarak sadece kendi alan adından script ve stil yüklenmesine izin ver. Sonra kullandığın CDN’leri ekle. En son inline script’lere bir nonce mekanizması ekle. Teker teker oturtunca taşlar yerini buluyor.
Basit bir CSP ile başlamak
Aşağıdaki politika başlangıç için iş görür. Kendi ihtiyaçlarına göre genişletirsin:
Content-Security-Policy: default-src 'self'; script-src 'self' https://cdn.example.com 'nonce-r4nd0m'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; connect-src 'self'; frame-ancestors 'self'; upgrade-insecure-requests;
Buradaki nonce’ı her yanıt için rastgele üretip sayfadaki inline script’e eklersin: <script nonce="r4nd0m">...</script>. Sunucu tarafında templating ile bunu yerleştirmek kolay. “Report-Only” sürümü de şöyle görünür:
Content-Security-Policy-Report-Only: default-src 'self'; ... ; report-to csp-endpoint;
Politikaları yazarken açıklamaların ve örneklerin toplu halde bulunduğu bir kaynak istersen, CSP için MDN’nin kapsamlı kılavuzunu referans alman çok işine yarar. Orada “hangi direktif ne yapar” net net anlatılıyor.
Güvenlik tek başına değil; performans ve ağ katmanıyla kol kola. Örneğin, HTTP/2 veya HTTP/3’e geçtiğinde kaynak yükleme stratejin de değişir. Bu başlıkları elden geçirirken, HTTP/3 protokolünün performansa etkilerini aklında tutmak güzel olur. Güvenliği sıkarken hızı da korumak mümkün.
X-Frame-Options ve Clickjacking: Penceremi Kimse Taşımayacak
Başına gelmiş olabilir: Bir kullanıcı, sitenin bir bölümünün başka bir sitede iframe içinde açıldığını söylüyor. Her şey normal görünse de, üstte görünmez bir katmanla tıklamayı çalma girişimleri yapılabiliyor. Buna clickjacking deniyor. X-Frame-Options da bu noktada bir cümleyle çözüm: “Beni kimse içine gömmesin” ya da “Sadece ben kendimi gömerim” diyebilirsin.
Pratikte iki ayar sık kullanılır: DENY ya da SAMEORIGIN. İlki “asla içime alınma” demek; ikincisi “kendi alan adım içinden gömülebilirim” demek. Dış bir uygulama paneline bilinçli gömmen gerekiyorsa strateji değişir; o durumda modern yaklaşım olarak CSP’nin frame-ancestors direktifini kullanmak daha esnek ve güncel bir yol.
Hızlı uygulama
Nginx:
add_header X-Frame-Options "SAMEORIGIN" always;
Apache / .htaccess:
Header always set X-Frame-Options "SAMEORIGIN"
Iframe kullanan birkaç sayfan varsa, önce nerede hangi alan adından gömüldüğünü not et. Gerekirse bu sayfalarda X-Frame-Options yerine CSP’de frame-ancestors ile daha ince ayar yap. Bu esneklik, özellikle ödeme sağlayıcıları veya canlı destek widget’larıyla çalışırken yumuşak bir geçiş sağlar.
X-Content-Type-Options: “Türünü Tahmin Etme, Ben Söylerim”
Tarayıcılar bazen gelen içeriğin türünü tahmin etmeye çalışır. Normalde masum görünür ama bazı durumlarda istenmeyen yürütmelere kapı aralayabilir. X-Content-Type-Options: nosniff diyerek, “ne gönderiyorsam onu kabul et, fazlasını tahmin etme” mesajını verirsin. Küçük ama etkisi temiz bir ayar.
Nginx için:
add_header X-Content-Type-Options "nosniff" always;
Apache / .htaccess için:
Header always set X-Content-Type-Options "nosniff"
Tabii ki bu başlık tek başına yetmez; statik dosyalarının doğru Content-Type ile servis edildiğinden emin ol. CSS dosyan text/css, JS dosyan application/javascript olarak gitsin. Küçük temizlikler, büyük sürprizleri önlüyor.
Sahaya Sürmek: Nginx, Apache, .htaccess, cPanel ve Cloudflare İle Adım Adım
Şimdi işi mutfağa taşıyalım. “Ben Nginx kullanıyorum, nereden başlarım?” diyorsan, önerim server bloğunda tüm başlıkları bir araya getirmen. Hem düzenli olur hem de nerede ne yaptığını unutmamış olursun. Aşağıdaki paket, temel bir başlangıç profili:
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
add_header Content-Security-Policy "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; connect-src 'self'; frame-ancestors 'self'; upgrade-insecure-requests;" always;
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
Apache tarafında sanal host config’i tercih edebilirsin. Paylaşımlı ortamda .htaccess ile de olur. Örnek bir .htaccess parçası:
<IfModule mod_headers.c>
Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
Header always set Content-Security-Policy "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; connect-src 'self'; frame-ancestors 'self'; upgrade-insecure-requests;"
Header always set X-Frame-Options "SAMEORIGIN"
Header always set X-Content-Type-Options "nosniff"
</IfModule>
cPanel kullanıyorsan, dosya yöneticisiyle kök dizine .htaccess eklemek genelde en hızlısı. Kurulum ve ortam yönetimi tarafında yardıma ihtiyaç duyarsan, sunucu katmanını sağlam kurmak için VPS sunucu güvenliğini pratik ve ölçeklenebilir adımlarla ele alan bu rehber iyi bir eşlikçi olur. Altyapı oturdukça, başlıkların etkisi de daha görünür hale gelir.
CDN ya da Cloudflare kullanıyorsan iş daha da kolay. “Rules” bölümünde HTTP Response Header ekleme kurallarıyla, tek bir panelden tüm kenar noktalarına bu başlıkları yayabilirsin. Dağıtık bir yapıdaysan, bu merkezi yöntem hem tutarlılık sağlar hem de unutulan bir sunucunun açık kapı bırakma ihtimalini azaltır.
Uygularken dikkat edeceğin küçük ama kritik nüanslar
HSTS’i ilk gün “sonsuz” gibi uzun bir süreyle açma. Önce küçük bir süreyle dene, sonra yükselt. CSP’yi “Report-Only” modda gözlemle; konsolda gördüğün ihlallere bak, CDN’lerini ve üçüncü taraf servislerini tek tek ekle. X-Frame-Options ile bazı sayfaların bilinçli olarak gömülmesi gerekiyorsa, o sayfalar için farklı bir kural uygula veya CSP’de frame-ancestors ile esnek davran.
İşin güvenlik tarafını güçlendirirken, ağ katmanını da ihmal etme. Anlık dalgalanmaları ve kapasite denemelerini hesaba katmak için DDoS saldırılarını ve korunma yöntemlerini daha pratik bir gözle okuman yol gösterici olur. Başlıklar uygulamada, ağ ve uygulama katmanı savunmada olursa, iyi bir denge yakalarsın.
Doğrulama, Test ve Kademeli Yayın: Kırmadan Sertleştir
Benim sevdiğim test rutini çok basit. Önce terminalde bir curl -I ile bakarım:
curl -I https://seninsiten.com
Yanıtta başlıkların gelip gelmediğini kontrol ederim. Ardından tarayıcı konsolunu açıp hem ağ sekmesinde hem konsolda uyarı var mı diye bakarım. CSP ihlalleri burada çok net görünür. Sonra küçük bir kullanıcı grubuna yayar, hataları dinler, kademeli olarak tüm trafiğe açarım.
Bir de otomatik kontrol hoşuma gider. Zaman zaman Security Headers taraması ile başlık puanını kontrol eder, değişikliklerin etkisini görürüm. A notu bazen tek hedef gibi görünür ama asıl mesele, sitenin iş hedeflerini bozmadan güvenliği artırmak. Bu yüzden sıkılık seviyesini ürünün gereksinimlerine göre ayarlamak en mantıklısı.
Son bir nokta: Başlıklar, uygulamanın güvenli kodlandığı ve altyapının sağlam olduğu varsayımıyla parlıyor. Kod tarafında input doğrulamaları, çıktı kaçışları, oturum yönetimi gibi klasik konular da aynı denklemde. Güvenliği katmanlı düşünmek iyi bir alışkanlık. Bu bağlamda, trafik yönetimini ve segmentasyonu düşünürken güvenlik duvarının rolü ve ağ katmanı savunması hatırlanmalı. Bir de performans tarafından “ben hızdan feragat etmek istemiyorum” diyorsan; modern protokoller, önbellek ve sıkıştırma ile aynı anda iki hedefi tutturmak mümkün. Bu denge için HTTP/3 hakkında bu notlar aklının bir köşesinde dursun.
Kapanış: Küçük Başlıklar, Büyük Etki
Toparlayalım. HSTS ile “yalnızca güvenli bağlantı” netleşiyor. CSP ile “hangi kaynaktan ne yüklenecek” keskinleşiyor. X-Frame-Options ile clickjacking kapısı kapanıyor. X-Content-Type-Options ile tarayıcı “tahmin etme, ben söylüyorum” mesajını alıyor. Dördü birlikte, saldırı yüzeyini sessizce ama etkili şekilde daraltıyor.
Uygularken aceleye gerek yok. Önce küçük bir HSTS süresi, sonra yükselt. CSP’yi Report-Only ile gözlemle, hangi CDN’e ve hangi üçüncü tarafa gerçekten ihtiyacın olduğuna karar ver. X-Frame-Options’ı genel kuralla koy, istisnai sayfaları CSP’nin frame-ancestors’ına emanet et. X-Content-Type-Options’ı unutma; üstüne bir de doğru içerik türleriyle dosyaları servis et. Bu ritmi oturttuğunda, sürprizlerin sayısı hızla azalır.
İşin altyapı tarafı için de bir not bırakayım: Sunucunun temel güvenliği, güncellemeler, izleme ve log’lar bir bütün. Detaylı bir yol haritası ararsan, VPS güvenliği rehberi iyi bir pusula olur. Umarım bu yazı, seni başlıklara bir adım daha yaklaştırır. Takıldığın yerde dönüp bakabileceğin bir rehber olarak burada kalsın. Bir sonraki yazıda görüşürüz; bu arada bugün küçük bir HSTS’i devreye alıp, CSP’yi Report-Only ile denemeye başlamaya ne dersin?
