WordPress Siteniz Neden Saldırıya Uğruyor: Güvenlik Açıkları ve Çözümleri

Geçen ay bir müşterimin WordPress sitesine ne olduğunu anlattığımda gözlerine inanamadılar. Sabah 09:00’da normal bir site, öğleden sonra 14:00’te Google “Bu site zararlı yazılım içeriyor” uyarısı veriyor. Araya giren 5 saatte ne olmuştu? Cevap her zaman olduğu gibi basitti: temel güvenlik önlemleri alınmamıştı. Bu yazıda WordPress sitelerinin neden bu kadar kolay hedef haline geldiğini, saldırganların tam olarak neye baktığını ve bunu nasıl engelleyebileceğinizi konuşacağız.

WordPress Neden Bu Kadar Çok Saldırıya Uğruyor

İnternetin yaklaşık %43’ünü çalıştıran bir platform olduğunuzda hedef olmak kaçınılmaz. Ama asıl sorun popülerlik değil. Asıl sorun şu: WordPress kurulumlarının büyük çoğunluğu varsayılan ayarlarla çalışıyor, güncellemeler ihmal ediliyor ve “nasılsa küçük bir site, kim saldıracak ki” zihniyetiyle yönetiliyor.

Saldırganlar manuel olarak sizin sitenizi seçmiyor çoğu zaman. Botlar interneti sürekli tarıyor, belirli imzaları arıyor ve açık bulduklarında otomatik olarak exploit çalıştırıyor. Sitenizin büyüklüğünün bir önemi yok. Kripto madenciliği için sunucu kaynağına, spam göndermek için temiz bir IP adresine veya phishing sayfası barındırmak için güvenilir bir domaine ihtiyaçları var. Siz de bu ihtiyaçları karşılayan bir hedefsiniz.

Saldırganların İlk Baktığı Yerler

wp-login.php Brute Force Saldırıları

En yaygın saldırı vektörü hâlâ brute force. Bunu kendi sunucunuzun access loglarından görebilirsiniz:

grep "wp-login.php" /var/log/nginx/access.log | grep "POST" | awk '{print $1}' | sort | uniq -c | sort -rn | head -20

Çıktıda aynı IP’den saniyeler içinde yüzlerce istek görüyorsanız, aktif bir brute force saldırısı altındasınız demektir. Normal bir kullanıcı giriş sayfasına günde belki 2-3 kez istek atar. 500 kez atan bir IP, bot.

Fail2ban ile bu saldırıları otomatik engelleyebilirsiniz:

# /etc/fail2ban/filter.d/wordpress.conf
[Definition]
failregex = ^<HOST> .* "POST .*wp-login.php
ignoreregex =
# /etc/fail2ban/jail.local dosyasına ekleyin
[wordpress]
enabled = true
filter = wordpress
logpath = /var/log/nginx/access.log
maxretry = 5
findtime = 300
bantime = 3600

Fail2ban’ı yeniden başlatın:

systemctl restart fail2ban
fail2ban-client status wordpress

XML-RPC Açığı: Çoğunun Aklına Gelmeyen Arka Kapı

wp-login.php’yi korumaya aldınız, tebrikler. Peki ya xmlrpc.php? Bu dosya WordPress’in uzaktan yönetim API’si. Jetpack gibi eklentiler için gerekli ama saldırganlar için altın değerinde çünkü tek bir istek içinde binlerce kullanıcı adı/parola kombinasyonu deneyebiliyorlar. Buna “multicall brute force” deniyor ve normal rate limiting’i tamamen bypass ediyor.

XML-RPC’ye ihtiyacınız yoksa tamamen kapatın:

# Nginx konfigürasyonuna ekleyin
location = /xmlrpc.php {
    deny all;
    access_log off;
    log_not_found off;
}

Apache kullanıyorsanız .htaccess’e şunu ekleyin:

# .htaccess
<Files xmlrpc.php>
Order Deny,Allow
Deny from all
</Files>

Kapatmadan önce XML-RPC’nin kullanılıp kullanılmadığını kontrol edin:

grep "xmlrpc.php" /var/log/nginx/access.log | grep -v "404" | wc -l

Sıfır veya çok düşük bir sayı görüyorsanız, kapatmaktan çekinmeyin.

Eklenti ve Tema Güvenlik Açıkları

Gerçek şu ki WordPress çekirdeğinin kendisi son yıllarda oldukça güvenli hale geldi. Saldırıların ezici çoğunluğu eklentilerden ve temalardan geliyor. WPScan veritabanına bakarsanız her hafta onlarca yeni eklenti açığı yayınlandığını görürsünüz.

En tehlikeli kategoriler şunlar:

  • SQL Injection: Eklenti, kullanıcıdan gelen veriyi doğrudan veritabanı sorgusuna eklediğinde oluşur. Saldırgan veritabanınızı okuyabilir, kullanıcı bilgilerini çalabilir hatta admin hesabı oluşturabilir.
  • File Upload Bypass: Dosya yükleme fonksiyonu düzgün kontrol edilmezse PHP web shell yüklenebilir.
  • Cross-Site Scripting (XSS): Stored XSS durumunda saldırgan admin paneline zararlı JavaScript enjekte edebilir.
  • Privilege Escalation: Düşük yetkili bir kullanıcının admin yetkisi kazanmasını sağlayan açıklar.

Mevcut kurulumunuzu WPScan ile kontrol edebilirsiniz:

# WPScan kurulumu (Ruby gerektirir)
gem install wpscan

# Temel tarama
wpscan --url https://siteniz.com --enumerate p,t,u

# API token ile güncel açık veritabanını kullan
wpscan --url https://siteniz.com --api-token APITOKEN_BURAYA --enumerate ap,at,u

Bu taramayı kendi sitenize düzenli yapın. Başkasının yapmasını beklemeyin.

Güvenlik açığı bulunan eklentileri komut satırından güncellemek için WP-CLI kullanabilirsiniz:

# Tüm eklentileri güncelle
wp plugin update --all

# Belirli bir eklentiyi güncelle
wp plugin update woocommerce

# Güncelleme gerektiren eklentileri listele
wp plugin list --update=available --format=table

Dosya İzinleri: Sıkça Atlanan Ama Kritik Konu

WordPress kurulumlarında yanlış dosya izinleri hem güvenlik açığı hem de saldırı sonrası hasarı artıran bir faktör. Web sunucusu kullanıcısının her şeye yazma yetkisi olmamalı.

Doğru izinleri ayarlamak için:

# WordPress kurulum dizinine gidin
cd /var/www/html/wordpress

# Dizinler için 755
find . -type d -exec chmod 755 {} ;

# Dosyalar için 644
find . -type f -exec chmod 644 {} ;

# wp-config.php özel koruma
chmod 400 wp-config.php

# Sahipliği doğru ayarlayın (www-data yerine nginx veya apache olabilir)
chown -R www-data:www-data .

# Uploads dizini yazılabilir olmalı ama PHP çalıştırmamalı
chmod 755 wp-content/uploads

Uploads dizininde PHP çalışmasını engellemek kritik öneme sahip. Oraya yüklenen bir PHP dosyası doğrudan çalıştırılabilir hale gelirse, file upload saldırısı anında remote code execution’a dönüşür:

# Nginx: uploads dizininde PHP çalıştırmayı engelle
location ~* /uploads/.*.php$ {
    deny all;
}

wp-config.php ve Veritabanı Güvenliği

wp-config.php dosyası veritabanı şifresi, güvenlik anahtarları ve tablo prefix’ini içeriyor. Bu dosyaya yetkisiz erişim site güvenliğini tamamen çökertiyor.

Öncelikle bu dosyayı web root’unun dışına taşıyın:

# wp-config.php'yi bir üst dizine taşı
mv /var/www/html/wordpress/wp-config.php /var/www/wp-config.php

WordPress otomatik olarak bir üst dizinde arar. Nginx veya Apache konfigürasyonunda da doğrudan erişimi engelleyin:

# Nginx
location = /wp-config.php {
    deny all;
}

# .htaccess (Apache)
<files wp-config.php>
order allow,deny
deny from all
</files>

Veritabanı tablo prefix’ini varsayılan wp_ yerine rastgele bir değere almak SQL injection saldırılarını zorlaştırır. Mevcut bir kurulumda değiştirmek için:

# MySQL'e bağlan ve tabloları listele
mysql -u root -p wordpress_db -e "SHOW TABLES;"

# Prefix değiştirme scripti (ÖNCE YEDEK AL!)
mysql -u root -p wordpress_db << 'EOF'
RENAME TABLE wp_posts TO xk7m_posts;
RENAME TABLE wp_users TO xk7m_users;
RENAME TABLE wp_options TO xk7m_options;
-- Tüm tablolar için devam edin
EOF

wp-config.php içinde de prefix’i güncelleyin ve wp_usermeta ile wp_options tablolarındaki wp_ referanslarını da düzeltmeyi unutmayın. Bu işlem riskli, mutlaka tam yedek alarak yapın.

Gerçek Dünya Senaryosu: Bir Saldırı Nasıl İlerler

Teorik konuşmak yerine tipik bir saldırı zincirini açıklayayım. 2023’te destek verdiğim bir e-ticaret sitesinde yaşandı.

Saldırgan önce WPScan benzeri bir araçla siteyi taradı ve güncelliğini yitirmiş bir form eklentisi buldu. Bu eklentide authenticated stored XSS açığı vardı; yani herhangi bir kayıtlı kullanıcı (müşteri hesabı da dahil) zararlı JavaScript enjekte edebiliyordu. Saldırgan basit bir müşteri hesabı açtı, ürün yorumuna özel hazırlanmış bir script ekledi. Admin bu yorumu panel üzerinden onaylamaya gittiğinde saldırganın JavaScript’i çalıştı ve admin session cookie’si harici bir sunucuya gönderildi.

Buradan sonrası kolaydı: çalınan cookie ile admin paneline erişildi, uploads dizinine PHP web shell yüklendi ve sunucu ele geçirildi. Tüm süreç 20 dakikadan az sürdü.

Bu senaryoyu önlemenin yolları:

  • Eklentileri güncel tutmak (açık yamayı almıştı)
  • Content Security Policy header’ı ile XSS etkisini sınırlamak
  • Admin session’larına 2FA eklemek
  • Dosya upload’larını sunucu tarafında da doğrulamak

Güvenlik Header’ları ve Server Hardening

WordPress uygulaması güvenli olsa bile web sunucusu katmanında ek koruma katmanları ekleyebilirsiniz. Nginx için temel güvenlik header’ları:

# Nginx server bloğuna ekleyin
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-XSS-Protection "1; mode=block" always;
add_header X-Content-Type-Options "nosniff" always;
add_header Referrer-Policy "no-referrer-when-downgrade" always;
add_header Content-Security-Policy "default-src 'self' https: data: 'unsafe-inline' 'unsafe-eval'" always;
add_header Permissions-Policy "camera=(), microphone=(), geolocation=()" always;

# WordPress REST API'yi kısıtla (gerekli değilse)
location ~* /wp-json/wp/v2/users {
    deny all;
}

Bu son satır önemli: WordPress REST API varsayılan olarak tüm kullanıcı isimlerini herkese açık şekilde listeliyor. Saldırgan /wp-json/wp/v2/users endpoint’ine istek atarak admin kullanıcı adını öğrenebilir, sonra brute force’a girişebilir.

İzleme ve Erken Uyarı

Saldırıya uğradıktan sonra fark etmek yerine saldırı başlar başlamaz haberdar olmak çok daha değerli. Basit bir dosya bütünlüğü kontrolü kurun:

# WordPress core dosyalarının hash'lerini kaydet
find /var/www/html/wordpress -name "*.php" -not -path "*/wp-content/*" 
  -exec md5sum {} ; > /root/wordpress_hashes.txt

# Sonraki kontrolde değişen dosyaları bul
find /var/www/html/wordpress -name "*.php" -not -path "*/wp-content/*" 
  -exec md5sum {} ; | diff /root/wordpress_hashes.txt - | grep "^>"

Bu scripti cron’a ekleyerek düzenli çalıştırabilirsiniz:

# Crontab'a ekle: her gece 02:00'de kontrol et
0 2 * * * /root/check_wordpress_integrity.sh | mail -s "WordPress Integrity Check" [email protected]

Ayrıca yeni oluşturulan PHP dosyalarını gerçek zamanlı izlemek için inotifywait kullanabilirsiniz:

# inotify-tools kurulumu
apt-get install inotify-tools

# wp-content dizinini izle
inotifywait -m -r -e create,modify /var/www/html/wordpress/wp-content 
  --format '%T %w %f %e' --timefmt '%Y-%m-%d %H:%M:%S' | 
  grep -i ".php" >> /var/log/wordpress_file_changes.log

Yedekleme: Güvenlik Stratejisinin Parçası

Güvenlik sadece saldırıyı önlemek değil, saldırı gerçekleştiğinde hızlı toparlanabilmek de. Yedek olmadan saldırı sonrası temizlik hem zor hem de başarı garantisi olmayan bir işlem.

Otomatik WordPress yedeklemesi için basit bir script:

#!/bin/bash
# /root/backup_wordpress.sh

BACKUP_DIR="/backup/wordpress"
DATE=$(date +%Y%m%d_%H%M%S)
WP_DIR="/var/www/html/wordpress"
DB_NAME="wordpress_db"
DB_USER="wp_user"
DB_PASS="sifre_buraya"

mkdir -p $BACKUP_DIR

# Veritabanı yedeği
mysqldump -u $DB_USER -p$DB_PASS $DB_NAME | gzip > $BACKUP_DIR/db_$DATE.sql.gz

# Dosya yedeği (wp-content öncelikli)
tar -czf $BACKUP_DIR/files_$DATE.tar.gz -C $WP_DIR wp-content wp-config.php

# 30 günden eski yedekleri sil
find $BACKUP_DIR -name "*.gz" -mtime +30 -delete

echo "Yedekleme tamamlandi: $DATE"

Yedekleri aynı sunucuda tutmak, sunucunun ele geçirilmesi durumunda yedeğin de tehlikeye girmesi anlamına gelir. Offsite yedek kritik; S3, Backblaze B2 veya başka bir lokasyon kullanın.

Hızlı Kontrol Listesi

Bir WordPress sitesini devralırken veya mevcut sitenizi değerlendirirken bakmanız gerekenler:

  • WordPress çekirdeği güncel mi?: wp core check-update
  • Tüm eklentiler güncel mi?: wp plugin list --update=available
  • Aktif olmayan eklenti ve temalar silinmiş mi?: Devre dışı bırakmak yetmez, silin
  • Admin kullanıcı adı “admin” değil mi?: Hâlâ admin kullanıyorsanız değiştirin
  • Güçlü parola + 2FA var mı?: Her admin hesabı için zorunlu
  • wp-login.php rate limiting aktif mi?: Brute force koruması
  • XML-RPC kapalı mı?: İhtiyaç yoksa kapatın
  • Dosya izinleri doğru mu?: 644/755 kuralı
  • wp-config.php korumalı mı?: Web erişimi kapalı
  • Düzenli yedek alınıyor mu?: Ve yedekler test ediliyor mu?
  • Güvenlik header’ları var mı?: En azından temel olanlar
  • Loglar izleniyor mu?: Otomatik uyarı sistemi

Sonuç

WordPress güvenliği tek seferlik bir iş değil, sürekli bakım gerektiren bir süreç. Yukarıda anlattıklarımın hepsini bugün uygulasanız bile altı ay sonra eklenti açığı çıkabilir, yeni bir saldırı vektörü keşfedilebilir. Önemli olan sistemi kurmak ve rutini oturtmak: düzenli güncelleme, düzenli log inceleme, düzenli yedek testi.

Saldırıların büyük çoğunluğu fırsatçı. Temel önlemleri almış bir site, aynı sunucu üzerindeki korumasız siteye kıyasla saldırıya uğrama olasılığı dramatik biçimde daha düşük. Botlar en kolay hedefi seçer. Zor hedef olun.

Son bir not: Bir güvenlik ihlali yaşandığında panikleyip “temizleyip devam edelim” moduna girmeyin. Saldırganın nasıl girdiğini anlamadan temizlik yapmak, aynı kapıyı açık bırakmak demektir. Her ihlali bir post-mortem ile kapatın ve kök nedeni mutlaka tespit edin.

Bir yanıt yazın

E-posta adresiniz yayınlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir