v2.5.2
Giriş yap

Ajax API Güvenliği Hk.

r00t
440 defa görüntülendi

Merhabalar;
Sorum özellikle PHP projelerimdeki Ajax requestlerimin güvenliği için ortaya çıkıyor. Ancak her dil için ortak noktaları elbet vardır.
Sizlerin bu tarz Ajax ile GET/POST gibi requestlerinizde, endpoint tarafında vs. mutlaka dikkat ettiğiniz noktalar nelerdir? Gerek front-end tarafında isteği yollarken, gerek hedef backend dosya üzerinde yaptığınız kontroller vs.
Örneğin;
POST isteği var mı? CSRF-TOKEN eşleşiyor mu? Referer kontrolü, Dosyaya link üzerinden direct access'i blocklama, parametreleri sanitize etme vb.vb.

Gerek buraya aklınıza gelen maddeleri, gerekse faydalanabileceğimiz linkleri bırakırsanız; bu konu başlığı aracılığı ile pek çok kişiye faydası dokunur diye düşünüyorum.

saygılar

Cevap yaz
Cevaplar (6)
sefaaydin
655 gün önce

Bu kısım Ajaxtan gelen verileri aldığımız PHP dosyası. $csrf_token, $recaptcha Göndermeyi unutmayın.
Bunun bir gelişmişi vardı. Bulamadım. Orada şöyle bir işlem daha yapmıştım. Ajax query alan adından mı geliyor? veya bu alan adından gelmeyen ajax isteklerini şuraya yönlendir gibi özellikler vardı. Sende buna göre düzenleyebilirsin.



function isAjaxRequest(){
    return !empty($_SERVER['HTTP_X_REQUESTED_WITH']) && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest';
}

$errors = [];
$data   = [];


if (isAjaxRequest()){
    
    if(isset($_POST) & !empty($_POST)){

        $postAdi      = strip_tags($_POST["postAdi"]);

        if(empty($recaptcha)){
            $data['status'] = 'error';
            $errors['recaptcha'] = 'Please check the the captcha form.';
            $data['errors'] = $errors;
        }else{

            // CSRF Token Validation
            if(isset($csrf_token)){
                if($csrf_token === $_SESSION['csrf_token']){

                    // CSRF Token Time Validation
                    $max_time = 60*60*24; // in seconds
                    if(isset($_SESSION['csrf_token_time'])){
                        $token_time = $_SESSION['csrf_token_time'];
                        if(($token_time + $max_time) >= time() ){

                            // Tüm hataları burada kontrol edebilirsin.
                            if (empty($postAdi)) {
                                $errors['hataAdi'] = 'Hata açıklaması bu alanda olmalı.';
                            }
                
                            // eğer $errors değişkeni boş değilse hatalar geri dönecek.
                            if (!empty($errors)) {
                                $data['status'] = 'error';
                                $data['errors'] = $errors;
                            } else {
                                // $errors değişkeni boşsa işlemler burada başlayacak.
                                // veritabanı vs işlemleri
                                
                                $data['status'] = 'success';
                                $data['message']= 'işleminiz başarıyla gerçekleşti.';
                            }

                        }else{
                            $errors['csrfExpired'] = 'CSRF token hatası. Sayfayı yenileyin!';
                            $data['status'] = 'error';
                            $data['errors'] = $errors;
                            unset($_SESSION['csrf_token']);
                            unset($_SESSION['csrf_token_time']);
                        }
                    }else{
                        $errors['csrfTime'] = 'CSRF token süresi dolmuştur. Lütfen sayfayı yenileyin!';
                        $data['status'] = 'error';
                        $data['errors'] = $errors;
                    }

                }else{
                    $errors['csrfValidate'] = 'CSRF Token doğrulama hatası. Lütfen sayfayı yenileyin!';
                    $data['status'] = 'error';
                    $data['errors'] = $errors;
                }
            }else{
                $errors['csrfToken'] = 'CSRF Token bulunamadı. Lütfen sayfayı yenileyin!';
                $data['status'] = 'error';
                $data['errors'] = $errors;
            }
        }
    }else {
        $errors['realuser'] = "İstek yöntemi POST değil veya Sayfaya gönderilen POST mevcut değil!";
        $data['status'] = 'error';
        $data['errors'] = $errors;
    }
} else {
    $errors['pageError'] = "Kullanılabilir istek yok veya Gelen istek Ajax değerinde değil!";
    $data['status'] = 'error';
    $data['errors'] = $errors;
}


echo json_encode($data);


devepdogukan
659 gün önce

Buradaki en güvenli durum jwt tokendır. İstersen header içerisinde gönder bu tokenı istersen httpSecure tipinde cookie oluşturup öyle gönder. Jwt token senin belirttiğin bir key ile şifrelenip sadece senin domain'den gelen istekleri kabul eder.

jct
659 gün önce

@r00t kesinlikle dediğin gibi, benim tecrübe edindiğim bu konudaki tek şey gönderdiğin Token'ı nasıl güvenli kıldığın.

PHP nezdinde bakarsan; $_SERVER, $_POST, $_GET veya AJAX isteğine bakmak, ortak kullanılan sunucu'larda güvenli değil.

Ben ne yapıyorum; Kendime özgü bir şifreleme fonksiyonu geliştirdim. Tabiki oturup bir HASH algoritması yazmadım. Gönderdiğim Token içerisine bir Security Key ve göndermek istediğim Data'yı koyuyorum. Back-End tarafında bu GET veya POST isteğini kontrol ediyorum.

GET veya POST yoksa (die), varsa bu kez şifreleme algoritmasını tersine çalıştırıp, içindeki Security Key'i kontrol ediyorum. Key doğruysa Data'yı alıyorum. Bu Data bir ID ise'de ID'yi kontrol ettiriyorum.

Düşünsene eğer ark niyetli kişi Sunucu'ya ulaşamadıysa Browser nezdinde sana birşey yapması mümkün değil. Artık sunucuya ulaşabildiyse zaten, şifreleme fonksiyonunda, Security Key'inde bir önemi kalmadı demektir.

r00t
660 gün önce

@jct bahsettiğin durum zaten request data içerisinde csrf-token göndermekle aynı şey, farkı var mı bilemedim :=)

jct
660 gün önce

Kendi kullandığım yöntem; İstek attığım adresin sonuna şifrelenmiş bir GET isteği ekliyorum.

http://APIURL?req=ŞifrelenmişToken

İşlem yapacağım sayfada bu Token değerini kontrol ediyorum, eğer yok yada doğru değilse, sayfaya girişi engelliyorum. Umarım işinize yarar...

istek61
661 gün önce

soru çok güzel ama bende cevap yok :) umarım güzel cevaplar gelir