IIS yönetiyorsanız ve sunucunuz internete açıksa, güvenlik sertleştirme yapmadan uyumanız gerçekten zor olmalı. Varsayılan IIS kurulumu işlevsel ama asla güvenli değil. Microsoft her şeyi kutudan çıkar çıkmaz çalışır hale getiriyor, ancak bu “çalışır” durum çoğu zaman “güvenli” anlamına gelmiyor. Bu yazıda gerçek dünya saldırılarından yola çıkarak IIS’i nasıl sertleştireceğinizi adım adım anlatacağım.
Neden IIS Sertleştirme Gerekli?
Geçen yıl bir e-ticaret müşterimizin sunucusuna baktığımda şunu gördüm: IIS 10 kurulu, Windows Server 2019 üzerinde çalışıyor, ancak HTTP response header’larında sunucu versiyonu açıkça yazıyor, WebDAV aktif, gereksiz HTTP metodları etkin ve SSL konfigürasyonu berbat durumdaydı. Shodan’da aratınca sunucu zaten kataloglanmıştı bile.
IIS sertleştirme birkaç temel prensip üzerine kuruludur:
- Saldırı yüzeyini küçültmek: Kullanmadığın her şeyi kapat
- Bilgi sızdırmayı engellemek: Sunucu hakkında minimum bilgi ver
- Erişim kontrollerini sıkılaştırmak: Kimin neye erişeceğini net belirle
- Şifrelemeyi zorlamak: HTTP’yi öldür, HTTPS’i yaşat
- Loglama ve izlemeyi güçlendirmek: Ne olduğunu bil
Temel IIS Rolü ve Özellik Yönetimi
İlk adım gereksiz IIS özelliklerini kapatmak. Çoğu sysadmin IIS kurarken “hepsini seç” diyip geçiyor. Bu büyük hata.
PowerShell ile hangi özelliklerin kurulu olduğuna bakalım:
# Kurulu IIS özelliklerini listele
Get-WindowsFeature -Name Web-* | Where-Object {$_.InstallState -eq "Installed"}
# WebDAV'ı kaldır (çoğu senaryoda gereksiz ve tehlikeli)
Remove-WindowsFeature -Name Web-DAV-Publishing
# FTP'yi kullanmıyorsanız kaldır
Remove-WindowsFeature -Name Web-Ftp-Server
# CGI gereksizse kaldır
Remove-WindowsFeature -Name Web-CGI
WebDAV özellikle dikkat edilmesi gereken bir bileşen. PUT ve DELETE HTTP metodlarına izin verdiği için yanlış konfigürasyonda saldırganın sunucuya dosya yazmasına imkan tanıyabilir.
Gereksiz HTTP Metodlarını Devre Dışı Bırakma
Web uygulamanız sadece GET ve POST kullanıyorsa diğer metodları neden açık bırakasınız? TRACE metodu özellikle XST (Cross-Site Tracing) saldırılarında kullanılır.
# web.config ile HTTP metodlarını kısıtla
# C:inetpubwwwrootweb.config dosyasına ekle
Add-WebConfigurationProperty -pspath 'MACHINE/WEBROOT/APPHOST' `
-filter "system.webServer/security/requestFiltering/verbs" `
-name "." `
-value @{verb='TRACE';allowed='false'}
Add-WebConfigurationProperty -pspath 'MACHINE/WEBROOT/APPHOST' `
-filter "system.webServer/security/requestFiltering/verbs" `
-name "." `
-value @{verb='OPTIONS';allowed='false'}
Add-WebConfigurationProperty -pspath 'MACHINE/WEBROOT/APPHOST' `
-filter "system.webServer/security/requestFiltering/verbs" `
-name "." `
-value @{verb='PUT';allowed='false'}
Add-WebConfigurationProperty -pspath 'MACHINE/WEBROOT/APPHOST' `
-filter "system.webServer/security/requestFiltering/verbs" `
-name "." `
-value @{verb='DELETE';allowed='false'}
Sunucu Bilgisi Sızdırmayı Engelleme
Bir pentest yaptığınızda ilk baktığınız şey sunucunun kendini nasıl tanıttığıdır. Varsayılan IIS kurulumunda response header’larına bakarsanız şunu görürsünüz:
Server: Microsoft-IIS/10.0X-Powered-By: ASP.NETX-AspNet-Version: 4.0.30319
Bu bilgiler saldırgana hedefini net gösterir. Hangi versiyona özgü açıkları arayacağını bilir. Bunu kapatmak şart.
# Server header'ını gizle
# ApplicationHost.config üzerinden
Import-Module WebAdministration
Set-WebConfigurationProperty -pspath 'MACHINE/WEBROOT/APPHOST' `
-filter "system.webServer/security/requestFiltering" `
-name "removeServerHeader" `
-value "True"
# X-Powered-By header'ını kaldır
Remove-WebConfigurationProperty -pspath 'MACHINE/WEBROOT/APPHOST' `
-filter "system.webServer/httpProtocol/customHeaders" `
-name "." `
-AtElement @{name='X-Powered-By'}
# ASP.NET versiyon header'ını kaldır
# web.config içine ekle
Set-WebConfigurationProperty -pspath 'MACHINE/WEBROOT/APPHOST/Default Web Site' `
-filter "system.web/httpRuntime" `
-name "enableVersionHeader" `
-value "False"
Özel Hata Sayfaları
Varsayılan IIS hata sayfaları da bilgi sızdırır. Stack trace görünüyorsa, veritabanı bağlantı string’i log’da çıkıyorsa, dosya yolları hata mesajında yer alıyorsa bunların hepsi saldırgan için ipucu. Özel hata sayfaları oluşturun:
# Özel hata sayfalarını ayarla
Set-WebConfigurationProperty -pspath 'MACHINE/WEBROOT/APPHOST/Default Web Site' `
-filter "system.web/customErrors" `
-name "mode" `
-value "RemoteOnly"
# 404 için özel sayfa
Add-WebConfigurationProperty -pspath 'MACHINE/WEBROOT/APPHOST' `
-filter "system.webServer/httpErrors" `
-name "." `
-value @{statusCode='404';subStatusCode='0';prefixLanguageFilePath='';path='/errors/404.html';responseMode='ExecuteURL'}
SSL/TLS Sertleştirmesi
Bu kısım gerçekten kritik. 2024’te hala TLS 1.0 ve TLS 1.1 kabul eden sunucular görüyorum. POODLE, BEAST, DROWN gibi saldırılar bu protokolleri hedef alır.
Registry üzerinden protokol yönetimi yapmak zorundayız. Bunu elle yapmak hata riski taşıdığından PowerShell script’i kullanın:
# TLS 1.0'ı devre dışı bırak
$tls10Path = "HKLM:SYSTEMCurrentControlSetControlSecurityProvidersSCHANNELProtocolsTLS 1.0"
New-Item -Path "$tls10PathServer" -Force
New-ItemProperty -Path "$tls10PathServer" -Name "Enabled" -Value 0 -PropertyType DWORD -Force
New-ItemProperty -Path "$tls10PathServer" -Name "DisabledByDefault" -Value 1 -PropertyType DWORD -Force
New-Item -Path "$tls10PathClient" -Force
New-ItemProperty -Path "$tls10PathClient" -Name "Enabled" -Value 0 -PropertyType DWORD -Force
New-ItemProperty -Path "$tls10PathClient" -Name "DisabledByDefault" -Value 1 -PropertyType DWORD -Force
# TLS 1.1'i devre dışı bırak
$tls11Path = "HKLM:SYSTEMCurrentControlSetControlSecurityProvidersSCHANNELProtocolsTLS 1.1"
New-Item -Path "$tls11PathServer" -Force
New-ItemProperty -Path "$tls11PathServer" -Name "Enabled" -Value 0 -PropertyType DWORD -Force
New-ItemProperty -Path "$tls11PathServer" -Name "DisabledByDefault" -Value 1 -PropertyType DWORD -Force
# TLS 1.2 ve 1.3'ü aktif bırak/yap
$tls12Path = "HKLM:SYSTEMCurrentControlSetControlSecurityProvidersSCHANNELProtocolsTLS 1.2"
New-Item -Path "$tls12PathServer" -Force
New-ItemProperty -Path "$tls12PathServer" -Name "Enabled" -Value 1 -PropertyType DWORD -Force
New-ItemProperty -Path "$tls12PathServer" -Name "DisabledByDefault" -Value 0 -PropertyType DWORD -Force
# SSL 2.0 ve 3.0'ı kesinlikle kapat
$ssl3Path = "HKLM:SYSTEMCurrentControlSetControlSecurityProvidersSCHANNELProtocolsSSL 3.0"
New-Item -Path "$ssl3PathServer" -Force
New-ItemProperty -Path "$ssl3PathServer" -Name "Enabled" -Value 0 -PropertyType DWORD -Force
Write-Host "Protokol ayarlari tamamlandi. Sunucuyu yeniden baslatın." -ForegroundColor Green
Bu değişiklikler sonrası sunucuyu yeniden başlatmanız gerekiyor. Canlı sistemlerde bunu maintenance window’a alın.
Zayıf Cipher Suite’leri Devre Dışı Bırakma
TLS versiyonunu sertleştirdiniz ama eski ve zayıf cipher suite’ler hala açıksa tam güvenli değilsiniz. RC4, DES, 3DES bunların hepsi çıkmalı:
# Zayıf cipher'ları devre dışı bırak
$ciphersToDisable = @(
"RC4 128/128",
"RC4 64/64",
"RC4 40/128",
"DES 56/56",
"Triple DES 168",
"NULL"
)
foreach ($cipher in $ciphersToDisable) {
$cipherPath = "HKLM:SYSTEMCurrentControlSetControlSecurityProvidersSCHANNELCiphers$cipher"
New-Item -Path $cipherPath -Force
New-ItemProperty -Path $cipherPath -Name "Enabled" -Value 0 -PropertyType DWORD -Force
Write-Host "$cipher devre disi birakildi" -ForegroundColor Yellow
}
Güvenlik HTTP Header’ları Ekleme
Modern web güvenliğinin önemli bir parçası da doğru HTTP güvenlik header’larını ayarlamak. XSS, clickjacking, MIME sniffing gibi saldırılara karşı browser seviyesinde koruma sağlarlar.
# Tüm güvenlik header'larını tek seferde ekle
$headers = @{
"X-Frame-Options" = "SAMEORIGIN"
"X-Content-Type-Options" = "nosniff"
"X-XSS-Protection" = "1; mode=block"
"Strict-Transport-Security" = "max-age=31536000; includeSubDomains"
"Referrer-Policy" = "strict-origin-when-cross-origin"
"Permissions-Policy" = "geolocation=(), microphone=(), camera=()"
}
foreach ($header in $headers.GetEnumerator()) {
# Varsa önce kaldır, sonra ekle
try {
Remove-WebConfigurationProperty -pspath 'MACHINE/WEBROOT/APPHOST' `
-filter "system.webServer/httpProtocol/customHeaders" `
-name "." `
-AtElement @{name=$header.Key} -ErrorAction SilentlyContinue
} catch {}
Add-WebConfigurationProperty -pspath 'MACHINE/WEBROOT/APPHOST' `
-filter "system.webServer/httpProtocol/customHeaders" `
-name "." `
-value @{name=$header.Key;value=$header.Value}
Write-Host "$($header.Key) header eklendi" -ForegroundColor Green
}
X-Frame-Options: SAMEORIGIN ile sitenizin başka sitelerde iframe içinde gösterilmesi engellenir, clickjacking saldırılarına karşı koruma sağlar.
Strict-Transport-Security yani HSTS ile tarayıcıya “bu siteye sadece HTTPS ile bağlan” diyorsunuz. Bir kez ziyaret eden kullanıcı 1 yıl boyunca HTTP üzerinden gelmez.
Content-Security-Policy header’ı ayrıca değerlendirmeyi hak ediyor çünkü her uygulama için özelleştirilmesi gerekiyor. Hazır bir değer koymak yerine uygulamanızın ihtiyacına göre ayarlayın.
Request Filtering ile Saldırı Önleme
IIS’in Request Filtering modülü kötü istekleri uygulama katmanına bile ulaşmadan engelleyebilir. Bu çok güçlü bir özellik.
# Request Filtering genel ayarları
$rfPath = 'MACHINE/WEBROOT/APPHOST'
$rfFilter = "system.webServer/security/requestFiltering"
# Maksimum URL uzunluğunu sınırla (varsayılan 260, bunu azalt)
Set-WebConfigurationProperty -pspath $rfPath `
-filter "$rfFilter/requestLimits" `
-name "maxUrl" `
-value 2048
# Maksimum query string uzunluğunu sınırla
Set-WebConfigurationProperty -pspath $rfPath `
-filter "$rfFilter/requestLimits" `
-name "maxQueryString" `
-value 2048
# Maksimum içerik uzunluğu (10MB = 10485760 byte)
Set-WebConfigurationProperty -pspath $rfPath `
-filter "$rfFilter/requestLimits" `
-name "maxAllowedContentLength" `
-value 10485760
# Çift nokta kodlamasını engelle (path traversal saldırıları)
Set-WebConfigurationProperty -pspath $rfPath `
-filter $rfFilter `
-name "allowDoubleEscaping" `
-value "False"
# Yüksek bit karakterlerine izin verme
Set-WebConfigurationProperty -pspath $rfPath `
-filter $rfFilter `
-name "allowHighBitCharacters" `
-value "False"
Write-Host "Request filtering ayarlari tamamlandi" -ForegroundColor Green
Hassas Dosyalara Erişimi Engelleme
Web root altında .git, .env, web.config gibi hassas dosyalar veya dizinler varsa bunlara dışarıdan erişim engellenmelidir. Bir müşterimizin sunucusunda .git dizini açıktı ve kaynak kodu tamamen indirilebilir durumdaydı.
# Gizli dosya uzantılarına erişimi engelle
$extensionsToBlock = @(".bak", ".config", ".sql", ".fla", ".psd", ".ini", ".log", ".sh", ".inc", ".swp", ".dist")
foreach ($ext in $extensionsToBlock) {
Add-WebConfigurationProperty -pspath 'MACHINE/WEBROOT/APPHOST' `
-filter "system.webServer/security/requestFiltering/fileExtensions" `
-name "." `
-value @{fileExtension=$ext;allowed='false'}
Write-Host "$ext uzantisi engellendi" -ForegroundColor Yellow
}
# .git dizinine erişimi engelle
Add-WebConfigurationProperty -pspath 'MACHINE/WEBROOT/APPHOST' `
-filter "system.webServer/security/requestFiltering/hiddenSegments" `
-name "." `
-value @{segment='.git'}
Add-WebConfigurationProperty -pspath 'MACHINE/WEBROOT/APPHOST' `
-filter "system.webServer/security/requestFiltering/hiddenSegments" `
-name "." `
-value @{segment='.env'}
Uygulama Havuzu Güvenliği
Uygulama havuzlarını doğru yapılandırmak izolasyon açısından kritik. Bir uygulamanın ele geçirilmesi diğerlerini etkilememeli.
Her web sitesi için ayrı bir uygulama havuzu oluşturun ve Network Service yerine daha kısıtlı bir hesap kullanın. Mümkünse her uygulama için ayrı bir servis hesabı tanımlayın.
# Uygulama havuzu kimlik tipini ApplicationPoolIdentity olarak ayarla
# Bu en güvenli seçenek, ayrı bir hesap oluşturmaya gerek kalmaz
Set-WebConfigurationProperty -pspath 'MACHINE/WEBROOT/APPHOST' `
-filter "system.applicationHost/applicationPools/add[@name='DefaultAppPool']/processModel" `
-name "identityType" `
-value "ApplicationPoolIdentity"
# Boşta kalma süresini ayarla (dakika cinsinden, 0 = hiç kapanma)
Set-WebConfigurationProperty -pspath 'MACHINE/WEBROOT/APPHOST' `
-filter "system.applicationHost/applicationPools/add[@name='DefaultAppPool']/recycling/periodicRestart" `
-name "time" `
-value "00:00:00"
# Maksimum worker process sayısını sınırla
Set-WebConfigurationProperty -pspath 'MACHINE/WEBROOT/APPHOST' `
-filter "system.applicationHost/applicationPools/add[@name='DefaultAppPool']" `
-name "maxProcesses" `
-value 1
# 32-bit uygulama çalıştırmayı gerekli değilse kapat
Set-WebConfigurationProperty -pspath 'MACHINE/WEBROOT/APPHOST' `
-filter "system.applicationHost/applicationPools/add[@name='DefaultAppPool']" `
-name "enable32BitAppOnWin64" `
-value "False"
IIS Loglama ve İzleme
Güvenlik olaylarını yakalayamazsanız saldırıyı fark edemezsiniz. IIS loglarını doğru yapılandırmak ve merkezi bir yere göndermek şart.
# Loglama ayarlarını güçlendir
# Tüm alanları logla
Set-WebConfigurationProperty -pspath 'MACHINE/WEBROOT/APPHOST' `
-filter "system.applicationHost/sites/siteDefaults/logFile" `
-name "logExtFileFlags" `
-value "Date,Time,ClientIP,UserName,ServerIP,Method,UriStem,UriQuery,HttpStatus,Win32Status,TimeTaken,ServerPort,UserAgent,Referer,HttpSubStatus"
# Log boyutunu sınırla ve günlük rotation yap
Set-WebConfigurationProperty -pspath 'MACHINE/WEBROOT/APPHOST' `
-filter "system.applicationHost/sites/siteDefaults/logFile" `
-name "period" `
-value "Daily"
# Failed Request Tracing'i aktif et
# Bu özellik 400-500 hataları detaylı loglar
Enable-WebRequestTracing -Name "Default Web Site"
Write-Host "Loglama ayarlari tamamlandi. Log dizini: C:inetpublogs" -ForegroundColor Green
Logları sadece yerel tutmak yetmez. Windows Event Forwarding veya bir SIEM çözümü kullanarak logları merkezi bir yere gönderin. Sunucunuz ele geçirilirse loglar silinebilir.
Windows Firewall ile IIS Koruması
IIS sertleştirme sadece IIS ayarlarıyla bitmez. Firewall katmanını da doğru yapılandırmanız lazım.
# Sadece 80 ve 443 portlarına dışarıdan erişime izin ver
# Önce gereksiz kuralları kaldır, sonra sadece gerekenleri ekle
# HTTP trafiği
New-NetFirewallRule -DisplayName "IIS HTTP" `
-Direction Inbound `
-Protocol TCP `
-LocalPort 80 `
-Action Allow
# HTTPS trafiği
New-NetFirewallRule -DisplayName "IIS HTTPS" `
-Direction Inbound `
-Protocol TCP `
-LocalPort 443 `
-Action Allow
# IIS Yönetim Servisine sadece yönetim ağından erişim
New-NetFirewallRule -DisplayName "IIS Management Restricted" `
-Direction Inbound `
-Protocol TCP `
-LocalPort 8172 `
-RemoteAddress "192.168.10.0/24" `
-Action Allow
# Tüm diğer gelen trafiği engelle (bu son kural olmalı)
Set-NetFirewallProfile -Profile Domain,Public,Private -DefaultInboundAction Block
Gerçek Dünya: Sertleştirme Sonrası Kontrol
Tüm bu değişiklikleri yaptıktan sonra gerçekten çalışıp çalışmadığını doğrulamanız gerekiyor. Birkaç pratik kontrol yöntemi:
SSL Labs testi için ssllabs.com/ssltest adresine gidin, domain’inizi girin ve A+ almayı hedefleyin. TLS konfigürasyonunuz doğruysa bu skora ulaşırsınız.
SecurityHeaders.com ile HTTP header’larınızı kontrol edin. Eklediğiniz güvenlik header’larının gerçekten gönderilip gönderilmediğini gösteriri.
Curl ile hızlı kontrol yapın:
# Response header'larını kontrol et
curl -I -k https://yourdomain.com
# TRACE metodunun engellendiğini doğrula
curl -v -X TRACE https://yourdomain.com
# Hassas dosyaya erişimin engellendiğini doğrula
curl -v https://yourdomain.com/web.config
# TLS versiyonunu test et
openssl s_client -connect yourdomain.com:443 -tls1
# Bu bağlantı başarısız olmalı, TLS 1.0 kapatıldıysa
Tüm bu testleri düzenli otomatize etmek için bir script yazıp zamanlanmış görev olarak çalıştırabilirsiniz.
Sonuç
IIS sertleştirme bir kerelik yapılan bir iş değil. Windows güncellemeleri bazen bazı ayarları sıfırlayabilir, yeni özellikler eklendikçe yeni saldırı vektörleri ortaya çıkabilir. Bu yüzden bu işlemleri dokümante edin, düzenli aralıklarla kontrol edin ve her büyük Windows Update sonrasında kritik ayarları tekrar gözden geçirin.
Özetlemek gerekirse sertleştirme sürecinizde şu sırayı izleyin: Önce gereksiz özellikleri kaldırın, ardından bilgi sızdırmayı engelleyin, SSL/TLS’i sıkılaştırın, güvenlik header’larını ekleyin, request filtering’i yapılandırın, uygulama havuzlarını izole edin ve loglama altyapısını güçlendirin. Bu adımları eksiksiz uyguladığınızda sunucunuz sıradan taramalara ve otomatize saldırılara karşı çok daha dirençli hale gelecek.
Hedefiniz saldırıyı tamamen sıfırlamak değil, saldırganın işini mümkün olduğunca zorlaştırmak ve bir şeyler olduğunda anında haberdar olmak. Güvenlik bir ürün değil, sürekli devam eden bir süreç.