Güvenli DNS: Windows Server’da DNS Filtreleme

Kurumsal ağlarda DNS, genellikle güvenlik açısından en çok göz ardı edilen bileşenlerden biridir. Oysa DNS filtreleme, kötü amaçlı yazılımların komuta-kontrol sunucularıyla iletişimini kesmekten tutun da kullanıcıların zararlı sitelere erişimini engellemeye kadar kritik bir savunma katmanı oluşturur. Windows Server üzerinde DNS filtrelemeyi doğru yapılandırmak, hem maliyetsiz hem de son derece etkili bir güvenlik önlemi olarak öne çıkar. Bu yazıda adım adım gerçek dünya senaryolarıyla Windows Server DNS filtrelemeyi ele alacağız.

DNS Filtreleme Neden Bu Kadar Önemli?

Düşün bir dakika: Bir kullanıcı farkında olmadan kimlik avı bağlantısına tıkladığında ilk ne olur? Tarayıcı, söz konusu domain için DNS sorgusu gönderir. Eğer bu noktada bir filtreleme mekanizman varsa, zararlı domain hiçbir zaman IP adresine çözümlenmez ve bağlantı kurulmadan tehdit bertaraf edilir.

Windows Server DNS’in built-in özellikleri birçok kurum için yeterli koruma sağlayabilir. Response Policy Zone (RPZ) desteği olmasa da PowerShell, DNS Manager politikaları ve üçüncü taraf entegrasyonlarıyla güçlü bir filtreleme altyapısı kurabilirsin.

Temel filtreleme senaryoları:

  • Bilinen zararlı domainlerin engellenmesi (malware, phishing, C2 sunucuları)
  • Kategoriye göre içerik filtrelemesi (sosyal medya, kumar, yetişkin içerik)
  • DNS tünelleme saldırılarının tespiti ve engellenmesi
  • Split-horizon DNS ile iç/dış kaynak ayrımı
  • Çalışan saatlerine göre dinamik filtreleme

Ortamın Hazırlanması

Önce mevcut DNS yapını kontrol edelim. Windows Server 2016 ve üzeri sürümler, DNS politikaları açısından çok daha yetenekli geldi. Hangi sürümde olduğunu kontrol et:

Get-WindowsFeature -Name DNS
$PSVersionTable.PSVersion
(Get-WmiObject Win32_OperatingSystem).Caption

DNS Server rolü yüklü değilse şu komutla kur:

Install-WindowsFeature -Name DNS -IncludeManagementTools -IncludeAllSubFeature
Import-Module DNSServer

Sonra mevcut DNS zone’larını ve yapılandırmayı görelim:

Get-DnsServer
Get-DnsServerZone
Get-DnsServerForwarder
Get-DnsServerCache

Bu çıktılar sana başlangıç noktasını verecek. Özellikle forwarder ayarlarına dikkat et. Çoğu kurumda forwarder olarak ISP’nin DNS adresleri girilmiş olur ki bu güvenlik açısından hiç ideal değildir.

DNS Politikası ile Temel Filtreleme

Windows Server 2016 ile birlikte gelen DNS Politikaları, belirli istemci gruplarına, saatlere veya sorgulara göre farklı yanıtlar döndürmeni sağlar. Bu, filtrelemenin temelidir.

Engellenecek Domain Listesi Oluşturma

Önce engellenecek domainleri tutacak bir yapı kur. Ben genellikle bir TXT dosyasından besleyen bir PowerShell scripti tercih ediyorum:

# Engellenecek domainleri dosyadan oku ve DNS zone olarak ekle
$blockedDomains = Get-Content "C:DNSblocked_domains.txt"
$dnsServer = $env:COMPUTERNAME

foreach ($domain in $blockedDomains) {
    $domain = $domain.Trim()
    if ($domain -and -not $domain.StartsWith("#")) {
        try {
            # Zone yoksa oluştur
            if (-not (Get-DnsServerZone -Name $domain -ErrorAction SilentlyContinue)) {
                Add-DnsServerPrimaryZone -Name $domain -ZoneFile "$domain.dns" -DynamicUpdate None
                Write-Host "Zone eklendi: $domain" -ForegroundColor Green
            }
            
            # SOA ve NS kayıtları otomatik eklenir, A kaydı ekle (sinkhole IP)
            Add-DnsServerResourceRecordA -ZoneName $domain -Name "@" -IPv4Address "0.0.0.0" -ErrorAction SilentlyContinue
            Add-DnsServerResourceRecordA -ZoneName $domain -Name "*" -IPv4Address "0.0.0.0" -ErrorAction SilentlyContinue
            
        } catch {
            Write-Warning "Hata - $domain : $($_.Exception.Message)"
        }
    }
}

Yukarıdaki script, zararlı domainler için local zone oluşturur ve bunları 0.0.0.0 adresine yönlendirir. Bu yönteme DNS Sinkhole denir. Wildcard A kaydı (*) sayesinde sub.zararlısite.com gibi alt domainler de engellenir.

Sinkhole IP Seçimi

0.0.0.0 yerine kendi ağında bir “uyarı sayfası” sunucusu kurabilirsin. Böylece kullanıcı engellenen siteye erişmeye çalıştığında boş bir sayfa yerine anlamlı bir uyarı mesajı görür:

# Uyarı sunucusu IP'si (kendi ortamında değiştir)
$sinkholeIP = "192.168.1.250"

# Mevcut zone'ların sinkhole IP'sini güncelle
$zones = Get-DnsServerZone | Where-Object {$_.ZoneFile -like "*.dns" -and $_.ZoneName -notlike "*.in-addr.arpa"}

foreach ($zone in $zones) {
    $records = Get-DnsServerResourceRecord -ZoneName $zone.ZoneName -RRType A -ErrorAction SilentlyContinue
    foreach ($record in $records) {
        if ($record.RecordData.IPv4Address.IPAddressToString -eq "0.0.0.0") {
            $newRecord = $record.Clone()
            $newRecord.RecordData.IPv4Address = [System.Net.IPAddress]::Parse($sinkholeIP)
            Set-DnsServerResourceRecord -ZoneName $zone.ZoneName -OldInputObject $record -NewInputObject $newRecord
        }
    }
}
Write-Host "Sinkhole IP guncellendi: $sinkholeIP"

DNS Politikalarıyla Gelişmiş Filtreleme

DNS politikaları, kural tabanlı çok daha esnek bir yapı sunar. Örneğin mesai saatleri dışında sosyal medya erişimini engellemek istiyorsun diyelim:

# Mesai saati dışı (18:00-08:00) sosyal medya engeli için politika
# Önce istemci subnet'i tanımla
Add-DnsServerClientSubnet -Name "InternalUsers" -IPv4Subnet "192.168.0.0/16"

# Zaman dilimi tanımla (mesai saatleri)
Add-DnsServerQueryResolutionPolicy `
    -Name "BlockSocialAfterHours" `
    -Action DENY `
    -ClientSubnet "EQ,InternalUsers" `
    -TimeOfDay "EQ,18:00-08:00" `
    -QName "EQ,*.facebook.com,*.twitter.com,*.instagram.com,*.tiktok.com" `
    -ProcessingOrder 1 `
    -PassThru

Politikanın aktif olduğunu doğrula:

Get-DnsServerQueryResolutionPolicy | Format-List Name, Action, ProcessingOrder, IsEnabled

Otomatik Blocklist Güncelleme Sistemi

Manuel liste yönetimi uzun vadede sürdürülemez. Ücretsiz tehdit istihbaratı kaynaklarından otomatik güncelleme yapan bir sistem kur:

# Tehdit istihbaratı kaynaklarından blocklist güncelleme scripti
# C:DNSUpdate-BlockList.ps1

param(
    [string]$BlockListPath = "C:DNSblocked_domains.txt",
    [string]$LogPath = "C:DNSLogsupdate_$(Get-Date -Format 'yyyyMMdd').log"
)

# Log dizini oluştur
if (-not (Test-Path (Split-Path $LogPath))) {
    New-Item -ItemType Directory -Path (Split-Path $LogPath) -Force | Out-Null
}

function Write-Log {
    param([string]$Message)
    $timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
    "$timestamp - $Message" | Tee-Object -FilePath $LogPath -Append
}

# Ücretsiz blocklist kaynakları
$sources = @(
    @{
        Name = "Malware Domain List"
        URL = "https://www.malwaredomainlist.com/hostslist/hosts.txt"
        Parser = {
            param($content)
            $content -split "`n" | Where-Object {$_ -match "^0.0.0.0s+"} |
            ForEach-Object {($_ -split "s+")[1]} |
            Where-Object {$_ -and $_ -ne "0.0.0.0"}
        }
    },
    @{
        Name = "StevenBlack Hosts"
        URL = "https://raw.githubusercontent.com/StevenBlack/hosts/master/hosts"
        Parser = {
            param($content)
            $content -split "`n" | Where-Object {$_ -match "^0.0.0.0s+" -and $_ -notmatch "localhost"} |
            ForEach-Object {($_ -split "s+")[1]} |
            Where-Object {$_ -and $_ -ne "0.0.0.0"}
        }
    }
)

$allDomains = @()

foreach ($source in $sources) {
    try {
        Write-Log "Indiriliyor: $($source.Name)"
        $content = Invoke-WebRequest -Uri $source.URL -TimeoutSec 60 -UseBasicParsing | Select-Object -ExpandProperty Content
        $domains = & $source.Parser $content
        $allDomains += $domains
        Write-Log "$($source.Name): $($domains.Count) domain bulundu"
    } catch {
        Write-Log "HATA - $($source.Name): $($_.Exception.Message)"
    }
}

# Tekrar edenleri temizle ve sırala
$uniqueDomains = $allDomains | Sort-Object -Unique
Write-Log "Toplam benzersiz domain: $($uniqueDomains.Count)"

# Dosyaya yaz
$uniqueDomains | Set-Content $BlockListPath -Encoding UTF8
Write-Log "Blocklist guncellendi: $BlockListPath"

Bu scripti Task Scheduler’a ekle:

# Scheduled Task olustur (her gece 02:00'de calistir)
$action = New-ScheduledTaskAction `
    -Execute "PowerShell.exe" `
    -Argument "-NonInteractive -ExecutionPolicy Bypass -File C:DNSUpdate-BlockList.ps1"

$trigger = New-ScheduledTaskTrigger -Daily -At "02:00"

$settings = New-ScheduledTaskSettingsSet `
    -ExecutionTimeLimit (New-TimeSpan -Hours 1) `
    -RestartCount 3 `
    -RestartInterval (New-TimeSpan -Minutes 10)

$principal = New-ScheduledTaskPrincipal -UserId "SYSTEM" -RunLevel Highest

Register-ScheduledTask `
    -TaskName "DNS-BlockList-Update" `
    -Action $action `
    -Trigger $trigger `
    -Settings $settings `
    -Principal $principal `
    -Description "DNS blocklist guncelleme gorevi"

Write-Host "Scheduled task olusturuldu."

DNS Tünelleme Tespiti

DNS tünelleme, saldırganların güvenlik duvarlarını atlatmak için DNS protokolünü veri kanalı olarak kullandığı gelişmiş bir tekniktir. Bunu tespit etmek için DNS sorgu loglarını analiz etmen gerekir.

Önce debug logging’i etkinleştir:

# DNS debug logging aktif et
Set-DnsServerDiagnostics `
    -All $true `
    -LogFilePath "C:WindowsSystem32dnsdns_debug.log" `
    -MaxMBFileSize 500

# Sadece kritik loglar istiyorsan (performans için tercih edilir)
Set-DnsServerDiagnostics `
    -Queries $true `
    -Answers $true `
    -SendPackets $true `
    -ReceivePackets $true `
    -LogFilePath "C:DNSLogsdns_queries.log" `
    -MaxMBFileSize 200

Şüpheli DNS aktivitesini analiz eden bir script:

# DNS tünelleme tespiti - anormal sorgu analizi
# C:DNSDetect-DNSTunnel.ps1

$logPath = "C:DNSLogsdns_queries.log"
$threshold_queryLength = 50    # 50 karakterden uzun subdomain sorgular
$threshold_queryCount = 100    # Dakikada 100'den fazla sorgu
$reportPath = "C:DNSReportstunnel_suspects_$(Get-Date -Format 'yyyyMMdd_HHmm').txt"

Write-Host "DNS tünelleme analizi basliyor..."

# Windows Event Log'dan DNS sorgularini oku (DNS debug log yerine Event Log kullaniyorsan)
$dnsEvents = Get-WinEvent -LogName "Microsoft-Windows-DNS-Server/Audit" -MaxEvents 10000 -ErrorAction SilentlyContinue

$suspiciousPatterns = @()

foreach ($event in $dnsEvents) {
    $message = $event.Message
    
    # Uzun subdomain tespiti (DNS tünelleme genellikle cok uzun subdomain kullanir)
    if ($message -match "QNAME:s+(S+)") {
        $queryName = $matches[1]
        $parts = $queryName.Split(".")
        
        foreach ($part in $parts) {
            if ($part.Length -gt $threshold_queryLength) {
                $suspiciousPatterns += [PSCustomObject]@{
                    Time = $event.TimeCreated
                    Type = "Uzun Subdomain"
                    Query = $queryName
                    SubdomainLength = $part.Length
                    Detail = "Subdomain $($part.Length) karakter uzunlugunda"
                }
            }
        }
        
        # Base64 benzeri karakter yogunlugu kontrolu
        if ($queryName -match "^[a-zA-Z0-9+/]{20,}") {
            $suspiciousPatterns += [PSCustomObject]@{
                Time = $event.TimeCreated
                Type = "Base64 Benzeri Sorgu"
                Query = $queryName
                SubdomainLength = $queryName.Length
                Detail = "Base64 kodlu icerik suptesi"
            }
        }
    }
}

if ($suspiciousPatterns.Count -gt 0) {
    Write-Warning "$($suspiciousPatterns.Count) suphueli DNS aktivitesi tespit edildi!"
    $suspiciousPatterns | Export-Csv $reportPath -NoTypeInformation -Encoding UTF8
    Write-Host "Rapor kaydedildi: $reportPath"
    
    # Email bildirimi gonder (SMTP ayarlarini degistir)
    # Send-MailMessage -To "[email protected]" -Subject "DNS Tunel Suphesi" -Body ($suspiciousPatterns | Out-String)
} else {
    Write-Host "Anormal aktivite tespit edilmedi." -ForegroundColor Green
}

Harici DNS Sunucularını Engelleme

Kullanıcıların DNS filtrelemeni bypass etmek için 8.8.8.8 gibi harici DNS sunucularını kullanmasını Windows Firewall ile engelle:

# Harici DNS sorgularini engelle (sadece kendi DNS sunucunu kullanmalarini zorla)
# Port 53 UDP ve TCP - kendi DNS sunucularin disindaki tum IP'lere blok

$internalDNSServers = @("192.168.1.10", "192.168.1.11")  # Kendi DNS IP'lerini gir

# Outbound DNS'i engelle
New-NetFirewallRule `
    -DisplayName "Block External DNS UDP" `
    -Direction Outbound `
    -Protocol UDP `
    -RemotePort 53 `
    -RemoteAddress "Any" `
    -Action Block `
    -Profile Any `
    -Enabled True

New-NetFirewallRule `
    -DisplayName "Block External DNS TCP" `
    -Direction Outbound `
    -Protocol TCP `
    -RemotePort 53 `
    -RemoteAddress "Any" `
    -Action Block `
    -Profile Any `
    -Enabled True

# Kendi DNS sunucularindan DNS'e izin ver (istisnalar)
foreach ($dnsIP in $internalDNSServers) {
    New-NetFirewallRule `
        -DisplayName "Allow Internal DNS UDP - $dnsIP" `
        -Direction Outbound `
        -Protocol UDP `
        -RemotePort 53 `
        -RemoteAddress $dnsIP `
        -Action Allow `
        -Profile Any `
        -Enabled True

    New-NetFirewallRule `
        -DisplayName "Allow Internal DNS TCP - $dnsIP" `
        -Direction Outbound `
        -Protocol TCP `
        -RemotePort 53 `
        -RemoteAddress $dnsIP `
        -Action Allow `
        -Profile Any `
        -Enabled True
}

Write-Host "Firewall kurallari olusturuldu. Sadece internal DNS kullanilabilir."

DNS over HTTPS (DoH) ile Bypass’ı Engelleme

Modern tarayıcılar DNS over HTTPS kullanarak DNS filtrelemeni tamamen atlayabilir. Windows’ta Group Policy ile bunu engelle:

# Registry uzerinden DoH'u devre disi birak (Windows 11 ve Server 2022 icin)
$regPath = "HKLM:SYSTEMCurrentControlSetServicesDnscacheParameters"

# DoH'u devre disi birak
Set-ItemProperty -Path $regPath -Name "EnableAutoDoh" -Value 0 -Type DWord

# Chrome'un dahili DoH'unu engellemek icin Group Policy Registry ayarlari
$chromePoliciesPath = "HKLM:SOFTWAREPoliciesGoogleChrome"
if (-not (Test-Path $chromePoliciesPath)) {
    New-Item -Path $chromePoliciesPath -Force | Out-Null
}
Set-ItemProperty -Path $chromePoliciesPath -Name "DnsOverHttpsMode" -Value "off" -Type String

# Firefox icin
$firefoxPoliciesPath = "HKLM:SOFTWAREPoliciesMozillaFirefox"
if (-not (Test-Path $firefoxPoliciesPath)) {
    New-Item -Path $firefoxPoliciesPath -Force | Out-Null
}
Set-ItemProperty -Path $firefoxPoliciesPath -Name "DNSOverHTTPS" -Value 0 -Type DWord

Write-Host "DoH politikalari uygulandı. Degisikliklerin etkili olmasi icin tarayiciyi yeniden baslatiniz."

DNS Önbellek Zehirlenmesine Karşı Önlemler

DNS cache poisoning, saldırganların DNS yanıtlarını tahrif ederek kullanıcıları sahte sitelere yönlendirdiği klasik bir saldırıdır. Windows Server DNS buna karşı bazı built-in korumalar sunar:

# DNSSEC dogrulama aktif et
Set-DnsServerRecursion `
    -Enable $true `
    -SecureResponse $true `
    -AdditionalTimeout 4 `
    -RetryInterval 3 `
    -Timeout 8

# Önbellek kirlenmesine karsi koruma
Set-DnsServerCache `
    -MaxTTL 1.00:00:00 `
    -MaxNegativeTtl 0:15:00 `
    -PollutionProtect $true `
    -LockingPercent 100 `
    -StoreEmptyAuthenticationResponse $true

# Randomized kaynak port (Kaminsky saldirilarini engeller)
# Bu Windows DNS Server'da varsayilan olarak aktif, dogrulamayi yap:
Get-DnsServerSetting | Select-Object SocketPoolSize, SocketPoolExcludedPortRanges

# Socket pool boyutunu artir (varsayilan 2500, artirmak guvenlik saglar)
Set-DnsServerSetting -SocketPoolSize 10000

Monitoring ve Raporlama

Yaptığın tüm bu yapılandırmanın işe yarayıp yaramadığını görmek için monitoring kritik. Event ID’leri ile DNS aktivitesini izle:

# DNS sorgu istatistikleri ve en cok engellenen domainleri raporla
# C:DNSReportsGenerate-DNSReport.ps1

$reportDate = Get-Date -Format "yyyy-MM-dd"
$reportPath = "C:DNSReportsDNS_Report_$reportDate.html"

# DNS sunucu istatistikleri
$stats = Get-DnsServerStatistics
$zoneCount = (Get-DnsServerZone).Count
$blockedZones = (Get-DnsServerZone | Where-Object {$_.ZoneFile -like "*.dns"}).Count

# HTML rapor olustur
$html = @"
<!DOCTYPE html>
<html>
<head><title>DNS Guvenlik Raporu - $reportDate</title>
<style>body{font-family:Arial;margin:20px} h2{color:#333} .stat{background:#f0f0f0;padding:10px;margin:5px}</style>
</head>
<body>
<h2>DNS Guvenlik Raporu - $reportDate</h2>
<div class='stat'><b>Toplam Zone Sayisi:</b> $zoneCount</div>
<div class='stat'><b>Engellenen Domain Zone:</b> $blockedZones</div>
<div class='stat'><b>Toplam Sorgu:</b> $($stats.Query.TotalQueries)</div>
<div class='stat'><b>Recursive Sorgu:</b> $($stats.Query.TotalQueriesRecursed)</div>
<div class='stat'><b>Baskari Sorgu:</b> $($stats.Query.TotalReferrals)</div>
</body>
</html>
"@

$html | Out-File $reportPath -Encoding UTF8
Write-Host "Rapor olusturuldu: $reportPath"

# Onemli Event ID'leri kontrol et
$criticalEvents = Get-WinEvent -FilterHashtable @{
    LogName = 'DNS Server'
    Level = 1,2,3  # Critical, Error, Warning
    StartTime = (Get-Date).AddHours(-24)
} -ErrorAction SilentlyContinue

if ($criticalEvents) {
    Write-Warning "Son 24 saatte $($criticalEvents.Count) kritik DNS eventi tespit edildi!"
    $criticalEvents | Select-Object TimeCreated, Id, Message | Format-Table -AutoSize
}

Gerçek Dünya Senaryosu: Fidye Yazılımı C2 Engellemesi

2022 yılında bir müşterimde yaşanan vakayı anlatayım. Çalışanlardan biri sahte bir fatura ekine tıkladı. Endpoint antivirus’u ilk yükleyiciyi yakalamadı. Ancak DNS filtreleme sistemi, zararlı yazılımın komuta-kontrol sunucusuna bağlanma girişimini anında kesti.

Olayın ardından geriye dönük log analizinde şunu gördük: Zararlı yazılım, update.microsoftsecurity-cdn.net ve telemetry.windowsupdate-cdn.net gibi meşru görünen ama tehdit istihbaratı listelerinde yer alan domainlere sorgu atmaya çalışmış. DNS sinkhole sayesinde bu sorgular 0.0.0.0‘a yönlendirilmiş ve C2 iletişimi hiç kurulamamış.

Bu vakadan çıkan en önemli ders şu: Threatfeed’leri güncel tut, wildcard engellemesini ihmal etme ve DNS loglarını düzenli izle.

Sonuç

Windows Server’da DNS filtreleme, katmanlı güvenlik mimarisinin vazgeçilmez bir parçasıdır. Anlattığımız yöntemleri özetleyecek olursak:

  • DNS Sinkhole ile zararlı domainleri hiçbir IP’ye çözümlenmeden engelle
  • DNS Politikaları ile zaman ve istemci bazlı dinamik kurallar uygula
  • Otomatik blocklist güncellemesi ile tehdit istihbaratını her gece sisteme entegre et
  • DNS tünelleme tespiti için uzun ve anormal sorguları analiz et
  • Firewall kuralları ile harici DNS bypass girişimlerini kes
  • DoH kısıtlaması ile tarayıcı bazlı filtreleme atlatma girişimlerini önle
  • DNS önbellek koruma ayarlarıyla cache poisoning saldırılarına karşı önlem al

Bu yapılandırmaları bir kez kurulsun ve unutulsun olarak bakma. DNS tehdit ortamı sürekli değişiyor. Aylık blocklist doğrulaması, haftalık log analizi ve her güvenlik olayının ardından kural gözden geçirmesi rutin haline gelmeli.

Son olarak şunu söylemeliyim: DNS filtreleme tek başına yeterli değil. Ama doğru yapılandırıldığında, saldırı zincirinin en kritik halkalarından birini koparıyor. Ve bu, fidye yazılımı, APT ya da basit phishing fark etmeksizin seni ciddi anlamda koruyor.

Yorum yapın