Asosiy matnga o'tish
Blog

Veb

CORS noto'g'ri sozlanganda: Origin'ni aks ettirish, wildcard va null

CORS himoya emas, balki brauzerga beriladigan ruxsat. Noto'g'ri sozlansa, begona sayt foydalanuvchi nomidan API'ingizdan ma'lumot o'qiydi. curl bilan tekshirish va to'g'ri sozlash.

· 9 daq. o'qish

Foto: Nenea hartia, CC BY-SA 4.0 · Wikimedia Commons

CORS (Cross-Origin Resource Sharing) haqida dasturchilar ko'pincha bitta holatda o'ylaydi: frontend API'ga so'rov yuboradi va brauzer konsolida qizil xato chiqadi. Tez yechim sifatida internetdan topilgan "hammasiga ruxsat" sozlamasi qo'yiladi va xato yo'qoladi. Bu sozlama production'ga ham o'tadi va keyin hech kim unga qaytmaydi.

Bu maqolada CORS aslida nima qilishini, qaysi sozlamalar xavfli ekanini, ularni curl bilan qanday tekshirishni va Laravel, Node hamda nginx'da qanday to'g'ri sozlashni ko'rsatamiz.

CORS nima va nima emas

Brauzerda Same-Origin Policy degan asosiy qoida bor: https://evil.example sahifasidagi JavaScript https://api.your-domain.uz ga so'rov yuborishi mumkin, lekin javobni o'qiy olmaydi. Origin — bu sxema, domen va port birikmasi: https://app.your-domain.uz va https://api.your-domain.uz turli origin hisoblanadi.

CORS — bu qoidadan ongli ravishda istisno qilish mexanizmi. Server javobga quyidagi headerlarni qo'shib, brauzerga "bu origin'ga javobni o'qishga ruxsat ber" deydi:

Access-Control-Allow-Origin: https://app.your-domain.uz
Access-Control-Allow-Credentials: true

Ikki muhim xulosa:

  • CORS himoya qatlami emas, ruxsat qatlami. U cheklovni yumshatadi, kuchaytirmaydi. Har bir noto'g'ri qiymat — qo'shimcha ochilgan eshik.
  • CORS faqat brauzerda ishlaydi. curl, server yoki mobil ilova CORS'ga e'tibor bermaydi. Shuning uchun CORS avtorizatsiya o'rnini bosmaydi: API har bir so'rovda foydalanuvchini o'zi tekshirishi kerak.

Nima uchun bu ekspertiza uchun muhim

CORS xatosining xavfi — foydalanuvchining brauzeri hujum vositasiga aylanishida. Foydalanuvchi sizning tizimingizga kirgan holda begona sahifani ochadi. Agar API cookie bilan ishlasa va CORS istalgan origin'ga ishonch bildirsa, o'sha sahifadagi skript foydalanuvchi nomidan so'rov yuborib, javobni — profil, hisobotlar, tokenlar — o'qib oladi va o'z serveriga jo'natadi.

Ekspertizada bu "Security Misconfiguration" yoki ma'lumot ochiqlanishi sifatida baholanadi. Uni topish oson: bir nechta curl so'rovi yetarli. Shuning uchun bu band ekspertizadan oldin albatta tekshirilishi kerak bo'lgan sozlamalar qatoriga kiradi.

Xavfli holat 1: Origin'ni aks ettirish + credentials

Eng jiddiy xato. Server so'rovdagi Origin headerini olib, javobga o'zgarishsiz qaytaradi va cookie'larga ruxsat beradi:

Access-Control-Allow-Origin: https://evil.example
Access-Control-Allow-Credentials: true

Bu amalda "har qanday sayt foydalanuvchi nomidan API'ni o'qishi mumkin" degani. Ko'pincha bu quyidagicha kod natijasi:

// XATO
app.use(cors({ origin: true, credentials: true }));

origin: true — cors paketida "kelgan Origin'ni aks ettir" degan ma'noni beradi.

Xavfli holat 2: wildcard

Access-Control-Allow-Origin: * — "har qanday origin javobni o'qishi mumkin". Brauzerlar * ni Allow-Credentials: true bilan birga qabul qilmaydi, shuning uchun cookie bilan himoyalangan ma'lumot to'g'ridan-to'g'ri o'qilmaydi. Lekin * baribir xavfli bo'lishi mumkin:

  • API ichki tarmoqdagi yoki IP bo'yicha cheklangan resurslarni autentifikatsiyasiz qaytarsa.
  • Token cookie'da emas, lekin boshqa "ambient" usul bilan (masalan, IP ruxsati) beriladigan bo'lsa.
  • Dasturchi * ishlamagani uchun keyinroq uni "Origin'ni aks ettirish" ga almashtirsa — bu esa 1-holatga olib keladi.

Ommaviy, haqiqatan ochiq ma'lumot (masalan, valyuta kurslari) uchun * qabul qilinadi. Shaxsiy kabinet API'si uchun — yo'q.

Xavfli holat 3: null origin

Ba'zi sozlamalarda ruxsat etilganlar ro'yxatida null turadi — ko'pincha lokal fayllarni sinash uchun qo'shilgan. Lekin Origin: null ni hujumchi ham yuborishi mumkin: sandbox qilingan iframe, data: URL yoki file:// sahifasidan kelgan so'rovlar shu qiymat bilan yuboriladi. null ni hech qachon ruxsat etilgan origin sifatida qo'ymang.

Xavfli holat 4: noto'g'ri tekshirish (regex va endsWith)

Ruxsat etilgan origin'larni tekshirish kodida xato bo'lsa, ro'yxat bor bo'lsa ham u chetlab o'tiladi:

// XATO: evilyour-domain.uz ham, your-domain.uz.evil.example ham o'tadi
if (origin.endsWith('your-domain.uz') || origin.includes('your-domain.uz')) { ... }

// XATO: nuqta qochirilmagan, langar yo'q
/https:\/\/.*.your-domain.uz/

To'g'ri usul — aniq ro'yxat bo'yicha to'liq tenglik yoki qat'iy langarlangan regex:

/^https:\/\/([a-z0-9-]+\.)?your-domain\.uz$/

Yana bir eslatma: http:// origin'larni (shifrlanmagan) production ro'yxatiga qo'shmang — tarmoqdagi hujumchi ularning nomidan kontent kirita oladi.

curl bilan qanday tekshirish

Begona origin bilan so'rov yuboring va javobdagi Access-Control-* headerlarini ko'ring:

curl -si https://api.your-domain.uz/v1/me \
  -H "Origin: https://evil.example" | grep -i access-control

curl -si https://api.your-domain.uz/v1/me \
  -H "Origin: null" | grep -i access-control

curl -si https://api.your-domain.uz/v1/me \
  -H "Origin: https://your-domain.uz.evil.example" | grep -i access-control

Preflight (OPTIONS) so'rovini ham tekshiring — PUT, DELETE yoki maxsus headerli so'rovlardan oldin brauzer aynan shuni yuboradi:

curl -si -X OPTIONS https://api.your-domain.uz/v1/profile \
  -H "Origin: https://evil.example" \
  -H "Access-Control-Request-Method: DELETE" \
  -H "Access-Control-Request-Headers: authorization" | grep -i access-control

Natijani qanday o'qish:

  • Begona origin javobda qaytsa va Allow-Credentials: true bo'lsa — jiddiy topilma.
  • Allow-Origin: null qaytsa — topilma.
  • * qaytsa — endpoint qanday ma'lumot berishiga qarab baholang.
  • Begona origin uchun Access-Control-Allow-Origin umuman yo'q — to'g'ri.

Barcha asosiy endpointlarni, jumladan login, profil, fayl yuklab olish va admin API'larini sinang. Ba'zan CORS umumiy middleware'da emas, alohida kontrollerda qo'lda yozilgan bo'ladi.

Laravel'da to'g'ri sozlash

Laravel CORS'ni o'rnatilgan HandleCors middleware va config/cors.php orqali boshqaradi (Laravel 11+ da faylni php artisan config:publish cors bilan chiqarish mumkin):

return [
    'paths' => ['api/*', 'sanctum/csrf-cookie'],
    'allowed_methods' => ['GET', 'POST', 'PUT', 'PATCH', 'DELETE'],
    'allowed_origins' => [
        'https://app.your-domain.uz',
        'https://admin.your-domain.uz',
    ],
    'allowed_origins_patterns' => [],
    'allowed_headers' => ['Content-Type', 'Authorization', 'X-Requested-With', 'X-XSRF-TOKEN'],
    'exposed_headers' => [],
    'max_age' => 600,
    'supports_credentials' => true,
];

E'tibor bering:

  • allowed_origins da '*' va supports_credentials => true birga turmasin.
  • Origin'larni muhitga qarab .env dan o'qish qulay, lekin production qiymati aniq domenlar ro'yxati bo'lishi kerak.
  • allowed_origins_patterns ishlatsangiz, regex ^ va $ bilan langarlangan, nuqtalar qochirilgan bo'lsin.

Node (Express) da to'g'ri sozlash

const allowed = new Set([
  'https://app.your-domain.uz',
  'https://admin.your-domain.uz',
]);

app.use(cors({
  origin(origin, cb) {
    // Origin yo'q — brauzerdan tashqari so'rov (curl, server); CORS headeri kerak emas
    if (!origin) return cb(null, false);
    cb(null, allowed.has(origin));
  },
  credentials: true,
  methods: ['GET', 'POST', 'PUT', 'PATCH', 'DELETE'],
  maxAge: 600,
}));

cors paketi origin dinamik bo'lganda Vary: Origin headerini qo'shadi. Bu muhim: aks holda proksi yoki CDN bitta origin uchun berilgan javobni keshlab, boshqasiga ham qaytarishi mumkin.

nginx darajasida

Agar CORS headerlarini nginx qo'shsa, $http_origin ni to'g'ridan-to'g'ri qaytarmang — avval map bilan tekshiring:

map $http_origin $cors_origin {
    default "";
    "https://app.your-domain.uz"   $http_origin;
    "https://admin.your-domain.uz" $http_origin;
}

server {
    location /api/ {
        add_header Access-Control-Allow-Origin $cors_origin always;
        add_header Access-Control-Allow-Credentials "true" always;
        add_header Vary Origin always;
        # ...
    }
}

Bo'sh qiymatli add_header nginx tomonidan yuborilmaydi, shuning uchun ro'yxatda yo'q origin header olmaydi. Bitta joyda sozlang: CORS ham ilovada, ham nginx'da qo'shilsa, takroriy headerlar paydo bo'ladi va brauzer javobni rad etadi.

Bog'liq mavzular

CORS cookie bilan ishlaydigan API'larda CSRF bilan yaqin bog'liq: CORS javobni o'qishni boshqaradi, lekin so'rov yuborilishini to'xtatmaydi. Shuning uchun holatni o'zgartiruvchi so'rovlar CSRF token yoki SameSite cookie bilan alohida himoyalanishi kerak. Token qayerda saqlanishi haqida JWT maqolasida yozganmiz, API bo'yicha umumiy ro'yxat esa OWASP API Top 10 maqolasida.

CORS ro'yxati — bu "biz kimga ishonamiz" degan qaror. U qisqa, aniq va har bir qatori asoslangan bo'lishi kerak.

Checklist

  • Ruxsat etilgan origin'lar aniq ro'yxat; Origin aks ettirilmaydi.
  • * va Allow-Credentials: true birga ishlatilmaydi; shaxsiy API'da * yo'q.
  • null va http:// origin'lar ro'yxatda yo'q.
  • Regex tekshiruvlar langarlangan, nuqtalar qochirilgan; endsWith/includes ishlatilmaydi.
  • Dinamik origin bo'lsa, Vary: Origin yuboriladi.
  • Ruxsat etilgan usullar va headerlar minimal.
  • CORS bitta joyda (ilova yoki nginx) sozlangan.
  • API har bir so'rovda avtorizatsiyani CORS'dan mustaqil tekshiradi.
  • Begona, null va o'xshash domenli origin'lar bilan curl tekshiruvi o'tkazilgan.

Xulosa

CORS xatosi kodda emas, bitta konfiguratsiya qatorida yashaydi va ko'pincha "vaqtincha" qo'yilgan bo'ladi. Uni topish ham, tuzatish ham bir necha daqiqa oladi — faqat buni ekspertizadan oldin qilish kerak.

API'ingiz qaysi origin'larga ishonayotganini tekshirmoqchimisiz? Skanerlash uchun ariza qoldiring — Claude AI agenti sozlamalar va kodni ko'rib chiqadi, mutaxassisimiz topilmalarni tasdiqlab, ularni yopishga yordam beradi.