CodeBlanks Logo Icon CodeBlanks

Meydan okuma - Güvenlik uygulaması

PHP kursu · İleri seviye · Ders 89/92

password_hash, CSRF ve güvenlik başlıklarıyla tam bir kimlik doğrulama akışı yazarsın.

Kimlik doğrulama akışı

Bu derste AuthService sınıfını yazarsın. password_hash($pass, PASSWORD_DEFAULT) parolayı bcrypt ile hash'ler; tuz (salt) otomatik üretilir. password_verify($pass, $hash) hash'i doğrular ve zamanlama saldırılarına karşı güvenlidir.

Sınıf üç yöntem daha içerir. csrfToken() ilk çağrıda bin2hex(random_bytes(8)) ile 16 karakterlik bir dize üretir ve saklar. applyHeaders() header() ile X-Frame-Options: DENY ve X-Content-Type-Options: nosniff başlıklarını gönderir. Böylece API yanıtının yanına bir güvenlik katmanı eklersin.

Güvenlik başlıkları

HTTP yanıt başlıkları tarayıcının yanıtı nasıl işleyeceğini belirler. X-Frame-Options: DENY sayfanın başka bir sitede çerçevelenmesini engeller (tıklama kaçırma saldırılarına karşı). X-Content-Type-Options: nosniff tarayıcının MIME türünü tahmin etmesini önler.

PHP'de header("Ad: Değer") çağrısı bu başlıkları gönderir. CLI modunda çıktı üretmeseler de web sunucusunda yanıt başlıklarına eklenirler. applyHeaders() yöntemi tüm başlıkları tek yerden gönderir; böylece korumayı açma/kapama unutmazsın. Üstelik her istekte aynı başlıkları tekrar tekrar yazmazsın.

Uygulama AuthService sınıfını yaz

Başlangıç kodunda Ürün API'si hazır. Şimdi AuthService sınıfını ekle. Özel array $users = [] ve string $csrf = "" özellikleri olsun.

register(string $user, string $pass): void yöntemi password_hash($pass, PASSWORD_DEFAULT) ile hash üretip $users dizisine ekler. login(string $user, string $pass): bool yöntemi kullanıcı yoksa false, varsa password_verify sonucunu döndürür. csrfToken(): string ilk çağrıda bin2hex(random_bytes(8)) ile token üretir. applyHeaders(): void header() ile X-Frame-Options: DENY ve X-Content-Type-Options: nosniff gönderir. Demoyu çalıştır.

Örnek çözümü göster
class AuthService { private array $users = []; private string $csrf = ""; ... } tanımla. register içinde password_hash, login içinde password_verify, csrfToken içinde bin2hex(random_bytes(8)), applyHeaders içinde iki header() çağrısı yaz. Sonra demoyu çalıştır.
Örnek çözüm:
<?php
// Ürün API'si + güvenlik: AuthService yaz

class ProductRepository {
    private PDO $pdo;

    public function __construct(PDO $pdo) {
        $this->pdo = $pdo;
        $this->pdo->exec("CREATE TABLE products (id INTEGER PRIMARY KEY, name TEXT, price INTEGER)");
        $stmt = $this->pdo->prepare("INSERT INTO products (name, price) VALUES (?, ?)");
        $stmt->execute(["Kale", 5]);
        $stmt->execute(["Defter", 15]);
    }

    public function all(): array {
        $rows = $this->pdo->query("SELECT id, name, price FROM products ORDER BY id")->fetchAll(PDO::FETCH_ASSOC);
        return array_map(fn($r) => [
            "id" => (int)$r["id"],
            "name" => $r["name"],
            "price" => (int)$r["price"]
        ], $rows);
    }
}

function handleGet(PDO $pdo): string {
    $repo = new ProductRepository($pdo);
    return json_encode(["products" => $repo->all()], JSON_UNESCAPED_UNICODE);
}

class AuthService {
    private array $users = [];
    private string $csrf = "";

    public function register(string $user, string $pass): void {
        $this->users[$user] = password_hash($pass, PASSWORD_DEFAULT);
    }

    public function login(string $user, string $pass): bool {
        if (!isset($this->users[$user])) return false;
        return password_verify($pass, $this->users[$user]);
    }

    public function csrfToken(): string {
        if ($this->csrf === "") {
            $this->csrf = bin2hex(random_bytes(8));
        }
        return $this->csrf;
    }

    public function applyHeaders(): void {
        header("X-Frame-Options: DENY");
        header("X-Content-Type-Options: nosniff");
    }
}

// Demo:
$auth = new AuthService();
$auth->register("ayse", "gizli parola");
echo $auth->login("ayse", "gizli parola") ? "giriş: tamam" : "giriş: red";
echo "\n";
echo $auth->login("ayse", "yanlış") ? "giriş: tamam" : "giriş: red";
echo "\n";
echo strlen($auth->csrfToken()) . "\n";
$auth->applyHeaders();
echo "başlıklar: tamam\n";

Kendini test et

  1. password_verify çağrısını tamamla

    return ____($pass, $this->users[$user]);
    Cevabı göster
    return password_verify($pass, $this->users[$user]);
  2. CSRF token üretmek için hangi fonksiyon kullanılır?

    • random_bytes ile bin2hex
    • md5 ile zaman damgası
    • password_hash ile bcrypt
    • sha1 ile kullanıcı adı
    Cevabı göster

    random_bytes ile bin2hex — Doğru. random_bytes kriptografik olarak güvenli rastgele bayt üretir; bin2hex onu dizeye çevirir.

  3. Güvenlik kavramlarını eşleştir

    password_hash
    Parolayı bcrypt ile saklar
    password_verify
    Parolayı hash'e karşı denetler
    bin2hex
    Baytları onaltılık dizeye çevirir
    header
    HTTP yanıt başlığı gönderir

İleri seviye bölümündeki tüm dersler