WordPress Eklentilerinde Nonce, Sanitize ve Escape Kullanımı

Google News Google News Flipboard Flipboard Sesli oku Yazıyı beğen Favorilere Ekle 0 Yorumlar
Daha fazla
WordPress dünyasında raporlanan güvenlik açıklarının büyük çoğunluğu çekirdekten değil, üçüncü taraf eklentilerden çıkar. WPScan veritabanına bakıldığında bu açıkların önemli bir kısmı üç temel adımın atlanmasından doğar: nonce doğrulamagirdi sanitize ve çıktı escape. Bu üç kavram WordPress güvenlik mimarisinin omurgasıdır. Çekirdek kod büyük oranda sıkı yazılmıştır ancak özel geliştirilen bir eklentide bu üç adımdan biri eksik kalırsa CSRF, XSS veya SQL injection saldırılarına kapı açılır. Bu rehberde her üç kavramı pratik kod örnekleriyle ele alacağız, sık yapılan hataları göstereceğiz ve yayın öncesi kontrol listesini paylaşacağız.

WordPress nonce sanitize escape: Pratik Senaryo: Güvensiz Bir Eklenti Formu

WordPress nonce sanitize escape: Pratik Senaryo: Güvensiz Bir Eklenti Formu
WordPress nonce sanitize escape: Pratik Senaryo: Güvensiz Bir Eklenti Formu
Bir yönetici panelinde basit bir ayar formu olduğunu düşünün. Form, site açıklamasını günceller. Geliştirici hızlıca şu kodu yazıyor:
// KOTU ORNEK - kullanmayin
if (isset($_POST['aciklama'])) {
    update_option('site_aciklama', $_POST['aciklama']);
}
echo '<p>Mevcut acıklama: ' . get_option('site_aciklama') . '</p>';
Bu dört satırlık kod üç farklı saldırı vektörüne açıktır:
  • CSRF (Cross-Site Request Forgery): Saldırgan, oturumu açık bir adminin tarayıcısına gizli bir form çalıştırarak site açıklamasını değiştirebilir.
  • Stored XSS: POST verisinde gönderilen <script> etiketi veritabanına yazılır ve her sayfa yüklendiğinde çalışır.
  • Veri bütünlüğü kaybı: Beklenmedik karakterler, satır sonları veya kontrol dizileri filtrelenmeden veritabanına sızar.
Bu üç sorunu kapatmak için üç farklı katman gerekir: nonce, sanitize ve escape.

Nonce Kullanımı: CSRF Koruması

Nonce Nedir?

Nonce kelimesi “number used once” ifadesinin kısaltmasıdır. WordPress’te nonce, belirli bir kullanıcı, belirli bir eylem ve sınırlı bir zaman aralığı için üretilen tek kullanımlık benzeri bir token’dır. Varsayılan ömrü 24 saattir ve eylem (action) adına göre üretilir. Nonce’un işlevi tek bir cümleyle özetlenebilir: bir isteğin gerçekten o kullanıcının kendi sitesinden bilinçli olarak gönderildiğini doğrulamak. Nonce yetkilendirme için değildir; sadece isteğin kaynağını doğrular.

Nonce Üretme ve Doğrulama

Form içinde nonce alanı oluşturmak için wp_nonce_field() kullanılır:
// Formda nonce alani olustur
wp_nonce_field('ob_site_aciklama_guncelle', 'ob_site_aciklama_nonce');
İlk parametre eylem (action) adıdır, ikincisi form alanının adıdır. Bu fonksiyon iki gizli alan üretir: nonce token ve referer URL. İşleme tarafında doğrulama:
if (
    ! isset($_POST['ob_site_aciklama_nonce']) ||
    ! wp_verify_nonce(
        sanitize_text_field(wp_unslash($_POST['ob_site_aciklama_nonce'])),
        'ob_site_aciklama_guncelle'
    )
) {
    wp_die('Guvenlik dogrulamasi basarisiz.');
}
Eylem bir admin sayfası içindeyse daha kısa yol check_admin_referer()‘dır:
check_admin_referer('ob_site_aciklama_guncelle', 'ob_site_aciklama_nonce');
Bu fonksiyon doğrulama başarısız olursa otomatik olarak wp_die() ile durur.

AJAX İstekleri İçin Nonce

AJAX işlemlerinde nonce farklı yerleştirilir. Önce localize edilir:
wp_localize_script('ob-admin-js', 'obAdmin', [
    'ajaxUrl' => admin_url('admin-ajax.php'),
    'nonce'   => wp_create_nonce('ob_ajax_islem'),
]);
Sunucu tarafında doğrulama:
add_action('wp_ajax_ob_islem', function () {
    check_ajax_referer('ob_ajax_islem', 'security');
    // islem...
});
JavaScript tarafında security parametresine obAdmin.nonce değeri gönderilir. wp_ajax_nopriv_ ile giriş yapmamış kullanıcılara da açık endpoint’ler tanımlanıyorsa nonce burada özellikle önemlidir.

Girdi Sanitize Etme: Veri Temizleme

Girdi Sanitize Etme: Veri Temizleme
Girdi Sanitize Etme: Veri Temizleme
Nonce, isteğin meşru olduğunu doğrular. Ancak meşru bir kullanıcı bile yanlışlıkla veya kasıtlı olarak bozuk veri gönderebilir. Bu yüzden veritabanına yazılmadan önce her girdi temizlenmelidir. WordPress, veri türüne göre farklı sanitize fonksiyonları sunar. En sık kullanılanlar:
Fonksiyon Kullanım Yeri Davranış
sanitize_text_field() Tek satırlık metin alanları HTML temizler, satır sonlarını ve fazla boşlukları kaldırır
sanitize_textarea_field() Çok satırlı metin alanları HTML temizler ama satır sonlarını korur
sanitize_email() E-posta alanları Geçersiz karakterleri kaldırır, geçerli değilse boş döner
esc_url_raw() URL’nin veritabanına yazılması URL’yi güvenli forma getirir, ekrana yazmaz
absint() Pozitif tamsayılar (ID, sayfa numarası) Mutlak değerli tamsayı döner
sanitize_key() Slug, key, option name Sadece küçük harf, rakam, alt çizgi ve tire bırakır
wp_kses_post() Yazı içeriği İzin verilen HTML etiketlerini korur
Önceki güvensiz örneği güvenli hale getirmek için sanitize ekleyelim:
$aciklama = isset($_POST['aciklama'])
    ? sanitize_textarea_field(wp_unslash($_POST['aciklama']))
    : '';

update_option('site_aciklama', $aciklama);
wp_unslash() burada önemlidir. WordPress, magic quotes davranışını taklit ederek POST/GET verisindeki ters bölü işaretlerini otomatik ekler. Sanitize öncesinde bunlar temizlenmezse ters bölü işaretleri veritabanına sızar.

Çıktı Escape Etme: XSS Koruması

Sanitize, veritabanına yazılan veriyi temizler. Escape ise tam tersine, veriyi ekrana yazarken bağlama göre güvenli hale getirir. Sanitize girişte, escape çıkışta yapılır. İkisini karıştırmamak gerekir. Çekirdek mantık şudur: veriyi ne kadar temiz aldığınızdan emin olsanız bile, ekrana yazarken bağlama uygun escape uygulanmalıdır. Çünkü aynı veri farklı bağlamlarda farklı tehlikeler taşır.
Fonksiyon Kullanım Bağlamı
esc_html() HTML içinde metin: <p>...</p>
esc_attr() HTML niteliği: value="..."title="..."
esc_url() hrefsrc gibi URL bağlamları
esc_js() JavaScript dizesi içine değer gömme
esc_textarea() <textarea> içinde varsayılan değer
wp_kses_post() İzin verilen HTML ile içerik gösterimi
Hatalı bir yaklaşım, çıktı bağlamından bağımsız tek bir escape fonksiyonu kullanmaktır. Örneğin esc_html() ile escape edilmiş bir değeri href niteliğinin içine koymak hâlâ javascript: şemalı saldırılara açıktır. URL bağlamında esc_url() tercih edilmelidir.

Tam Bir Güvenli Form Örneği

Tam Bir Güvenli Form Örneği
Tam Bir Güvenli Form Örneği
Üç katmanı tek bir minimal örnek üzerinde birleştirelim. Aşağıdaki kod, admin panelinde site açıklamasını güncelleyen güvenli bir formdur:
// Admin sayfasini ekle
add_action('admin_menu', function () {
    add_options_page(
        'OB Site Aciklamasi',
        'OB Site Aciklamasi',
        'manage_options',
        'ob-site-aciklama',
        'ob_render_aciklama_sayfa'
    );
});

function ob_render_aciklama_sayfa() {
    if (! current_user_can('manage_options')) {
        wp_die('Yetkisiz erisim.');
    }

    // Form gonderildi mi?
    if (
        isset($_POST['ob_aciklama_submit']) &&
        check_admin_referer('ob_aciklama_action', 'ob_aciklama_nonce')
    ) {
        $aciklama = isset($_POST['ob_aciklama'])
            ? sanitize_textarea_field(wp_unslash($_POST['ob_aciklama']))
            : '';

        update_option('ob_site_aciklama', $aciklama);
        echo '<div class="notice notice-success"><p>Kaydedildi.</p></div>';
    }

    $mevcut = get_option('ob_site_aciklama', '');
    ?>
    <div class="wrap">
        <h1>OB Site Aciklamasi</h1>
        <form method="post">
            <?php wp_nonce_field('ob_aciklama_action', 'ob_aciklama_nonce'); ?>
            <p>
                <label for="ob_aciklama">Aciklama</label><br>
                <textarea
                    id="ob_aciklama"
                    name="ob_aciklama"
                    rows="5"
                    cols="60"
                ><?php echo esc_textarea($mevcut); ?></textarea>
            </p>
            <p>
                <button
                    type="submit"
                    name="ob_aciklama_submit"
                    class="button button-primary"
                >Kaydet</button>
            </p>
        </form>
        <h2>Onizleme</h2>
        <p><?php echo esc_html($mevcut); ?></p>
    </div>
    <?php
}
Bu kodda dört katmanlı koruma vardır:
  1. Yetki kontrolü: current_user_can('manage_options') ile sadece yöneticiler erişebilir.
  2. Nonce doğrulama: check_admin_referer() CSRF’yi kapatır.
  3. Girdi sanitize: sanitize_textarea_field() veritabanı için temizler.
  4. Çıktı escape: esc_textarea() ve esc_html() XSS’i engeller.

Sık Yapılan Hatalar

Pratikte tekrar eden hata kalıpları:
  • Yetki kontrolünü atlamak. Nonce, yetkilendirme yerine geçmez. Nonce sadece isteğin meşru olduğunu doğrular; kullanıcının o işlemi yapmaya hakkı olup olmadığını current_user_can() belirler.
  • Sanitize ve escape’i karıştırmak. Veritabanına yazarken sanitize, ekrana yazarken escape kullanılır. esc_html() ile temizlenmiş bir değeri veritabanına yazmak veri kaybına yol açabilir.
  • Çıktıyı tek bir fonksiyonla escape etmek. Bağlama göre esc_html()esc_attr()esc_url() ayrılmalıdır. Aksi halde bazı saldırı vektörleri açık kalabilir.
  • wp_unslash()‘i unutmak. WordPress POST/GET verisini otomatik olarak slash ekleyerek alır; sanitize öncesinde temizlenmezse ters bölü işaretleri veritabanına sızar.
  • AJAX endpoint’lerini nonce’suz bırakmak. admin-ajax.php giriş yapmamış kullanıcılar için de açık olabilir; wp_ajax_nopriv_ kullanılıyorsa nonce doğrulaması özellikle önemlidir.
  • SQL sorgularında $wpdb->prepare() kullanmamak. Bu rehberin doğrudan konusu değildir ancak sanitize ile birlikte düşünülmesi gereken bir katmandır.

Yayın Öncesi Kontrol Listesi

Eklentiyi depoya göndermeden veya canlıya almadan önce şu listeyi sırasıyla kontrol edin:
  1. Tüm formlarda wp_nonce_field() var mı?
  2. Tüm POST işleyicilerde wp_verify_nonce() veya check_admin_referer() çağrısı var mı?
  3. Tüm AJAX endpoint’lerinde check_ajax_referer() çağrılıyor mu?
  4. Her işlem için current_user_can() ile yetki kontrolü yapılıyor mu?
  5. Tüm $_POST$_GET$_REQUEST erişimleri wp_unslash() ile temizleniyor mu?
  6. Veritabanına yazılan her değer veri türüne uygun sanitize fonksiyonundan geçiyor mu?
  7. Ekrana yazılan her değer bağlama uygun escape fonksiyonundan geçiyor mu?
  8. HTML niteliklerinde esc_attr(), URL’lerde esc_url() ayrımı yapıldı mı?
  9. Kullanıcının HTML girebileceği alanlarda wp_kses_post() veya benzer filtre kullanılıyor mu?
  10. Doğrudan SQL sorgularında $wpdb->prepare() kullanılıyor mu?

Sonuç

WordPress eklenti güvenliğinin temeli üç katmandan oluşur: nonce ile isteğin meşruluğunu doğrulamak, sanitize ile girdiyi temizlemek ve escape ile çıktıyı güvenli hale getirmek. Bu üç adım birbirinin yerine geçmez; bir formda hepsi birlikte uygulanmalıdır. Sonraki adım olarak kendi eklentinizdeki tüm form ve AJAX endpoint’lerini yukarıdaki kontrol listesine göre gözden geçirebilir, eksik kalan katmanları tek tek tamamlayabilirsiniz. WPCS (WordPress Coding Standards) PHP_CodeSniffer kurallarıyla yapılacak otomatik taramalar da bu kontrolleri büyük oranda destekler ve sizi tekil hataları teker teker kovalamaktan kurtarır.

WordPress nonce sanitize escape için pratik kontrol listesi

WordPress nonce sanitize escape konusunda uygulamaya geçmeden önce mevcut yedeği doğrulayın, değişikliği küçük adımlarla test edin ve sonucu canlı sitede tekrar kontrol edin. Benzer konular için WordPress REST API ve WordPress güvenli giriş rehberlerine de bakabilirsiniz. Resmi kaynak olarak WordPress güvenlik dokümantasyonu sayfasını incelemek faydalı olur.

SSS: WordPress Eklentilerinde Nonce, Sanitize ve Escape Kullanımı

WordPress Eklentilerinde Nonce, Sanitize ve Escape Kullanımı için ilk kontrol ne olmalı?
Önce sorunun kapsamını belirleyin. Sadece tek sayfada mı, tüm sitede mi, yoksa belirli kullanıcı veya cihazlarda mı göründüğünü kontrol edin.

Bu işlem SEO performansını etkiler mi?
Evet, teknik sorunlar kullanıcı deneyimini ve tarama kalitesini etkileyebilir. Bu nedenle değişiklikten sonra Search Console verilerini takip etmek gerekir.

Canlı sitede işlem yapmadan önce yedek almak gerekir mi?
Kesinlikle gerekir. Dosya ve veritabanı yedeği olmadan yapılan canlı değişiklikler, küçük bir hatada geri dönüşü zorlaştırabilir.

Değişiklikten sonra cache temizlemek şart mı?
Çoğu durumda evet. WordPress cache eklentisi, CDN ve tarayıcı cache’i eski çıktıyı göstermeye devam edebilir.

Sorun devam ederse nasıl ilerlemeliyim?
Son yapılan değişikliği geri alın, hata loglarını kontrol edin ve eklenti/tema çakışmasını izole edin. Gerekirse küçük adımlarla yeniden test edin.

Yazar Hakkında

Benzer Yazılar

Bir Cevap Yaz

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

0/30 karakter