Xavfsizlik — XSS, CSRF, SQL injection, sessiya o'g'irlash

~20 daq · PHP · Zamonaviy PHP

Muammodan boshlaylik

Kurs davomida xavfsizlik haqida alohida darslarda gaplashdik: XSS (20-dars), SQL injection (36-dars), parollar (38-dars), fayl yuklash (22-dars). Bu darsda hammasini bitta tizimga yig'amiz va hali ko'rmagan muhim hujum — CSRF ni o'rganamiz.

Asosiy tamoyil bitta: foydalanuvchidan kelgan har qanday narsa — hujum bo'lishi mumkin. Brauzer sizning nazoratingizda emas.


1. SQL Injection

Hujum: foydalanuvchi ma'lumoti SQL kodi sifatida bajariladi.

// ❌
$pdo->query("SELECT * FROM users WHERE email = '$email'");

Himoya: prepared statements — har doim, istisnosiz.

// ✅
$stmt = $pdo->prepare('SELECT * FROM users WHERE email = ?');
$stmt->execute([$email]);

Ustun nomlari va ORDER BY yo'nalishi — faqat whitelist orqali.


2. XSS — Cross-Site Scripting

Hujum: foydalanuvchi kiritgan HTML/JavaScript boshqa foydalanuvchilarning brauzerida bajariladi. Natija: cookie o'g'irlash, sahifani soxtalashtirish, foydalanuvchi nomidan amallar.

// ❌
<p><?= $izoh ?></p>

Himoya:

// ✅
<p><?= htmlspecialchars($izoh, ENT_QUOTES, 'UTF-8') ?></p>

Qo'shimcha himoya qavatlari:

  • Sessiya cookie si httponly — JavaScript uni o'qiy olmaydi
  • Content-Security-Policy sarlavhasi — brauzerga qaysi skriptlarni bajarishga ruxsat borligini aytadi:
<?php

header("Content-Security-Policy: default-src 'self'; script-src 'self'");

Endi sahifaga qandaydir yo'l bilan <script> kirib qolsa ham — brauzer faqat sizning domeningizdagi skript fayllarini bajaradi, inline skriptlarni bloklaydi.


3. CSRF — Cross-Site Request Forgery

Bu yangi hujum turi. Diqqat bilan o'qing.

Vaziyat: foydalanuvchi sizning bankingiz saytiga kirgan (sessiya cookie si brauzerida bor). Keyin u boshqa tabda "Bepul iPhone yutib oling!" degan saytni ochdi. O'sha saytda yashirin forma bor:

<form action="https://sizning-bank.uz/otkazma" method="post" id="f">
    <input type="hidden" name="kimga" value="hujumchi_hisobi">
    <input type="hidden" name="summa" value="5000000">
</form>
<script>document.getElementById('f').submit();</script>

Brauzer bu formani sizning saytingizga yuboradi — va foydalanuvchining cookie sini qo'shib yuboradi. Sizning serveringiz uchun bu oddiy, login qilgan foydalanuvchidan kelgan to'g'ri so'rov. Pul o'tkazildi.

Foydalanuvchi hech narsa bosmadi. Hech qanday parol so'ralmadi.

Himoya: CSRF token

Har bir formaga hujumchi bilmaydigan tasodifiy qiymat qo'shamiz:

<?php
// src/csrf.php

function csrfToken(): string
{
    if (empty($_SESSION['csrf'])) {
        $_SESSION['csrf'] = bin2hex(random_bytes(32));
    }
    return $_SESSION['csrf'];
}

function csrfMaydon(): string
{
    return '<input type="hidden" name="_csrf" value="' . csrfToken() . '">';
}

function csrfTekshir(): void
{
    $kelgan = $_POST['_csrf'] ?? '';
    if (!hash_equals($_SESSION['csrf'] ?? '', $kelgan)) {
        http_response_code(419);
        exit("So'rov muddati o'tgan. Sahifani yangilab, qayta urinib ko'ring.");
    }
}

Formada:

<form method="post" action="/otkazma">
    <?= csrfMaydon() ?>
    <input name="kimga">
    <input name="summa">
    <button>O'tkazish</button>
</form>

Qayta ishlashda — birinchi qator:

<?php

if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    csrfTekshir();
    // ...
}

Hujumchining sayti foydalanuvchining sessiyasidagi tokenni bilmaydi va o'qiy olmaydi (brauzer boshqa saytning sahifasini o'qishga ruxsat bermaydi). Shuning uchun uning soxta formasi rad etiladi.

hash_equals() — oddiy === o'rniga. U har doim bir xil vaqtda ishlaydi, shuning uchun javob vaqtini o'lchab tokenni harfma-harf topish mumkin emas (timing attack).

Qo'shimcha himoya: SameSite cookie

<?php

session_set_cookie_params(['samesite' => 'Lax', 'httponly' => true, 'secure' => true]);

SameSite=Lax — brauzer boshqa saytdan kelgan POST so'rovlarga cookie qo'shmaydi. Zamonaviy brauzerlarda bu CSRF ning ko'p qismini to'xtatadi. Lekin eski brauzerlar va ba'zi holatlar uchun token baribir kerak.

[!TIP] Laravel da @csrf direktivasi va VerifyCsrfToken middleware aynan shu ishni avtomatik bajaradi. Endi siz uning ichida nima borligini bilasiz.


4. Sessiya o'g'irlash (Session Hijacking)

Hujum: hujumchi foydalanuvchining sessiya ID sini qo'lga kiritadi (XSS orqali, ochiq Wi-Fi da shifrlanmagan trafikdan, URL dagi ID dan) va uning nomidan kiradi.

Himoya:

<?php

ini_set('session.use_strict_mode', '1');    // noma'lum ID larni qabul qilmaslik
ini_set('session.use_only_cookies', '1');   // ID faqat cookie da, URL da hech qachon

session_set_cookie_params([
    'httponly' => true,    // XSS orqali o'g'irlab bo'lmaydi
    'secure'   => true,    // faqat HTTPS
    'samesite' => 'Lax',
]);
session_start();

Va har doim:

  • Login da session_regenerate_id(true) — session fixation dan himoya
  • Logout da session_destroy()
  • Butun saytda HTTPS — Let's Encrypt bilan bepul

5. Boshqa muhim qoidalar

Avtorizatsiya — "bu ma'lumot shu foydalanuvchinikimi?"

Eng ko'p e'tibordan chetda qoladigan xato:

<?php

// ❌ Har kim ID ni o'zgartirib, boshqaning buyurtmasini ko'radi
$stmt = $pdo->prepare('SELECT * FROM buyurtmalar WHERE id = ?');
$stmt->execute([$_GET['id']]);

// ✅ Faqat o'zining buyurtmasi
$stmt = $pdo->prepare('SELECT * FROM buyurtmalar WHERE id = ? AND user_id = ?');
$stmt->execute([$_GET['id'], $_SESSION['user_id']]);

Bu IDOR (Insecure Direct Object Reference) deyiladi. /buyurtma/1043 → /buyurtma/1044 — hujumchi faqat raqamni o'zgartiradi.

Xatolarni yashirish

display_errors = Off
log_errors = On

Fayllarni veb-ildizdan tashqarida saqlash

Faqat public/ ochiq. config.php, .env, vendor/, src/, uploads/ — undan tashqarida.

Bog'liqliklarni yangilab turish

composer audit

O'rnatilgan paketlarda ma'lum zaifliklar bormi — tekshiradi.


Xavfsizlik ro'yxati

Har bir loyihani ishga tushirishdan oldin:

Tekshiruv
☐ Barcha SQL — prepared statements
☐ Barcha chiqish — htmlspecialchars
☐ Barcha POST formalarda — CSRF token
☐ Parollar — password_hash
☐ Sessiya cookie — httponly, secure, samesite
☐ Login da session_regenerate_id(true)
☐ Har bir so'rovda "bu foydalanuvchiga ruxsat bormi?" tekshiruvi
☐ Fayl yuklash — MIME tekshiruv, tasodifiy nom, PHP bajarilmaydi
☐ display_errors = Off
☐ HTTPS
☐ .env, config.php — veb-ildizdan tashqarida va Git da yo'q
☐ composer audit toza

Nima uchun shunday?

Nima uchun veb-xavfsizlik bunchalik murakkab — nega brauzer o'zi himoya qilmaydi?

Chunki veb "ochiqlik" uchun yaratilgan: istalgan sayt istalgan saytga havola bera oladi, forma yubora oladi, rasm yuklay oladi. Bu ochiqlik internetni internet qilgan narsa. Lekin u har bir saytni potentsial hujum manbaiga ham aylantiradi. Brauzerlar yillar davomida himoya qavatlarini qo'shib kelgan (Same-Origin Policy, SameSite, CSP), lekin ular faqat siz to'g'ri sozlasangiz ishlaydi. Oxirgi himoya chizig'i — har doim sizning server kodingiz.


Xulosa

Eslab qoling:

  • SQL injection → prepared statements
  • XSS → htmlspecialchars + httponly cookie + CSP
  • CSRF → har bir POST formada token + hash_equals + SameSite
  • Sessiya o'g'irlash → httponly, secure, strict mode, session_regenerate_id, HTTPS
  • IDOR → har bir so'rovda egalikni tekshiring (AND user_id = ?)
  • Framework bularning ko'pini avtomatik qiladi — lekin qanday ishlashini bilish shart

Keyingi dars

44-dars: Laravel ga kirish — nima uchun framework kerak