ERETEK
BİLGİ SİSTEMLERİ

Web Sunucusunda TLS Yapılandırması: Protokol, Şifre ve HSTS

Nginx ve Apache’de TLS: eski protokolleri kapatma, Mozilla profilleri, eksik ara sertifika, HSTS ve preload riski, openssl ve testssl.sh ile doğrulama.

Bu makalede8 bölüm
Teknik özet
Teknoloji
TLS 1.2, TLS 1.3, Nginx, Apache mod_ssl, HSTS, OpenSSL, testssl.sh
Konu
Web sunucusunda güvenli ve uyumlu TLS ayarları
Seviye
Orta–ileri
Ön koşullar
  • Geçerli bir sertifika ve özel anahtar
  • Nginx veya Apache yapılandırma dosyalarına erişim
  • Temel OpenSSL komut satırı bilgisi

Adres çubuğunda kilit simgesi görünüyor diye TLS doğru yapılandırılmış sayılmaz. Aynı sunucuda TLS 1.0 hâlâ açık, ara sertifika eksik ya da HSTS aceleyle includeSubDomains ile yayınlanmış olabilir. Bunlar güvenlik taramasında bulgu, API istemcilerinde bağlantı hatası, bazen de aylarca geri alınamayan bir karar olarak döner. Aşağıda Nginx ve Apache’de protokol ve şifre seçimini, zincirin sunulmasını, HSTS kararını ve doğrulamayı uygulamada izlenmesi gereken sırayla ele alıyoruz.

TLS sürümleri ve uyumluluk

Bugün bir web sunucusunda açık olması gereken sürümler TLS 1.2 (RFC 5246) ve TLS 1.3’tür (RFC 8446). TLS 1.0 ve 1.1, RFC 8996 ile resmi olarak kullanımdan kaldırıldı; modern tarayıcılar da bu sürümlerle bağlanmıyor. SSLv2 veya SSLv3 açıksa tartışılacak bir şey yok. Bu doğrudan bir açıktır.

TLS 1.3, el sıkışmayı bir tur gidiş-dönüşe indirir, statik RSA anahtar değişimini ve CBC tabanlı şifreleri tamamen kaldırır, ileri gizliliği (forward secrecy) zorunlu kılar. TLS 1.2 ise doğru şifre takımlarıyla hâlâ güvenlidir ve eski istemcilerle uyumluluk için gereklidir.

Sürüm Durum Öneri
SSLv3, TLS 1.0, TLS 1.1 Kullanımdan kaldırıldı Kapatın
TLS 1.2 Güncel, yalnız AEAD şifrelerle Açık tutun
TLS 1.3 Güncel Açın

Karar vermeden önce kurumsal web sitenize kimlerin bağlandığını düşünün: yalnız tarayıcılar mı, yoksa eski bir ERP modülü, ödeme kuruluşu geri çağrısı veya sahadaki gömülü cihazlar da mı? Erişim loglarına $ssl_protocol ve $ssl_cipher değişkenlerini ekleyerek birkaç haftalık gerçek kullanımı görmek, bu soruyu tahminle değil veriyle yanıtlamayı sağlar. Protokol kapatma kararını bu veriyi görmeden vermeyin; bir ödeme kuruluşunun geri çağrısı sessizce düşerse site açılmaya devam ettiği için bunu ilk fark eden muhasebe olur.

Şifre takımı seçimi ve profiller

Şifre listesini forum yanıtlarından ya da eski bir sunucudan kopyalamayın. Mozilla’nın sürdürdüğü SSL Configuration Generator güncel ve tutarlı bir başlangıç noktasıdır; üç profil sunar:

  • Modern: Yalnız TLS 1.3. En sıkı seçenek; eski istemciler bağlanamaz.
  • Intermediate: TLS 1.2 ve 1.3; TLS 1.2 tarafında yalnızca ECDHE/DHE anahtar değişimli AEAD şifreler (AES-GCM, ChaCha20-Poly1305). Genel amaçlı siteler için önerilen profildir.
  • Old: Çok eski istemciler için; yalnızca bunu gerektiren özel bir bağımlılık varsa ve ayrı bir uç noktada kullanılmalıdır.

Intermediate profilde sunucu şifre tercihi kapalıdır (ssl_prefer_server_ciphers off): listedeki tüm şifreler güçlü olduğundan, istemcinin kendi donanımına uygun olanı (örneğin AES hızlandırması olmayan mobil cihazda ChaCha20) seçmesine izin verilir. TLS 1.3 şifre takımları (TLS_AES_128_GCM_SHA256, TLS_AES_256_GCM_SHA384, TLS_CHACHA20_POLY1305_SHA256) OpenSSL tarafından ayrı yönetilir; Nginx’in ssl_ciphers ve Apache’nin SSLCipherSuite varsayılan kullanımı bunları etkilemez.

Sertifika anahtar türü de bir karardır: ECDSA P-256 anahtarlar daha küçük ve el sıkışmada daha hızlıdır; RSA 2048 ise en geniş uyumluluğu verir. Nginx ve Apache aynı site için hem RSA hem ECDSA sertifikasını birlikte sunabilir; istemci desteklediğini alır. Uyumluluk tartışması varsa en az riskli yol budur.

Sertifika zinciri doğru kurulumu

İstemci, sunucu sertifikasından güvendiği köke kadar bir zincir kurabilmelidir. Sunucu, kendi sertifikasını ve ara sertifikaları göndermekle yükümlüdür; kök sertifika gönderilmez, istemcinin deposunda zaten bulunur.

  • Nginx: ssl_certificate tek bir dosya alır; bu dosya önce sunucu sertifikasını, ardından ara sertifikaları içermelidir. Certbot kullanıyorsanız cert.pem değil fullchain.pem kullanılır.
  • Apache: 2.4.8’den beri SSLCertificateFile ara sertifikaları da içerebilir; SSLCertificateChainFile bu sürümle birlikte kullanımdan kaldırılmış kabul edilir.

Sahada en sık görülen TLS hatası tam olarak budur: cert.pem ile kurulmuş bir site. Tarayıcı açar, API istemcisi açmaz.

Sertifika ile özel anahtarın eşleştiğini, değiştirme öncesinde iki taraftaki açık anahtarın SHA-256 değerini karşılaştırarak doğrulayın; bu yöntem RSA ve ECDSA için aynı şekilde çalışır:

openssl x509 -in fullchain.pem -noout -pubkey | sha256sum
openssl pkey -in privkey.pem -pubout | sha256sum
# İki çıktı aynı olmalıdır.

OCSP stapling uzun süre standart öneriydi; ancak bazı sertifika otoriteleri (Let’s Encrypt dahil) OCSP hizmetini sonlandırdı ve iptal bilgisini CRL üzerinden yayımlamaya geçti. Stapling’i açmadan önce CA’nızın sertifikalarında OCSP adresi bulunup bulunmadığını kontrol edin; adres yoksa bu ayar hata loglarında uyarıdan başka bir şey üretmez. Sertifikanın otomatik edinilmesi ve yenilenmesi ise ayrı bir süreçtir ve Let’s Encrypt sertifika otomasyonu rehberinde ele alınıyor.

HSTS ve preload kararı

HTTP Strict Transport Security (RFC 6797), tarayıcıya belirli bir süre boyunca bu alan adına yalnızca HTTPS ile bağlanmasını söyler. İlk ziyaretten sonra kullanıcı adres çubuğuna http:// yazsa bile tarayıcı isteği kendisi HTTPS’e çevirir; bu, ağdaki bir saldırganın ilk düz HTTP isteğini ele geçirmesini (SSL stripping) engeller ve sertifika hatasında “yine de devam et” seçeneğini kaldırır.

HSTS’in üç parametresi var; her biri ayrı bir risk taşır:

Parametre Etkisi Risk
max-age Kuralın tarayıcıda saklanma süresi Süre dolana kadar HTTP’ye dönüş yok
includeSubDomains Tüm alt alan adlarını kapsar HTTPS’siz iç veya eski alt alan adları erişilemez olur
preload Tarayıcıların gömülü listesine başvuru izni Listeden çıkış aylar sürebilir

Güvenli geçiş sırası: önce tüm HTTP isteklerini 301 ile HTTPS’e yönlendirin; ardından max-age=300 ile HSTS yayınlayın; tüm alt alan adlarının envanterini çıkarıp HTTPS’e taşındığını doğrulayın; değeri haftalar içinde bir yıla çıkarın; ancak bundan sonra includeSubDomains ve gerekirse preload ekleyin. Preload başvurusu hstspreload.org üzerinden yapılır ve en az bir yıllık max-age, includeSubDomains ile preload yönergelerini ister. Alan adının altında HTTPS’e taşınamayan bir intranet, yazıcı arayüzü veya eski uygulama varsa preload’a başvurmayın. Bu, geri alınması en zor karardır.

Nginx ve Apache yapılandırma örnekleri

Aşağıdaki örnekler Mozilla Intermediate profiline dayanır; şifre listesini kopyalamadan önce oluşturucudan sunucu ve OpenSSL sürümünüze göre güncel çıktıyı alın.

Nginx

server {
    listen 443 ssl;
    http2 on;
    server_name www.example.com;

    ssl_certificate     /etc/letsencrypt/live/example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;

    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305;
    ssl_prefer_server_ciphers off;

    ssl_session_cache shared:SSL:10m;
    ssl_session_timeout 1d;
    ssl_session_tickets off;

    add_header Strict-Transport-Security "max-age=63072000" always;
}

add_header kalıtımı, proxy başlıklarındaki tuzağın aynısını kurar: bir location bloğunda başka bir add_header tanımlanırsa, server seviyesindeki tüm add_header direktifleri o location için geçersiz olur ve HSTS başlığı sessizce kaybolur. Güvenlik başlıklarını bir snippet dosyasında toplayıp gereken her blokta include etmek bu sorunu önler. always parametresi başlığın hata yanıtlarında da gönderilmesini sağlar. Tarama raporlarındaki “HSTS bazı sayfalarda yok” bulgusunun yaygın nedeni bu kalıtımdır.

Apache (mod_ssl ve mod_headers)

<VirtualHost *:443>
    ServerName www.example.com
    SSLEngine on
    SSLCertificateFile    /etc/letsencrypt/live/example.com/fullchain.pem
    SSLCertificateKeyFile /etc/letsencrypt/live/example.com/privkey.pem

    SSLProtocol -all +TLSv1.2 +TLSv1.3
    SSLCipherSuite ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305
    SSLHonorCipherOrder off
    SSLSessionTickets off

    Header always set Strict-Transport-Security "max-age=63072000"
</VirtualHost>

Session ticket’ların kapatılması, anahtarı düzenli döndürülmeyen ticket’ların ileri gizliliği zayıflatmasını önlemek içindir; oturum yeniden kullanımı paylaşımlı oturum önbelleğiyle devam eder. Apache’de SSLSessionCache genellikle dağıtımın varsayılan ssl.conf dosyasında global olarak tanımlıdır; kontrol edin. Her iki sunucuda da değişiklikten önce nginx -t veya apachectl configtest çalıştırın. Sunucu seçimi ve Apache’ye özgü ayarlar için Apache HTTP Server kurulum ve optimizasyon hizmet sayfasına bakabilirsiniz.

Doğrulama araçları ve sık hatalar

Kilit simgesi doğrulama değildir. Yapılandırmayı protokol düzeyinde test edin:

# Zinciri ve el sıkışmayı gör (SNI için -servername şart)
openssl s_client -connect www.example.com:443 -servername www.example.com -showcerts </dev/null

# Eski protokol reddediliyor mu? (Bu komutun başarısız olması beklenir)
openssl s_client -connect www.example.com:443 -servername www.example.com -tls1_1 </dev/null

# Sertifika bitiş tarihi
echo | openssl s_client -connect www.example.com:443 -servername www.example.com 2>/dev/null | openssl x509 -noout -enddate

# HSTS başlığı
curl -sI https://www.example.com | grep -i strict-transport-security

# Kapsamlı tarama (protokoller, şifreler, zincir, bilinen zafiyetler)
./testssl.sh https://www.example.com

Not: Sisteminizdeki OpenSSL derlemesi TLS 1.1’i istemci tarafında da devre dışı bırakmışsa ikinci komut sunucudan bağımsız olarak başarısız olur; bu durumda sonucu testssl.sh çıktısıyla teyit edin. testssl.sh internet erişimi olmayan iç sunucularda da çalışır, bu yüzden dış tarama servislerine ulaşamayan sistemler için uygundur.

Belirti Neden Çözüm
Tarayıcı açıyor, curl veya API istemcisi hata veriyor Ara sertifika eksik fullchain.pem kullanın
Yanlış sertifika dönüyor SNI eşleşmiyor, varsayılan server bloğu yanıtlıyor server_name ve default_server kontrolü
HSTS bazı sayfalarda yok Location içinde add_header kalıtımı Başlıkları snippet ile her blokta tanımlayın
Alt alan adı erişilemiyor Erken includeSubDomains Envanter sonrası etkinleştirin
Taramada TLS 1.0 açık görünüyor Başka bir sanal sunucu veya port farklı ayarlı Ayarları global düzeyde de tanımlayın

Nginx’te ssl_protocols aynı IP:port üzerindeki varsayılan server bloğunun ayarından etkilenebilir; tüm sanal sunucularda aynı protokol ayarını http düzeyinde tanımlamak tutarsızlığı önler. Önde Cloudflare gibi bir CDN varsa, istemcinin gördüğü TLS ayarı CDN’in kenar ayarıdır; kaynak sunucu ile CDN arasındaki bağlantı için ayrıca “Full (strict)” benzeri doğrulamalı bir mod seçilmelidir. “Flexible” mod, CDN ile kaynak arasını şifresiz bırakır.

Uygulama kontrol listesi

  • Yalnız TLS 1.2 ve 1.3 açık; tüm sanal sunucu ve portlarda tutarlı.
  • TLS 1.2 şifreleri yalnız ECDHE/DHE tabanlı AEAD takımları.
  • Sunucu sertifikası ve ara sertifikalar birlikte sunuluyor; anahtar eşleşmesi doğrulandı.
  • HTTP’den HTTPS’e 301 yönlendirme var; HSTS kademeli artırıldı.
  • Preload kararı, tüm alt alan adı envanteri çıkarıldıktan sonra verildi.
  • Sertifika bitiş tarihi izleniyor; testssl.sh taraması her yapılandırma değişikliğinden sonra tekrarlanıyor.

TLS yalnızca taşımayı korur. Uygulama zafiyetleri, güvenlik başlıkları ve saldırı filtreleme ayrı bir katmandır; bunlar web uygulama güvenliği ve WAF çalışmasının konusudur. Reverse proxy arkasındaki uygulamaya protokol bilgisinin nasıl aktarıldığı ise Nginx reverse proxy yapılandırması yazısında anlatılıyor.

Sık sorulan sorular

TLS 1.2’yi kapatıp yalnızca TLS 1.3 kullanmak doğru mu?

Ziyaretçileriniz ve sitenize bağlanan sistemler TLS 1.3 destekliyorsa mümkündür; Mozilla’nın Modern profili bunu önerir. Ancak eski işletim sistemleri, gömülü cihazlar, bazı kurumsal proxy’ler ve eski kütüphanelerle çalışan entegrasyonlar TLS 1.3 desteklemeyebilir. Kurumsal sitelerde TLS 1.2 ve 1.3’ün birlikte açık olduğu Intermediate profil çoğu durumda doğru dengedir; kararı erişim loglarındaki protokol dağılımına bakarak verin.

HSTS max-age değeri ne olmalı?

Geçişte önce kısa bir değerle (örneğin 300 saniye) başlayıp tüm alt alan adlarının HTTPS ile sorunsuz çalıştığını doğruladıktan sonra değeri kademeli artırmak güvenlidir. Kalıcı durumda bir yıl (31536000) veya iki yıl (63072000) yaygındır; preload listesi en az bir yıl ister.

Sertifika geçerli olduğu halde bazı istemciler neden güvenilmeyen sertifika hatası veriyor?

En yaygın neden ara sertifikanın sunulmamasıdır. Tarayıcılar eksik ara sertifikayı önbellekten veya AIA bilgisiyle tamamlayabildiği için masaüstünde sorun görünmez; curl, Java, mobil uygulamalar ve API istemcileri ise bağlantıyı reddeder. Nginx’te fullchain dosyasını kullanın ve openssl s_client çıktısında zincirin tamamını görün.

TLS 1.3 şifre takımlarını Nginx’te ssl_ciphers ile değiştirebilir miyim?

Hayır. ssl_ciphers yalnızca TLS 1.2 ve öncesini etkiler. TLS 1.3 şifre takımları OpenSSL tarafından ayrı yönetilir ve varsayılan üç takım güvenlidir; çoğu kurulumda değiştirmeye gerek yoktur. Zorunlu bir gereksinim varsa Nginx 1.19.4 ve sonrasında ssl_conf_command Ciphersuites direktifiyle OpenSSL’e doğrudan ayar geçirilebilir.

Teknik özet
Teknoloji
TLS 1.2, TLS 1.3, Nginx, Apache mod_ssl, HSTS, OpenSSL, testssl.sh
Konu
Web sunucusunda güvenli ve uyumlu TLS ayarları
Seviye
Orta–ileri
Ön koşullar
  • Geçerli bir sertifika ve özel anahtar
  • Nginx veya Apache yapılandırma dosyalarına erişim
  • Temel OpenSSL komut satırı bilgisi
Eretek uzman desteği

Bu konu sizin ortamınızda nasıl çalışır, birlikte bakalım.

Mevcut yapınızı inceliyor, darboğazı tespit ediyor ve uygulanabilir bir iş planı öneriyoruz.