WordPress Versiyon Bilgisini Gizleme

WordPress sitenizi kurup yayına aldıktan sonra güvenlik konusunu düşünmeye başlıyorsunuz. Peki ya saldırganların ilk baktığı şeyin ne olduğunu hiç düşündünüz mü? Çoğu zaman bu, sitenizin hangi WordPress versiyonunu çalıştırdığıdır. Versiyon bilgisi açıkta kaldığında, bilinen güvenlik açıklarına sahip eski bir sürüm kullanıyorsanız saldırganlar bunu anında fark eder ve hedef alır. Bu yazıda WordPress versiyon bilgisini nerede sakladığını, neden gizlemeniz gerektiğini ve bunu functions.php üzerinden nasıl etkili şekilde yapabileceğinizi ele alacağız.

Neden Versiyon Bilgisini Gizlemeliyiz?

Güvenlik dünyasında “security through obscurity” yani belirsizlik yoluyla güvenlik tartışmalı bir kavramdır. Tek başına bir güvenlik yöntemi olarak kullanmak yanlıştır, ancak derinlemesine savunmanın bir parçası olarak değerlendirildiğinde kesinlikle mantıklıdır.

WordPress versiyon bilgisi varsayılan olarak birkaç farklı yerde açığa çıkar:

  • HTML kaynak kodundaki etiketi
  • wp-login.php sayfasının kaynak kodu
  • RSS ve Atom feed’lerindeki generator etiketi
  • readme.html dosyası (WordPress kurulum dizininde)
  • wp-json REST API endpoint’leri
  • Stil ve script dosyalarının URL’lerindeki ?ver= parametreleri

Bir saldırgan sitenizi taradığında ilk yaptığı şey bu bilgileri toplamaktır. WordPress 6.3 çalıştırdığınızı öğrendiğinde, o versiyona ait tüm bilinen CVE’leri (Common Vulnerabilities and Exposures) kontrol eder ve buna göre saldırı planlar. Versiyon bilgisini gizlemek bu işi zorlaştırır, imkansız kılmaz ama vakit kaybettirir ve çoğu otomatik tarayıcıyı geri çevirir.

functions.php’ye Neden Dokunuyoruz?

WordPress’te özelleştirmelerin merkezi functions.php dosyasıdır. Plugin kullanmadan, çekirdek dosyalara dokunmadan bu dosya üzerinden WordPress davranışlarını değiştirebilirsiniz. Çekirdek dosyaları düzenlemeniz kesinlikle önerilmez çünkü her WordPress güncellemesinde yaptığınız değişiklikler silinir. functions.php ise temanıza aittir ve güncellemelerden etkilenmez.

Önemli not: Eğer aktif temanızı doğrudan düzenliyorsanız, bir güncelleme geldiğinde değişiklikleriniz silinebilir. Bu yüzden her zaman bir child theme (alt tema) oluşturmanız ve değişikliklerinizi orada yapmanız önerilir.

functions.php Dosyasını Bulma ve Düzenleme

Dosyaya iki farklı şekilde erişebilirsiniz:

FTP/SFTP ile:

# SFTP bağlantısı kur
sftp [email protected]

# Tema dizinine git
cd /var/www/html/wp-content/themes/aktif-temaniz/

# Dosyayı indir
get functions.php

# Düzenleyip tekrar yükle
put functions.php

SSH ile doğrudan düzenleme:

# SSH ile bağlan
ssh [email protected]

# functions.php'yi düzenle
nano /var/www/html/wp-content/themes/aktif-temaniz/functions.php

# Değişiklikleri kaydet
# CTRL+X, Y, Enter

WP-CLI kullanıyorsanız:

# Aktif temayı öğren
wp theme list --status=active

# Tema dizinine git
cd $(wp theme path --active)

# Dosyayı düzenle
nano functions.php

Versiyon Bilgisini Gizleme Yöntemleri

1. Meta Generator Etiketini Kaldırma

HTML kaynak kodunda görünen etiketini kaldırmak için:

<?php
// WordPress generator meta etiketini kaldır
remove_action('wp_head', 'wp_generator');

// RSS feed'den de kaldır
add_filter('the_generator', '__return_empty_string');

Bu iki satır birlikte çalışır. remove_action HTML head bölümünden kaldırırken, add_filter ile RSS/Atom feed’lerindeki generator bilgisini boş string döndürerek temizliyoruz.

2. Script ve Style URL’lerinden Versiyon Parametrelerini Kaldırma

WordPress her script ve CSS dosyasının URL’sine ?ver=6.4 gibi bir parametre ekler. Bu parametre cache yönetimi için kullanılsa da versiyon bilgisini ele verir. Kaldırmak için:

<?php
// Script ve style dosyalarından versiyon parametresini kaldır
function wp_versiyonu_url_den_kaldir($src) {
    if (strpos($src, '?ver=') !== false) {
        $src = remove_query_arg('ver', $src);
    }
    return $src;
}
add_filter('style_loader_src', 'wp_versiyonu_url_den_kaldir', 9999);
add_filter('script_loader_src', 'wp_versiyonu_url_den_kaldir', 9999);

Dikkat: Bu yöntemi kullanırsanız tarayıcı cache’i doğru yönetemeyebilir. Eğer bir CDN veya caching plugin kullanıyorsanız bu adımı atlamayı düşünebilirsiniz.

3. WP-Login.php’den Versiyon Bilgisini Temizleme

Giriş sayfasının kaynak kodunda da versiyon bilgisi bulunabilir. Bunu temizlemek için:

<?php
// Login sayfası kaynak kodundaki versiyon bilgisini temizle
function login_sayfasi_versiyon_temizle() {
    remove_action('wp_head', 'wp_generator');
}
add_action('login_head', 'login_sayfasi_versiyon_temizle');

// Login sayfasına özel CSS versiyonunu da kaldır
function login_css_versiyon_kaldir($url) {
    if (false !== strpos($url, 'wp-login.php')) {
        return remove_query_arg('ver', $url);
    }
    return $url;
}
add_filter('style_loader_src', 'login_css_versiyon_kaldir');

4. REST API’den Versiyon Bilgisini Kaldırma

WordPress REST API, /wp-json/ endpoint’i üzerinden WordPress versiyonunu açığa çıkarabilir. Bu bilgiyi temizlemek için:

<?php
// REST API response'undan versiyon bilgisini kaldır
function rest_api_versiyon_gizle($response) {
    if (isset($response->data['namespaces'])) {
        // namespaces bilgisini koru ama generator bilgisini temizle
    }
    if (isset($response->data['description'])) {
        unset($response->data['description']);
    }
    // Versiyon bilgisini kaldır
    if (isset($response->data['wp_version'])) {
        unset($response->data['wp_version']);
    }
    return $response;
}
add_filter('rest_index', 'rest_api_versiyon_gizle');

5. Hepsini Bir Arada Kullanan Kapsamlı Fonksiyon

Yukarıdaki tüm yöntemleri temiz ve organize bir şekilde bir arada kullanan örnek:

<?php
/**
 * WordPress Güvenlik Sertleştirme - Versiyon Gizleme
 * Tüm versiyon açıklarını kapatır
 */

// 1. Meta generator'ı kaldır
remove_action('wp_head', 'wp_generator');

// 2. Feed generator'ı temizle
add_filter('the_generator', '__return_empty_string');

// 3. Tüm URL'lerden versiyon parametresini kaldır
function guvenlik_versiyon_url_temizle($src) {
    global $wp_version;
    // Sadece WordPress versiyonuyla eşleşen parametreleri kaldır
    if (strpos($src, 'ver=' . $wp_version) !== false) {
        $src = remove_query_arg('ver', $src);
    } elseif (strpos($src, '?ver=') !== false || strpos($src, '&ver=') !== false) {
        $src = remove_query_arg('ver', $src);
    }
    return $src;
}
add_filter('style_loader_src', 'guvenlik_versiyon_url_temizle', 9999);
add_filter('script_loader_src', 'guvenlik_versiyon_url_temizle', 9999);

// 4. REST API versiyon bilgisini gizle
add_filter('rest_index', function($response) {
    if (isset($response->data['wp_version'])) {
        unset($response->data['wp_version']);
    }
    return $response;
});

// 5. Login sayfası generator'ını kaldır
add_action('login_head', function() {
    remove_action('wp_head', 'wp_generator');
});

// 6. X-Powered-By header'ını temizle (PHP versiyon bilgisi)
if (function_exists('header_remove')) {
    add_action('init', function() {
        header_remove('X-Powered-By');
    });
}

Gerçek Dünya Senaryosu: E-ticaret Sitesi Güvenlik Sertleştirme

Diyelim ki bir WooCommerce mağazanız var ve düzenli güvenlik denetimleri yapıyorsunuz. Bir penetrasyon test uzmanı size rapor sundu ve sitenizin kaynak kodunda WordPress versiyonu açıkça görünüyor. Bu durumda ne yapmalısınız?

Önce mevcut durumu kontrol edin:

# Sitenizin kaynak kodunda versiyon var mı kontrol et
curl -s https://siteniz.com | grep -i "generator"

# Hangi dosyalarda ver= parametresi var
curl -s https://siteniz.com | grep -o 'ver=[^"&]*' | sort -u

# REST API'den versiyon bilgisi geliyor mu
curl -s https://siteniz.com/wp-json/ | python3 -m json.tool | grep -i version

Bu komutların çıktısında versiyon bilgisi görüyorsanız, yukarıdaki kod bloğunu functions.php‘ye ekleyin. Ardından kontrol edin:

# Değişiklikten sonra tekrar kontrol et
curl -s https://siteniz.com | grep -i "generator"
# Bu komut artık hiçbir şey döndürmemeli

# Script/style URL'lerini kontrol et
curl -s https://siteniz.com | grep -o '?ver=[^"]*'
# Bu da boş dönmeli

readme.html ve Diğer Hassas Dosyaları Kaldırma

functions.php tek başına yeterli değil. WordPress kurulumunda bulunan readme.html dosyası versiyon bilgisini açıkça içerir. Bu dosyayı sunucu tarafında kaldırmanız veya erişimi engellemeniz gerekir.

# readme.html dosyasını sil
rm /var/www/html/readme.html

# license.txt dosyasını da sil (isteğe bağlı)
rm /var/www/html/license.txt

# Eğer silmek istemiyorsanız, .htaccess ile erişimi engelle
echo "Options -Indexes" >> /var/www/html/.htaccess

Nginx kullanıyorsanız, site konfigürasyonunuza ekleyin:

# Nginx konfigürasyonu düzenle
nano /etc/nginx/sites-available/siteniz.com

# Şu bloğu server {} içine ekle:
# location ~* /readme.html$ {
#     deny all;
#     return 404;
# }
# location ~* /license.txt$ {
#     deny all;
#     return 404;
# }

# Konfigürasyonu test et
nginx -t

# Nginx'i yeniden yükle
systemctl reload nginx

Apache için .htaccess yöntemi:

# .htaccess dosyasını düzenle
nano /var/www/html/.htaccess

# Şu satırları ekle:
# <FilesMatch "^(readme|license|wp-config-sample)..*$">
#     Order Allow,Deny
#     Deny from all
# </FilesMatch>

WP-CLI ile Toplu Kontrol ve Yönetim

Birden fazla WordPress sitenizi yönetiyorsanız, WP-CLI ile bu işlemleri otomatize edebilirsiniz:

#!/bin/bash
# wp-versiyon-kontrol.sh
# Birden fazla sitede versiyon bilgisi sızıntısını kontrol et

SITELER=(
    "/var/www/html/site1"
    "/var/www/html/site2"
    "/var/www/html/site3"
)

for SITE in "${SITELER[@]}"; do
    echo "=== Kontrol ediliyor: $SITE ==="
    
    # WordPress versiyonu öğren
    WP_VER=$(wp --path="$SITE" core version 2>/dev/null)
    echo "WordPress Versiyonu: $WP_VER"
    
    # Ana sayfada versiyon var mı kontrol et
    SITE_URL=$(wp --path="$SITE" option get siteurl 2>/dev/null)
    GENERATOR=$(curl -s "$SITE_URL" | grep -i "generator" | head -1)
    
    if [ -z "$GENERATOR" ]; then
        echo "TAMAM: Generator etiketi bulunamadı"
    else
        echo "UYARI: Generator etiketi bulundu: $GENERATOR"
    fi
    
    # readme.html var mı
    if [ -f "$SITE/readme.html" ]; then
        echo "UYARI: readme.html mevcut, kaldırılmalı"
    else
        echo "TAMAM: readme.html mevcut değil"
    fi
    
    echo ""
done

Bu scripti düzenli aralıklarla çalıştırmak için cron job ekleyin:

# Crontab'ı düzenle
crontab -e

# Her gece saat 02:00'de çalıştır
0 2 * * * /bin/bash /root/scripts/wp-versiyon-kontrol.sh >> /var/log/wp-guvenlik.log 2>&1

Child Theme ile Güvenli Uygulama

Değişikliklerinizin tema güncellemelerinden etkilenmemesi için child theme oluşturun:

# Child theme dizini oluştur
mkdir /var/www/html/wp-content/themes/aktif-tema-child

# style.css oluştur
cat > /var/www/html/wp-content/themes/aktif-tema-child/style.css << 'EOF'
/*
 Theme Name: Aktif Tema Child
 Template: aktif-tema
 Version: 1.0
*/
EOF

# functions.php oluştur
cat > /var/www/html/wp-content/themes/aktif-tema-child/functions.php << 'EOF'
<?php
// Ana temayı yükle
add_action('wp_enqueue_scripts', function() {
    wp_enqueue_style(
        'parent-style',
        get_template_directory_uri() . '/style.css'
    );
});

// Versiyon gizleme kodlarını buraya ekle
remove_action('wp_head', 'wp_generator');
add_filter('the_generator', '__return_empty_string');

// Diğer güvenlik fonksiyonları...
EOF

# Doğru izinleri ayarla
chown -R www-data:www-data /var/www/html/wp-content/themes/aktif-tema-child
chmod 755 /var/www/html/wp-content/themes/aktif-tema-child
chmod 644 /var/www/html/wp-content/themes/aktif-tema-child/functions.php

Ek Güvenlik Önlemleri

Versiyon gizlemenin yanında functions.php‘ye ekleyebileceğiniz birkaç ek güvenlik önlemi daha var:

<?php
// WordPress admin bilgilerini URL'de gösterme
remove_action('wp_head', 'rsd_link');
remove_action('wp_head', 'wlwmanifest_link');
remove_action('wp_head', 'wp_shortlink_wp_head');

// XML-RPC'yi devre dışı bırak (brute force saldırılarına karşı)
add_filter('xmlrpc_enabled', '__return_false');

// Kullanıcı adlarını REST API'den gizle
add_filter('rest_endpoints', function($endpoints) {
    if (isset($endpoints['/wp/v2/users'])) {
        unset($endpoints['/wp/v2/users']);
    }
    if (isset($endpoints['/wp/v2/users/(?P<id>[d]+)'])) {
        unset($endpoints['/wp/v2/users/(?P<id>[d]+)']);
    }
    return $endpoints;
});

// Hata mesajlarını gizle (login sayfasında)
add_filter('login_errors', function() {
    return 'Giriş bilgileri hatalı.';
});

Değişikliklerin Doğrulanması

Her şeyi yaptıktan sonra mutlaka doğrulama yapın. Birkaç farklı araç kullanabilirsiniz:

# Temel kontroller
echo "=== Generator Etiketi Kontrolü ==="
curl -s https://siteniz.com | grep -i generator || echo "Temiz!"

echo "=== Feed Generator Kontrolü ==="
curl -s https://siteniz.com/feed/ | grep -i generator || echo "Temiz!"

echo "=== REST API Versiyon Kontrolü ==="
curl -s https://siteniz.com/wp-json/ | python3 -c "import sys,json; d=json.load(sys.stdin); print(d.get('wp_version', 'Versiyon bilgisi bulunamadı'))"

echo "=== readme.html Erişim Kontrolü ==="
HTTP_CODE=$(curl -o /dev/null -s -w "%{http_code}" https://siteniz.com/readme.html)
if [ "$HTTP_CODE" = "404" ] || [ "$HTTP_CODE" = "403" ]; then
    echo "Tamam! HTTP $HTTP_CODE"
else
    echo "Uyarı! readme.html erişilebilir: HTTP $HTTP_CODE"
fi

Ayrıca online araçlarla da kontrol edebilirsiniz:

  • WPScan: WordPress güvenlik tarayıcısı, versiyon tespiti yapabilir
  • Sucuri SiteCheck: Ücretsiz online güvenlik tarayıcısı
  • Qualys SSL Labs: Header güvenlik kontrolü için

Sonuç

WordPress versiyon bilgisini gizlemek başlı başına sizi güvende tutmaz, ancak saldırganların işini zorlaştıran ve otomatik tarayıcıları engelleyen önemli bir adımdır. Bu yazıda öğrendiklerinizi özetlersek:

  • remove_action('wp_head', 'wp_generator') ile meta generator etiketini kaldırırsınız
  • add_filter('the_generator', '__return_empty_string') ile feed’lerden temizlersiniz
  • Script ve style URL’lerinden ?ver= parametresini filtrelersiniz
  • REST API response’undan versiyon bilgisini çıkarırsınız
  • Sunucu tarafında readme.html ve license.txt dosyalarını kaldırır veya erişimini engellersiniz
  • WP-CLI ile bu kontrolleri otomatize edersiniz

Tüm bu işlemleri child theme üzerinde yapmanız, WordPress veya tema güncellemelerinde değişikliklerinizin korunmasını sağlar. Güvenlik katmanlı bir yaklaşım gerektirir; versiyon gizleme bu katmanlardan sadece biridir. Düzenli güncellemeler, güçlü parolalar, iki faktörlü kimlik doğrulama ve düzenli yedekleme ile birlikte uygulandığında gerçek anlamda sağlam bir güvenlik altyapısı elde edersiniz.

Bir yanıt yazın

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