Asosiy matnga o'tish
Blog

Veb

CSRF va SameSite cookie: foydalanuvchi nomidan yuborilgan so'rovlar

CSRF qanday ishlaydi, SameSite cookie undan qanchalik himoya qiladi, CSRF token, cookie va bearer token'li API'lar hamda CORS bilan bog'liqlik. Laravel va Node misollari bilan.

· 9 daq. o'qish

Foto: Gugalcrom123, CC BY-SA 4.0 · Wikimedia Commons

Cross-Site Request Forgery (CSRF) — foydalanuvchi o'zi bilmagan holda, o'z sessiyasi bilan sizning saytingizga so'rov yuborib qo'yadigan hujum. Foydalanuvchi sizning tizimingizga kirgan, keyin boshqa sahifani ochgan. O'sha sahifa yashirin forma orqali sizning saytingizga POST yuboradi. Brauzer esa odatiga ko'ra so'rovga sizning saytingiz cookie'larini qo'shadi — va server buni haqiqiy foydalanuvchi amali deb qabul qiladi.

So'nggi yillarda brauzerlar SameSite cookie atributini joriy qilgani sababli CSRF ancha qiyinlashdi. Lekin "endi CSRF yo'q" degan xulosa noto'g'ri. Ushbu maqolada CSRF qanday ishlashini, SameSite nimani yopadi va nimani yopmasligini, tokenlar, API'lar va CORS o'rtasidagi bog'liqlikni ko'rib chiqamiz.

Hujum qanday ko'rinadi

Tasavvur qiling, ilovangizda email manzilni o'zgartirish endpoint'i bor:

POST /profile/email
Cookie: session=...
email=new@example.uz

Hujumchi o'z sahifasiga quyidagini joylashtiradi:

<form action="https://app.example.uz/profile/email" method="POST" id="f">
  <input type="hidden" name="email" value="attacker@evil.example">
</form>
<script>document.getElementById('f').submit();</script>

Agar foydalanuvchi tizimga kirgan bo'lsa va server faqat sessiya cookie'siga tayansa, email almashadi. Keyin hujumchi "parolni tiklash" orqali akkauntni egallaydi. Xuddi shu usul bilan pul o'tkazish, rol o'zgartirish, ma'lumot o'chirish kabi amallarni bajarish mumkin.

E'tibor bering: hujumchi javobni o'qiy olmaydi. CSRF — "ko'r" hujum, uning maqsadi ma'lumot o'g'irlash emas, balki holatni o'zgartirish.

Nima uchun bu ekspertiza uchun muhim

CSRF CWE-352 sifatida tasniflanadi va OWASP Top 10 (2021) da A01 "Broken Access Control" toifasiga kiritilgan. OWASP ASVS esa holatni o'zgartiruvchi so'rovlar uchun CSRF himoyasini alohida talab qiladi. Ekspertizada odatda quyidagilar tekshiriladi:

  • Holatni o'zgartiruvchi formalarda CSRF token bormi va server uni haqiqatan tekshiradimi.
  • Sessiya cookie'larida SameSite, Secure, HttpOnly atributlari o'rnatilganmi.
  • GET so'rovi orqali holat o'zgarmaydimi.
  • CORS sozlamalari begona domenga cookie bilan so'rov yuborib, javobni o'qishga ruxsat bermaydimi.

SameSite: nimani yopadi, nimani yopmaydi

SameSite atributi brauzerga cookie'ni boshqa saytdan boshlangan so'rovlarga qo'shish-qo'shmaslikni aytadi:

  • Strict — cookie faqat o'z saytingiz ichidagi so'rovlarda yuboriladi. Boshqa saytdagi havoladan kelganda ham foydalanuvchi "kirilmagan" holatda bo'ladi.
  • Lax — boshqa saytdan kelgan oddiy navigatsiyada (havola orqali GET) cookie yuboriladi, lekin POST formalar, fetch, iframe va rasmlarda yuborilmaydi.
  • None — cookie hamma joyda yuboriladi. Bu holda Secure majburiy.

Zamonaviy brauzerlarning ko'pchiligi atribut ko'rsatilmagan cookie'ni Lax deb hisoblaydi. Laravel ham sessiya cookie'si uchun sukut bo'yicha lax ishlatadi (config/session.php dagi same_site).

Lax klassik POST CSRF'ni yopadi. Ammo u to'liq himoya emas:

  1. GET orqali holat o'zgarishi. Agar /logout, /delete?id=5 yoki /approve?id=7 GET bilan ishlasa, Lax cookie yuboradi va hujum ishlaydi.
  2. "Site" va "origin" farqi. SameSite sayt darajasida ishlaydi: app.example.uz va blog.example.uz bir sayt hisoblanadi. Agar subdomenlardan birida XSS bo'lsa yoki u boshqa tomonga topshirilgan bo'lsa, u yerdan yuborilgan so'rov "same-site" bo'ladi va SameSite yordam bermaydi.
  3. SameSite=None kerak bo'lgan holatlar. Ilova boshqa saytga iframe ichida joylashtirilsa yoki uchinchi tomon integratsiyasi bo'lsa, cookie None ga o'tkaziladi va himoya yo'qoladi.
  4. Eski brauzerlar va maxsus mijozlar atributni har doim bir xil talqin qilmaydi.

SameSite — yaxshi qo'shimcha qatlam, lekin CSRF token'ning o'rnini bosmaydi.

CSRF token: asosiy himoya

Klassik himoya — synchronizer token: server sessiyaga tasodifiy token yozadi, har bir formaga uni yashirin maydon sifatida qo'shadi va har bir holatni o'zgartiruvchi so'rovda tekshiradi. Begona sayt bu tokenni bilmaydi va o'qiy olmaydi.

Laravel

Laravel'da CSRF himoyasi web middleware guruhida sukut bo'yicha yoqilgan. Blade formalarida:

<form method="POST" action="/profile/email">
    @csrf
    <input type="email" name="email">
</form>

Axios va Inertia XSRF-TOKEN cookie'sini o'qib, X-XSRF-TOKEN headerida avtomatik yuboradi. Tekshirish kerak bo'lgan asosiy joy — istisnolar ro'yxati. Laravel 11+ da bootstrap/app.php:

->withMiddleware(function (Middleware $middleware) {
    $middleware->validateCsrfTokens(except: [
        'webhooks/payment',   // faqat haqiqiy tashqi webhook'lar
    ]);
})

Istisnolarga faqat tashqi xizmatlar chaqiradigan webhook'larni qo'shing va ularni imzo (HMAC) bilan tekshiring. "Ishlamayapti, shuning uchun istisnoga qo'shdim" degan 'api/*' yoki '*' — keng tarqalgan va jiddiy xato.

Node (Express)

Ilgari keng ishlatilgan csurf paketi eskirgan deb belgilangan. Uning o'rniga double-submit cookie naqshini amalga oshiradigan kutubxonalardan foydalaning yoki minimal himoyani o'zingiz yozing: Origin headerini tekshirish va token.

const ALLOWED_ORIGINS = new Set(['https://app.example.uz']);

function verifyOrigin(req, res, next) {
  if (['GET', 'HEAD', 'OPTIONS'].includes(req.method)) return next();
  const origin = req.get('Origin') || '';
  if (!ALLOWED_ORIGINS.has(origin)) {
    return res.status(403).json({ error: 'Invalid origin' });
  }
  next();
}

app.use(verifyOrigin);

Origin tekshiruvi zamonaviy brauzerlarda yaxshi ishlaydi, chunki POST so'rovlarida brauzer bu headerni o'zi qo'yadi va JavaScript uni soxtalashtira olmaydi. Qo'shimcha ravishda Sec-Fetch-Site headeridan ham foydalanish mumkin: cross-site qiymatli holatni o'zgartiruvchi so'rovlarni rad eting.

Sessiya cookie'si uchun:

app.use(session({
  secret: process.env.SESSION_SECRET,
  cookie: { httpOnly: true, secure: true, sameSite: 'lax' },
}));

CSRF'ning ildizi — brauzer cookie'ni avtomatik qo'shishi. Shuning uchun API'da autentifikatsiya qanday qilinishi hal qiluvchi:

  • Bearer token (Authorization: Bearer ...) — brauzer bu headerni o'zi qo'shmaydi, uni JavaScript qo'yishi kerak. Begona sayt tokenni bilmaydi, demak CSRF amalda mumkin emas. Lekin token localStorage da saqlansa, XSS uni o'g'irlashi mumkin — bu boshqa xavf.
  • Cookie asosidagi API (SPA, Sanctum stateful) — brauzer cookie'ni avtomatik yuboradi, demak CSRF himoyasi kerak. Laravel Sanctum SPA rejimida shuning uchun avval /sanctum/csrf-cookie chaqiriladi va keyingi so'rovlar X-XSRF-TOKEN bilan yuboriladi.

Sanctum'da SANCTUM_STATEFUL_DOMAINS ro'yxatiga faqat o'z frontend domenlaringizni yozing. Mobil ilova uchun esa cookie emas, token rejimidan foydalaning.

Bir xato tez-tez uchraydi: API "JSON qabul qiladi, demak forma bilan hujum qilib bo'lmaydi" deb CSRF tekshiruvi o'chiriladi. Agar server Content-Type ni qat'iy tekshirmasa va text/plain yoki application/x-www-form-urlencoded tanasini ham JSON sifatida o'qisa, oddiy forma bilan hujum qilish mumkin bo'lib qoladi.

CORS bilan bog'liqlik

CORS va CSRF ko'pincha chalkashtiriladi. Muhim nuqtalar:

  1. CORS CSRF'dan himoya qilmaydi. CORS faqat begona sahifa javobni o'qishi mumkinmi, shuni boshqaradi. Oddiy so'rovlar (forma POST, text/plain) preflight'siz yuboriladi va server ularni bajaradi — javob o'qilmasa ham.
  2. Noto'g'ri CORS CSRF'ni kuchaytiradi. Agar server istalgan Origin ni aks ettirib, Access-Control-Allow-Credentials: true qaytarsa, begona sayt cookie bilan so'rov yuborib, javobni ham o'qiy oladi — jumladan, CSRF tokenni. Shunda token himoyasi ham yiqiladi.
  3. Preflight foydali, lekin yagona himoya emas. Content-Type: application/json yoki maxsus header preflight'ni majburlaydi va to'g'ri sozlangan CORS uni rad etadi. Lekin bu faqat server Content-Type ni qat'iy tekshirsagina ishlaydi.

Laravel'da config/cors.php:

'paths' => ['api/*', 'sanctum/csrf-cookie'],
'allowed_origins' => ['https://app.example.uz'],
'supports_credentials' => true,

allowed_origins ga * yozib, supports_credentials ni true qilish mumkin emas — buni to'g'ri sozlang.

O'zingiz qanday tekshirishingiz mumkin

Token haqiqatan tekshiriladimi

Brauzerda tizimga kiring, DevTools orqali holatni o'zgartiruvchi so'rovni "Copy as cURL" qiling, keyin tokenni olib tashlab qayta yuboring:

# Token bilan — 200/302 kutiladi
curl -si -X POST https://staging.example.uz/profile/email \
  -H "Cookie: laravel_session=..." \
  -d "_token=VALID&email=test@example.uz"

# Tokensiz — 419 (Laravel) yoki 403 kutiladi
curl -si -X POST https://staging.example.uz/profile/email \
  -H "Cookie: laravel_session=..." \
  -d "email=test@example.uz"

Ikkinchi so'rov muvaffaqiyatli bo'lsa, himoya ishlamayapti.

Origin va CORS

curl -si https://staging.example.uz/api/user \
  -H "Origin: https://evil.example" \
  -H "Cookie: laravel_session=..." | grep -i "access-control"

Javobda Access-Control-Allow-Origin: https://evil.example va Access-Control-Allow-Credentials: true birga chiqsa, bu jiddiy muammo.

curl -si https://staging.example.uz/login | grep -i set-cookie

Sessiya cookie'sida Secure, HttpOnly va SameSite=Lax (yoki Strict) bo'lishi kerak.

GET bilan holat o'zgarishi

Marshrutlar ro'yxatini ko'rib chiqing:

php artisan route:list --method=GET | grep -iE "delete|remove|logout|approve|toggle"

Holatni o'zgartiruvchi amallar POST, PUT, PATCH yoki DELETE bo'lishi kerak.

Qisqa checklist

  • Barcha holatni o'zgartiruvchi so'rovlar CSRF token yoki Origin tekshiruvi bilan himoyalangan.
  • CSRF istisnolari ro'yxatida faqat imzo bilan tekshiriladigan webhook'lar bor.
  • GET so'rovlari holatni o'zgartirmaydi.
  • Sessiya cookie'larida Secure, HttpOnly, SameSite=Lax yoki Strict o'rnatilgan.
  • Cookie asosidagi SPA/API uchun CSRF himoyasi yoqilgan, Sanctum stateful domenlari aniq ko'rsatilgan.
  • Server Content-Type ni qat'iy tekshiradi.
  • CORS'da Origin aks ettirilmaydi, credentials faqat aniq domenlar uchun.
  • Subdomenlar nazorat ostida, ularda XSS yo'qligi tekshirilgan.

Xulosa

SameSite cookie CSRF'ni ancha qiyinlashtirdi, lekin uni yo'q qilmadi. Ishonchli himoya bir necha qatlamdan iborat: CSRF token yoki Origin tekshiruvi, holatni faqat POST/PUT/DELETE orqali o'zgartirish, to'g'ri cookie atributlari va qat'iy CORS. Bu sozlamalar ko'pincha mavjud, lekin istisnolar ro'yxati yoki "vaqtincha" o'chirilgan tekshiruv tufayli ishlamay qoladi — ekspertiza aynan shunday joylarni topadi.

Formalaringiz va API'ingizdagi CSRF himoyasini ekspertizadan oldin tekshirmoqchimisiz? Skanerlash uchun ariza qoldiring — Claude AI agenti marshrutlar, middleware va cookie sozlamalarini ko'rib chiqadi, mutaxassisimiz esa topilgan teshiklarni yopishga yordam beradi.