Apache mod_security ile WAF Kurulumu ve Kural Yazımı

Web uygulamalarını hedef alan saldırılar her geçen gün daha karmaşık bir hal alıyor. SQL injection, XSS, path traversal gibi klasik saldırı vektörleri hâlâ aktif olarak kullanılıyor ve basit bir güvenlik açığı tüm sunucunuzu tehlikeye atabilir. İşte tam bu noktada Apache’nin mod_security modülü devreye giriyor. Açık kaynaklı bir WAF (Web Application Firewall) olan mod_security, HTTP trafiğini gerçek zamanlı olarak analiz ederek zararlı istekleri engellemenizi sağlıyor. Bu yazıda kurulumdan kural yazımına kadar her şeyi ele alacağız.

mod_security Nedir ve Nasıl Çalışır?

mod_security, Apache HTTP sunucusu için geliştirilmiş bir web uygulama güvenlik duvarı modülüdür. Nginx ve IIS için de versiyonları mevcut, ancak Apache entegrasyonu en olgun haliyle burada karşımıza çıkıyor. Temelde HTTP isteklerini ve yanıtlarını belirli kurallara göre inceliyor; şüpheli istekleri loglayabiliyor, engelleyebiliyor ya da yönlendirebiliyor.

Çalışma prensibi oldukça basit: Her HTTP isteği Apache’ye ulaşmadan önce mod_security filtresinden geçiyor. Kural setleri bu isteklerin header bilgilerini, body içeriğini, query string parametrelerini ve cookie değerlerini analiz ediyor. Bir kural tetiklendiğinde tanımladığınız aksiyona göre istek loglanıyor ya da engelleniyor.

Önemli not: mod_security tek başına yeterli bir güvenlik katmanı değildir. Düzenli yazılım güncellemeleri, güçlü kimlik doğrulama ve doğru sunucu konfigürasyonuyla birlikte çalışmalıdır.

Kurulum

Ubuntu/Debian Sistemlerde Kurulum

# Önce sistemi güncelleyelim
sudo apt update && sudo apt upgrade -y

# mod_security ve Apache geliştirme araçlarını yükleyelim
sudo apt install libapache2-mod-security2 -y

# Modülü etkinleştirelim
sudo a2enmod security2

# Apache'yi yeniden başlatalım
sudo systemctl restart apache2

# Modülün yüklendiğini doğrulayalım
sudo apachectl -M | grep security

CentOS/RHEL/Rocky Linux Sistemlerde Kurulum

# EPEL reposunu ekleyelim
sudo dnf install epel-release -y

# mod_security'yi yükleyelim
sudo dnf install mod_security mod_security_crs -y

# Apache'yi yeniden başlatalım
sudo systemctl restart httpd

# Servis durumunu kontrol edelim
sudo systemctl status httpd

Kurulum tamamlandıktan sonra mod_security varsayılan olarak detection-only modunda çalışmaya başlar. Bu mod, kuralları tetikleyen istekleri sadece loglar, engellemez. Üretime geçmeden önce bu modda bir süre çalıştırıp false positive’leri temizlemenizi şiddetle tavsiye ederim.

Temel Konfigürasyon

Ana Konfigürasyon Dosyasını Düzenleme

Ubuntu’da konfigürasyon dosyası /etc/apache2/mods-enabled/security2.conf altında bulunur. CentOS’ta ise /etc/httpd/conf.d/mod_security.conf yolunu kullanırsınız.

# Mevcut konfigürasyon dosyasını yedekleyelim
sudo cp /etc/modsecurity/modsecurity.conf-recommended /etc/modsecurity/modsecurity.conf

# Konfigürasyon dosyasını düzenleyelim
sudo nano /etc/modsecurity/modsecurity.conf

Dosyanın içinde ilk yapmanız gereken şey motoru etkinleştirmek:

# Bu satırı bulun ve değiştirin:
# SecRuleEngine DetectionOnly
# Şu hale getirin:
SecRuleEngine On

# Request body işlemeyi etkinleştirin
SecRequestBodyAccess On

# Maksimum request body boyutunu ayarlayın (byte cinsinden)
SecRequestBodyLimit 13107200
SecRequestBodyNoFilesLimit 131072

# Response body işlemeyi etkinleştirin
SecResponseBodyAccess On
SecResponseBodyLimit 524288

# Audit log ayarları
SecAuditEngine RelevantOnly
SecAuditLogRelevantStatus "^(?:5|4(?!04))"
SecAuditLogParts ABIJDEFHZ
SecAuditLog /var/log/apache2/modsec_audit.log

# Debug log seviyesi (production'da 0 yapın)
SecDebugLogLevel 0
SecDebugLog /var/log/apache2/modsec_debug.log

OWASP CRS (Core Rule Set) Kurulumu

mod_security’nin gerçek gücü kural setlerinden geliyor. OWASP tarafından geliştirilen CRS, endüstri standardı haline gelmiş kapsamlı bir kural koleksiyonudur.

# CRS'yi indirin
cd /tmp
wget https://github.com/coreruleset/coreruleset/archive/v3.3.5.tar.gz
tar -xvzf v3.3.5.tar.gz

# CRS dosyalarını doğru konuma taşıyın
sudo mv coreruleset-3.3.5 /etc/modsecurity/crs

# CRS konfigürasyon dosyasını hazırlayın
sudo cp /etc/modsecurity/crs/crs-setup.conf.example /etc/modsecurity/crs/crs-setup.conf

# Apache konfigürasyonuna CRS'yi dahil edin
sudo nano /etc/apache2/mods-enabled/security2.conf

security2.conf dosyasına şu satırları ekleyin:

# Temel konfigürasyonu yükle
IncludeOptional /etc/modsecurity/*.conf

# CRS setup dosyasını yükle
Include /etc/modsecurity/crs/crs-setup.conf

# CRS kurallarını yükle
Include /etc/modsecurity/crs/rules/*.conf

Apache’yi yeniden başlatıp hata olmadığını kontrol edin:

sudo apache2ctl configtest
sudo systemctl restart apache2

Özel Kural Yazımı

Kural yazımı mod_security’nin en güçlü ve en az belgelenmiş taraflarından biri. Temel sözdizimini anladıktan sonra çok spesifik güvenlik politikaları oluşturabilirsiniz.

Kural Sözdizimi

Bir mod_security kuralının temel yapısı şöyledir:

SecRule DEĞIŞKEN OPERATOR [AKSIYON]
  • DEĞIŞKEN: Neyin inceleneceği (REQUEST_URI, ARGS, REQUEST_HEADERS, vb.)
  • OPERATOR: Nasıl karşılaştırılacağı (@rx, @contains, @beginsWith, vb.)
  • AKSIYON: Kural tetiklendiğinde ne yapılacağı (deny, log, pass, vb.)

Pratik Kural Örnekleri

Özel kurallarınız için ayrı bir dosya oluşturun:

sudo nano /etc/modsecurity/custom_rules.conf
# =============================================
# ÖZEL GÜVENLİK KURALLARI
# =============================================

# Kural 1: Basit SQL Injection koruması
# ARGS değişkenindeki SQL anahtar kelimelerini yakala
SecRule ARGS "@rx (?i)(union|select|insert|update|delete|drop|truncate|exec|execute)" 
    "id:10001,
    phase:2,
    deny,
    status:403,
    log,
    msg:'SQL Injection girişimi tespit edildi',
    tag:'attack-sqli',
    severity:'CRITICAL'"

# Kural 2: XSS saldırısı engelleme
SecRule ARGS "@rx (?i)(<script|javascript:|vbscript:|onload=|onerror=|onclick=)" 
    "id:10002,
    phase:2,
    deny,
    status:403,
    log,
    msg:'XSS saldırisi tespit edildi',
    tag:'attack-xss',
    severity:'HIGH'"

# Kural 3: Path traversal engelleme
SecRule REQUEST_URI "@rx (?:../|..\)" 
    "id:10003,
    phase:1,
    deny,
    status:403,
    log,
    msg:'Path traversal girişimi',
    tag:'attack-lfi',
    severity:'HIGH'"

# Kural 4: Belirli User-Agent'ları engelle
SecRule REQUEST_HEADERS:User-Agent "@rx (?i)(nikto|sqlmap|nmap|masscan|zgrab)" 
    "id:10004,
    phase:1,
    deny,
    status:403,
    log,
    msg:'Zararlı tarayıcı/araç tespit edildi',
    tag:'attack-scanner',
    severity:'MEDIUM'"

# Kural 5: Boş User-Agent engelleme (bot koruması)
SecRule REQUEST_HEADERS:User-Agent "@rx ^$" 
    "id:10005,
    phase:1,
    deny,
    status:403,
    log,
    msg:'Boş User-Agent engellendi'"

# Kural 6: Belirli IP adresini tamamen engelle
SecRule REMOTE_ADDR "@ipMatch 192.168.1.100,10.0.0.50" 
    "id:10006,
    phase:1,
    deny,
    status:403,
    log,
    msg:'Engellenen IP adresinden erişim girişimi'"

# Kural 7: Rate limiting benzeri kural - çok fazla 404
# Bu kural tek başına yetmez, mod_evasive ile birlikte kullanılmalı
SecRule RESPONSE_STATUS "@rx ^404$" 
    "id:10007,
    phase:5,
    pass,
    log,
    msg:'404 yanıtı verildi - olası tarama aktivitesi'"

Gelişmiş Kural Teknikleri

#### Zincirleme Kurallar (Chained Rules)

Birden fazla koşulun aynı anda sağlanması gerektiği durumlarda kural zincirleme kullanılır:

# Hem POST isteği hem de belirli bir path'e gelen SQL injection girişimi
SecRule REQUEST_METHOD "@streq POST" 
    "id:10010,
    phase:2,
    chain,
    log,
    msg:'POST ile SQL Injection girişimi'"
    SecRule REQUEST_URI "@beginsWith /admin" 
        "chain"
        SecRule ARGS "@rx (?i)(union.*select|select.*from)" 
            "deny,
            status:403"

#### Değişken Kullanımı ve Collection’lar

# TX (Transaction) değişkeni ile sayaç oluşturma
SecRule ARGS "@rx (?i)(union|select)" 
    "id:10015,
    phase:2,
    pass,
    setvar:tx.sql_score=+1,
    log,
    msg:'SQL keyword tespit edildi - skor artırıldı'"

# Skor belirli bir eşiği geçince engelle
SecRule TX:SQL_SCORE "@gt 5" 
    "id:10016,
    phase:2,
    deny,
    status:403,
    log,
    msg:'SQL Injection skoru eşiği aşıldı'"

False Positive Yönetimi

Bu konu, pek çok sysadmin’in mod_security’yi bırakmasına neden olan en kritik sorundur. Agresif kural setleri meşru kullanıcıları da engelleyebilir.

Belirli Kuralları Devre Dışı Bırakma

# Belirli bir kural ID'sini whitelist'e al
SecRuleRemoveById 981176

# Birden fazla kural ID'sini devre dışı bırak
SecRuleRemoveById 981176 981245 981318

# Belirli bir path için kural devre dışı bırak
<Location /wp-admin>
    SecRuleRemoveById 981176
    SecRuleRemoveById 960024
</Location>

# Belirli bir kural için sadece belirli parametreyi hariç tut
SecRuleUpdateTargetById 981176 "!ARGS:editor_content"

VirtualHost Bazında Konfigürasyon

sudo nano /etc/apache2/sites-available/example.com.conf
<VirtualHost *:443>
    ServerName example.com
    DocumentRoot /var/www/example.com

    # Bu site için mod_security'yi özelleştir
    <IfModule mod_security2.c>
        # Paranoya seviyesini düşür (1-4 arası, varsayılan 1)
        SecAction 
            "id:900000,
            phase:1,
            nolog,
            pass,
            t:none,
            setvar:tx.paranoia_level=1"

        # WordPress için gerekli istisnaları tanımla
        SecRuleRemoveById 920170
        SecRuleRemoveById 949110

        # API endpoint'i için body limit artır
        <Location /api/upload>
            SecRequestBodyLimit 52428800
        </Location>
    </IfModule>

    SSLEngine on
    SSLCertificateFile /etc/ssl/certs/example.com.crt
    SSLCertificateKeyFile /etc/ssl/private/example.com.key
</VirtualHost>

Log Analizi ve İzleme

Audit Log Okuma

mod_security audit logları oldukça detaylıdır ama biraz karmaşık görünebilir:

# Anlık log takibi
sudo tail -f /var/log/apache2/modsec_audit.log

# Engellenen istekleri filtrele
sudo grep "Access denied" /var/log/apache2/error.log

# Belirli bir kural ID'sinin kaç kez tetiklendiğini say
sudo grep "id "10001"" /var/log/apache2/modsec_audit.log | wc -l

# En çok tetiklenen kuralları bul
sudo grep -oP 'id "K[0-9]+' /var/log/apache2/modsec_audit.log | sort | uniq -c | sort -rn | head -20

# Belirli bir IP adresinin aktivitelerini filtrele
sudo grep "192.168.1.100" /var/log/apache2/modsec_audit.log

Gerçek Dünya Senaryosu: WordPress Koruması

WordPress siteleri sürekli saldırı altındadır. İşte spesifik WordPress koruma kuralları:

sudo nano /etc/modsecurity/wordpress_rules.conf
# WordPress xmlrpc.php'ye brute force koruması
SecRule REQUEST_URI "@contains /xmlrpc.php" 
    "id:20001,
    phase:1,
    deny,
    status:403,
    log,
    msg:'WordPress xmlrpc.php erişimi engellendi'"

# wp-config.php'ye doğrudan erişim engelleme
SecRule REQUEST_URI "@rx wp-config.php" 
    "id:20002,
    phase:1,
    deny,
    status:403,
    log,
    msg:'wp-config.php erişim girişimi'"

# Hassas WordPress dosyalarına erişim engelleme
SecRule REQUEST_URI "@rx .(htaccess|htpasswd|ini|log|sh|sql|bak)$" 
    "id:20003,
    phase:1,
    deny,
    status:403,
    log,
    msg:'Hassas dosyaya erişim girişimi'"

# WordPress login sayfasına izin ver ama POST'u kısıtla
SecRule REQUEST_URI "@contains /wp-login.php" 
    "id:20004,
    phase:2,
    chain,
    log"
    SecRule REQUEST_METHOD "@streq POST" 
        "setvar:ip.login_count=+1,
        expirevar:ip.login_count=300"

# 5 dakika içinde 10'dan fazla login denemesini engelle
SecRule IP:LOGIN_COUNT "@gt 10" 
    "id:20005,
    phase:2,
    deny,
    status:429,
    log,
    msg:'WordPress brute force girişimi engellendi'"

Performans Optimizasyonu

mod_security her isteği işlediği için performansa etkisi göz ardı edilemez. Birkaç pratik önlem:

# modsecurity.conf içinde performans ayarları
# Request body'yi geçici dosyaya yaz (büyük istekler için)
SecTmpDir /tmp/
SecDataDir /tmp/

# Gereksiz response body incelemeyi kapat
SecResponseBodyAccess Off

# Sadece belirli MIME tiplerini incele
SecResponseBodyMimeType text/plain text/html text/xml application/json

# Bağlantı başına maksimum kural sayısını sınırla
SecPcreMatchLimit 1000
SecPcreMatchLimitRecursion 1000

Ayrıca, yüksek trafikli sitelerde mod_security’yi reverse proxy katmanında (örneğin bir Nginx WAF veya ayrı bir mod_security sunucusu) çalıştırmak, uygulama sunucusundaki yükü azaltır.

Test ve Doğrulama

Kurulum sonrası sisteminizin düzgün çalışıp çalışmadığını test etmeniz gerekiyor:

# Basit test - SQL injection denemesi (zararlı değil, sadece test)
curl -v "http://localhost/?id=1+UNION+SELECT+1,2,3--"

# XSS test
curl -v "http://localhost/?search=<script>alert(1)</script>"

# Path traversal test
curl -v "http://localhost/../../etc/passwd"

# Nikto scanner engeli testi
curl -v -A "Nikto" http://localhost/

# Başarılı engellemenin logda göründüğünü doğrula
sudo tail -20 /var/log/apache2/error.log | grep "ModSecurity"

Testlerde 403 yanıtı alıyorsanız ve logda ModSecurity kayıtları görüyorsanız, kurulumunuz doğru çalışıyor demektir.

Sonuç

mod_security, doğru yapılandırıldığında web uygulamalarınız için çok katmanlı güvenliğin önemli bir parçası haline gelir. Kurulumu birkaç dakika sürebilir ama asıl iş kural yönetimi ve false positive optimizasyonunda. Şunu her zaman aklınızda tutun: Önce DetectionOnly modunda çalıştırın, logları analiz edin, false positive’leri temizleyin, sonra production’a alın.

OWASP CRS gibi hazır kural setleri iyi bir başlangıç noktası sağlasa da uygulamanıza özel özel kurallar yazmak çok daha etkili sonuç verir. Özellikle WordPress, Magento veya özel bir e-ticaret uygulaması çalıştırıyorsanız, o platformun bilinen saldırı vektörlerine karşı özel kurallar geliştirmeniz güvenlik duruşunuzu önemli ölçüde iyileştirir.

Bir son tavsiye: mod_security loglarını düzenli olarak gözden geçirin. Neyin engellendiğini takip etmek, hem false positive’leri erken yakalamanızı hem de gerçek saldırı trendlerini görmenizi sağlar. Güvenlik pasif bir süreç değildir; sürekli dikkat ve iyileştirme gerektirir.

Yorum yapın