Web sitenize bir kullanıcı HTTP üzerinden bağlandığında, tarayıcı ile sunucu arasındaki bu ilk握手tamamen açık metin olarak gerçekleşir. Siz sunucu tarafında HTTPS’e yönlendirme yapıyor olsanız bile, o ilk istek bir saldırgan tarafından ele geçirilebilir ve kullanıcı farkında olmadan HTTP üzerinde kalmaya devam edebilir. İşte HSTS (HTTP Strict Transport Security), tam olarak bu açığı kapatan bir güvenlik mekanizmasıdır. Bugün HSTS’nin ne olduğunu, nasıl çalıştığını ve farklı web sunucularında nasıl yapılandırıldığını ele alacağız.
HSTS Nedir?
HSTS, bir web sunucusunun tarayıcıya “benimle sadece HTTPS üzerinden konuş” dediği bir HTTP güvenlik başlığıdır. RFC 6797 ile standartlaştırılan bu mekanizma, tarayıcının belirli bir süre boyunca ilgili domain için yalnızca HTTPS bağlantısı kullanmasını zorunlu kılar.
Teknik açıdan baktığımızda, sunucu HTTPS yanıtına şu başlığı ekler:
Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
Tarayıcı bu başlığı gördükten sonra, belirlenen süre boyunca (max-age saniye cinsinden) o domain’e yapılan tüm HTTP isteklerini otomatik olarak HTTPS’e çevirir. Sunucuya bile sormadan, tamamen istemci tarafında bu dönüşüm gerçekleşir.
SSL Stripping Saldırısı ve HSTS’nin Önemi
HSTS’yi neden kullandığımızı anlamak için önce SSL Stripping saldırısını kavramak gerekiyor.
Saldırgan, kullanıcı ile sunucu arasına girerek (Man-in-the-Middle) şu senaryoyu uygular:
- Kullanıcı
http://bank.example.comadresine bağlanmaya çalışır - Saldırgan bu isteği yakalar ve sunucuyla kendi HTTPS bağlantısını kurar
- Sunucudan aldığı HTTPS yanıtını HTTP’ye çevirerek kullanıcıya iletir
- Kullanıcı HTTP üzerinden iletişim kurduğunu fark etmez, tüm veriler açıkta kalır
Sunucu tarafında 301/302 yönlendirme yapılmış olsa bile, bu ilk HTTP isteği saldırgan tarafından yakalanabilir. HSTS ile tarayıcı, HTTP isteğini sunucuya hiç göndermez ve doğrudan HTTPS kullanır. Saldırganın araya girebileceği ilk HTTP isteği ortadan kalkar.
HSTS Başlık Parametreleri
max-age
max-age: Tarayıcının bu kuralı kaç saniye boyunca hatırlayacağını belirtir. Yaygın değerler:
- max-age=3600: 1 saat (test ortamları için)
- max-age=86400: 1 gün (geçiş dönemlerinde)
- max-age=2592000: 30 gün
- max-age=31536000: 1 yıl (üretim ortamları için önerilen)
- max-age=63072000: 2 yıl (preload listesi için minimum)
includeSubDomains
includeSubDomains: Bu direktif eklendiğinde, kural yalnızca ana domain için değil, tüm alt domainler için de geçerli olur. api.example.com, mail.example.com, cdn.example.com gibi tüm subdomainler HTTPS zorunluluğuna tabi olur. Bu direktifi eklemeden önce tüm subdomainlerinizin geçerli SSL sertifikasına sahip olduğundan emin olun.
preload
preload: Tarayıcıların içine gömülü olan HSTS Preload listesine dahil olmak istediğinizi belirtir. Bu liste sayesinde, kullanıcı sitenize ilk kez hiç girmeden bile tarayıcı HTTPS kullanır. Sadece bu direktifi eklemek yeterli değildir; ayrıca hstspreload.org üzerinden başvuru yapmanız gerekir.
Nginx’te HSTS Yapılandırması
Nginx için en temel HSTS yapılandırması şu şekildedir:
# /etc/nginx/sites-available/example.com
server {
listen 80;
server_name example.com www.example.com;
# HTTP'den HTTPS'e kalıcı yönlendirme
return 301 https://$server_name$request_uri;
}
server {
listen 443 ssl http2;
server_name example.com www.example.com;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
# HSTS başlığı - sadece HTTPS bloğuna eklenmeli
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
# Diğer güvenlik başlıkları
add_header X-Content-Type-Options "nosniff" always;
add_header X-Frame-Options "SAMEORIGIN" always;
location / {
root /var/www/example.com;
index index.html;
}
}
Önemli bir nokta: add_header direktifini sadece HTTPS server bloğuna ekleyin. HTTP bloğuna eklerseniz, tarayıcı HTTP üzerinden HSTS başlığı alır ve bu güvenilir değildir.
Yapılandırmayı test edip yeniden yükleyelim:
# Nginx yapılandırmasını test et
nginx -t
# Başarılıysa servisi yeniden yükle
systemctl reload nginx
# HSTS başlığını doğrula
curl -I https://example.com | grep -i strict
Nginx’te Global HSTS Yapılandırması
Birden fazla siteniz varsa, her site için tekrar tekrar yazmak yerine global bir yapılandırma dosyası oluşturabilirsiniz:
# /etc/nginx/conf.d/security-headers.conf
# Bu dosyayı HTTPS server bloklarınızda include edin
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" 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;
Sonra her HTTPS server bloğunda:
server {
listen 443 ssl http2;
server_name example.com;
include /etc/nginx/conf.d/security-headers.conf;
# Diğer yapılandırmalar...
}
Apache’de HSTS Yapılandırması
Apache için önce mod_headers modülünün etkin olduğundan emin olun:
# mod_headers'ı etkinleştir
a2enmod headers
a2enmod rewrite
# Servisi yeniden başlat
systemctl restart apache2
Ardından virtual host yapılandırmasına HSTS ekleyin:
# /etc/apache2/sites-available/example.com.conf
<VirtualHost *:80>
ServerName example.com
ServerAlias www.example.com
# HTTP'yi HTTPS'e yönlendir
RewriteEngine On
RewriteCond %{HTTPS} off
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]
</VirtualHost>
<VirtualHost *:443>
ServerName example.com
ServerAlias www.example.com
SSLEngine on
SSLCertificateFile /etc/letsencrypt/live/example.com/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/example.com/privkey.pem
# HSTS başlığını sadece HTTPS bağlantılarına ekle
Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
DocumentRoot /var/www/example.com
<Directory /var/www/example.com>
AllowOverride All
Require all granted
</Directory>
</VirtualHost>
Apache’de .htaccess dosyası üzerinden de yapılandırma yapılabilir, ancak bu yöntem performans açısından tercih edilmez. Yine de paylaşımlı hosting gibi durumlarda işe yarar:
# .htaccess
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{HTTPS} off
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]
</IfModule>
<IfModule mod_headers.c>
# Sadece HTTPS bağlantılarda başlık ekle
Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains" env=HTTPS
</IfModule>
HAProxy ile HSTS
Load balancer olarak HAProxy kullanıyorsanız, HSTS’yi backend sunuculara bırakmak yerine HAProxy seviyesinde merkezi olarak yönetmek çok daha pratiktir:
# /etc/haproxy/haproxy.cfg
frontend https_frontend
bind *:443 ssl crt /etc/haproxy/certs/example.com.pem
bind *:80
# HTTP'yi HTTPS'e yönlendir
http-request redirect scheme https unless { ssl_fc }
# HSTS başlığını frontend'de ekle
http-response set-header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
default_backend web_servers
backend web_servers
balance roundrobin
server web1 192.168.1.10:80 check
server web2 192.168.1.11:80 check
Uygulama Seviyesinde HSTS
Node.js / Express
# npm install helmet
const express = require('express');
const helmet = require('helmet');
const app = express();
// Helmet ile HSTS yapılandırması
app.use(helmet.hsts({
maxAge: 31536000,
includeSubDomains: true,
preload: true
}));
// Ya da manuel olarak
app.use((req, res, next) => {
if (req.secure) {
res.setHeader(
'Strict-Transport-Security',
'max-age=31536000; includeSubDomains; preload'
);
}
next();
});
Python / Django
# settings.py
SECURE_HSTS_SECONDS = 31536000
SECURE_HSTS_INCLUDE_SUBDOMAINS = True
SECURE_HSTS_PRELOAD = True
SECURE_SSL_REDIRECT = True
# Nginx/Apache arkasında çalışıyorsa
SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')
HSTS Preload Listesine Başvuru
Preload listesi, Chrome, Firefox, Safari, Edge gibi tarayıcılara gömülü olarak gelir ve bu listedeki domainler için tarayıcı ilk ziyaretten itibaren HTTPS kullanır.
Başvuru için gereksinimler:
- Geçerli bir SSL sertifikasına sahip olmak
- HTTP’den HTTPS’e yönlendirme yapıyor olmak
- Tüm subdomainlerin HTTPS desteklemesi
max-agedeğerinin en az 31536000 (1 yıl) olmasıincludeSubDomainsdirektifinin bulunmasıpreloaddirektifinin bulunması
Başvuruyu https://hstspreload.org adresinden yapabilirsiniz. Listeye dahil olmak birkaç ay sürebilir ve bir sonraki tarayıcı güncellemesiyle birlikte etkili olur.
Dikkat: Preload listesinden çıkmak, listeye girmekten çok daha zor ve uzun sürelidir. Bu kararı vermeden önce tüm subdomainlerinizin kalıcı olarak HTTPS’i destekleyeceğinden emin olun.
Gerçek Dünya Senaryoları
Senaryo 1: Kademeli HSTS Geçişi
Büyük bir e-ticaret sitesini yönetiyorsunuz. Bazı subdomainlerinizin henüz SSL sertifikası yok ve hızlıca includeSubDomains eklemek sorun çıkarır. Kademeli geçiş şu şekilde olabilir:
İlk hafta, düşük max-age ile başlayın:
Strict-Transport-Security: max-age=86400
Bir hafta sonra sorun çıkmıyorsa artırın:
Strict-Transport-Security: max-age=604800
Tüm subdomainlere SSL ekledikten sonra:
Strict-Transport-Security: max-age=2592000; includeSubDomains
Kararlı bir süre sonra tam yapılandırmaya geçin:
Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
Senaryo 2: HSTS’yi Sıfırlamak
Bir alt domain’in SSL sertifikasını yenilemeyi unuttuğunuzu ve HSTS nedeniyle kullanıcıların siteye erişemediğini varsayalım. Kısa vadeli çözüm olarak max-age=0 döndürebilirsiniz:
# Nginx - Acil HSTS sıfırlama
add_header Strict-Transport-Security "max-age=0" always;
Bu, tarayıcıların HSTS kaydını silmesini sağlar, ancak halihazırda etkilenen kullanıcılar için elle temizleme gerekebilir. Chrome’da chrome://net-internals/#hsts adresinden belirli bir domain için HSTS kaydı silinebilir.
Senaryo 3: Staging Ortamında HSTS
Staging ortamınızda HSTS etkinleştirirseniz ve bu ortam production ile aynı domain adını kullanıyorsa, geliştiricilerin tarayıcılarında kalıcı bir zorunluluk oluşturabilirsiniz. Staging için kısa max-age kullanın veya HSTS’yi tamamen devre dışı bırakın:
# staging.nginx.conf
server {
listen 443 ssl;
server_name staging.example.com;
# Staging'de HSTS ekleme, kısa tutuyoruz
add_header Strict-Transport-Security "max-age=3600" always;
# Production benzeri konfigürasyon buraya...
}
HSTS Yapılandırmasını Test Etme
Yapılandırmanın doğru çalıştığını test etmek için birkaç yöntem:
# curl ile başlık kontrolü
curl -sI https://example.com | grep -i "strict-transport"
# Beklenen çıktı:
# strict-transport-security: max-age=31536000; includeSubDomains; preload
# OpenSSL ile SSL/TLS kontrolü
openssl s_client -connect example.com:443 -servername example.com 2>/dev/null | openssl x509 -noout -dates
# Nmap ile HSTS kontrolü
nmap --script http-security-headers -p 443 example.com
# HTTPie ile daha okunaklı çıktı
http --headers https://example.com | grep -i strict
Online araçlar için securityheaders.com ve ssllabs.com/ssltest adreslerini kullanabilirsiniz. SSL Labs, HSTS yapılandırmanızı değerlendirerek A+ notu almanızı sağlar.
Sık Yapılan Hatalar
HSTS başlığını HTTP bloğuna eklemek: Tarayıcılar HSTS başlığını yalnızca güvenli bağlantılar üzerinden aldıklarında geçerli sayar. HTTP bloğuna eklenen HSTS başlığı görmezden gelinir.
Self-signed sertifika ile HSTS: HSTS yalnızca geçerli, güvenilen bir sertifika ile anlamlıdır. Self-signed sertifika kullanan bir sitede HSTS aktif etseydiniz, kullanıcılar sertifika uyarısını aşamaz ve siteye hiç erişemez hale gelirlerdi.
Sertifika süresini kaçırmak: HSTS aktifken sertifikanızın süresi dolarsa, kullanıcılar sitenize erişemez. Sertifika yenilemeyi otomatize edin:
# Let's Encrypt otomatik yenileme kontrolü
systemctl status certbot.timer
# Manuel test
certbot renew --dry-run
# Cron ile yedek yenileme
echo "0 3 * * * root certbot renew --quiet --post-hook 'systemctl reload nginx'" > /etc/cron.d/certbot-renew
includeSubDomains’i acele eklemek: Tüm subdomainlerinizi kontrol etmeden bu direktifi eklemeyin. Özellikle üçüncü parti servislerin subdomainleri (mail, ftp, legacy uygulamalar) sorun çıkarabilir.
Sonuç
HSTS, modern web güvenliğinin olmazsa olmaz parçalarından biridir. SSL Stripping saldırılarına karşı etkili bir savunma hattı oluşturur ve kullanıcılarınızın bağlantılarını pasif olarak korur. Yapılandırması görece basit olsa da, yanlış uygulandığında ciddi erişim sorunlarına yol açabilir.
Uygulamaya geçerken kademeli bir yaklaşım benimseyin: önce düşük max-age ile başlayın, altyapınızın HTTPS için tamamen hazır olduğunu doğrulayın, sonra değeri artırın ve son olarak includeSubDomains ile preload direktiflerini ekleyin. Sertifika yenileme sürecinizi otomatize etmeyi unutmayın; HSTS aktifken süresi dolmuş bir sertifika ciddi kesintilere neden olur.
Preload listesine başvurmak geri dönüşü olmayan bir adımdır. Bu kararı vermeden önce tüm altyapınızın uzun vadede HTTPS’i destekleyeceğinden emin olun. Doğru yapılandırılmış bir HSTS politikası, SSL Labs testlerinde A+ notunu almanızı sağlayacak ve kullanıcılarınızın güvenliğini önemli ölçüde artıracaktır.