Mundarija (32)
- Bu darsda
- 1. Nega bu kerak?
- 2. Ro'yxat
- 3. Kim va nimaga: API1, API2, API3, API5
- 3.1 API1 — BOLA
- 3.2 API2 — Broken Authentication
- 3.3 API3 — BOPLA
- 3.4 API5 — BFLA
- 4. Qancha: API4 va API6
- 5. Atrof: API7–API10
- 6. Hujumchi nigohi
- 7. Bog'liqliklar: 7 kun qoidasi
- 8. Ko'p uchraydigan xatolar
- 9. Mashqlar
- 1-mashq (oson): toifani toping
- 2-mashq (o'rta): ruxsat ro'yxati bilan javob
- 3-mashq (qiyin): inventar tekshiruvi
- 10. Loyiha qadami: OWASP auditi
- 10.1 docs/OWASP-API.md
- 10.2 test/owasp-api.test.ts
- 10.3 .env.example va hujjatlar
- 10.4 Tekshiruv va commit
- 11. Frontend'ni haqiqiy kirishga ulash
- 11.1 Qayerdan boshlaymiz
- 11.2 Birinchi urinish: proxy tuzog'i
- 11.3 O'zgarishlar
- 11.4 Natija
- 11.5 22-qism testlarini yangilash
- 11.6 Frontend commit
- 12. Real ishda
- Xulosa
- Manbalar
OWASP API Security Top 10: vazifalar-api auditi, regressiya testlari va frontend'ni ulash
Qisqacha: OWASP API Security Top 10:2023 — API'larga xos 10 xavf. Ular: begona obyektga ID orqali kirish (BOLA), kimlik xatolari, ortiqcha maydonlar (BOPLA), cheklovsiz resurs sarfi va ruxsatsiz funksiya (BFLA). Yana: biznes oqimlarini suiiste'mol qilish, SSRF, noto'g'ri sozlama, unutilgan endpoint'lar va tashqi API'larga ko'r-ko'rona ishonish. Qism yakunida
vazifalar-apishu ro'yxat bo'yicha tekshirildi. Natija — har toifa uchun "qanday ko'rinadi → qaysi test → qanday yopilgan" jadvali va 7 ta regressiya testi. Eng qimmatli ustun — 28-qism davomida haqiqatan topilgan zaifliklar: 25–27-qismlardagi kodimizda ham teshiklar bor edi. Oxirida frontend haqiqiy kirishga ulanadi va 22-qism testlari yangi API'ga moslanadi.
Bu darsda
- API1–API10:2023 toifalarini nomi, misoli va himoyasi bilan aytib bera olasiz.
- 28-qismda
vazifalar-apiva frontend'da topilgan haqiqiy zaifliklarni toifalarga ajratasiz. - BOPLA'ni javob kalitlarini rekursiv tekshirib sinaysiz.
- Bog'liqliklar uchun "7 kun qoidasi" buzilganini qanday topish va tuzatishni ko'rasiz.
docs/OWASP-API.md,owasp-api.test.tsva.env.exampleni qo'shasiz; frontend'ni server sessiyasiga ulab, uning testlarini yangilaysiz.
Oldin bilishingiz kerak: OWASP Top 10:2025 xaritasi, RBAC va resurs egaligi, SSRF va tashqi URL'lar bilan ishlash, CAPTCHA tokenini serverda tekshirish, Tokenni qayerda saqlash va CSRF.
28-qism boshida OWASP Top 10:2025 xaritasi darsida API ro'yxatining birinchi to'rt qatorini ko'rgan va "to'liq ro'yxat — qism oxirida" degan edik. Shu payt keldi. Endi bu ro'yxat biz uchun nazariya emas: har qatorining orqasida o'tgan darslardagi kod va test turibdi.
1. Nega bu kerak?
Uyni qurib bo'lgach, quruvchi chiqib ketishdan oldin nazoratchi keladi. U qo'lidagi ro'yxat bo'yicha yuradi: elektr, gaz, quvur, zinapoya panjarasi. "Hammasi joyidami?" deb emas — har bandni alohida tekshiradi. Ro'yxat — xotiraga ishonmaslik uchun.
API Top 10 — xuddi shunday ro'yxat. Biz 28-qism davomida 30 dars bo'yicha himoya qo'ydik. Endi teskari yo'nalishda yuramiz: ro'yxatni olib, har band uchun vazifalar-api ga hujum qilib ko'ramiz. Natija — ikki narsa:
- hujjat (
docs/OWASP-API.md) — auditor, yangi jamoa a'zosi yoki o'zingiz uchun bir yildan keyin; - regressiya testlari (
owasp-api.test.ts) — kelajakdagi o'zgarish eski teshikni qaytarsa, test yiqiladi.
Nega veb Top 10 yetmaydi? API'da HTML va brauzer sahifasi yo'q, lekin obyektlar, ID'lar va ommaviy so'rovlar ko'p. API ro'yxati shu farqqa qaratilgan. Joriy nashr — 2023 (OWASP sahifasida 2026-10-28 holatida eng oxirgisi).
2. Ro'yxat
| Kod | Nomi | Qisqa ma'nosi |
|---|---|---|
| API1 | Broken Object Level Authorization | begona obyekt ID orqali (BOLA) |
| API2 | Broken Authentication | kimlik tasdig'i buzilgan |
| API3 | Broken Object Property Level Authorization | ruxsatsiz maydon (BOPLA) |
| API4 | Unrestricted Resource Consumption | cheklovsiz resurs |
| API5 | Broken Function Level Authorization | ruxsatsiz funksiya (BFLA) |
| API6 | Unrestricted Access to Sensitive Business Flows | biznes oqimini suiiste'mol |
| API7 | Server Side Request Forgery | SSRF |
| API8 | Security Misconfiguration | noto'g'ri sozlama |
| API9 | Improper Inventory Management | unutilgan endpoint'lar |
| API10 | Unsafe Consumption of APIs | tashqi API'ga ko'r ishonch |
Nomlarni tarjima qilmaymiz — hisobotlarda aynan shunday uchraydi. Uchta guruhga bo'lib ko'ramiz: kim va nimaga (API1–API3, API5), qancha (API4, API6), atrof (API7–API10).
3. Kim va nimaga: API1, API2, API3, API5
3.1 API1 — BOLA
BOLA (Broken Object Level Authorization) — foydalanuvchi boshqa odamning obyektiga ID orqali yetadi. Veb ro'yxatida u IDOR deb ataladi. vazifalar-api da ID'lar ketma-ket son: Aziz GET /v1/vazifalar/7 ni ko'rsa, /8 ni sinashga hech narsa to'sqinlik qilmaydi.
Himoya — uch qatlam (RBAC va resurs egaligi): egasi so'rovdan emas, sessiyadan; SQL'da egasi_id sharti; va Postgres RLS — WHERE unutilsa ham boshqa qator ko'rinmaydi.
Test bitta qoidani alohida tekshiradi: begona vazifaga 404, 403 emas. 403 "bunday vazifa bor, lekin sizniki emas" degani — mavjudlikni oshkor qiladi. 404 esa hech narsa aytmaydi.
Topilgan: 28-qism boshida ikkita BOLA chiqdi. Idempotency-Key keshi umumiy edi — Dilnoza Aziz bilan bir xil kalit yuborib, Azizning javobini oldi. Eksport ishlari esa egasiz saqlanardi. Ikkalasi ham 25-qismdan beri bor edi — auth yo'q paytda "egasi" tushunchasi yo'q edi. Bundan tashqari, 27-qismda API Postgres'ga superuser bilan ulanardi va RLS'ni chetlab o'tardi.
3.2 API2 — Broken Authentication
Login, sessiya, parol tiklash, OTP, 2FA, API kalit — 28-qismning katta qismi shu toifa. Test oddiy: sessiyasiz, soxta cookie va soxta Bearer bilan — hamma joyda 401.
Topilgan: parol tiklash so'rovi vaqt orqali email borligini oshkor qilardi: mavjud email 30.0 ms, yo'q email 12.8 ms. Xat yuborish fonga o'tgach — 16.6 va 17.6 ms, farq yo'qoldi (Email tasdiqlash va parol tiklash oqimlari). 2FA kodini esa bir muddat cheklovsiz terish mumkin edi — tezlik cheklovi qo'shilganda yopildi.
3.3 API3 — BOPLA
BOPLA (Broken Object Property Level Authorization) — obyektning o'zi sizniki, lekin uning ba'zi maydonlari sizga emas. Ikki yo'nalish:
- chiqish: javobda ortiqcha maydon — parol hash'i, telefon, ichki ID;
- kirish: so'rovda ortiqcha maydon —
egasiId,rol(bu — Backend'dagi injection va mass assignment dagi ommaviy tayinlash).
Kanon testi chiqish yo'nalishini qanday tekshiradi? Javobdagi hamma kalitlarni rekursiv yig'adi va "xavfli" nomlarni qidiradi. Brauzerda sinaymiz — men haqiqiy /v1/auth/men javobining shakli, yomon — ataylab buzilgan:
const ICHKI = /parol|hash|egasi|sir|token|bloklangan|telefon/i;
const kalitlar = (x) =>
x !== null && typeof x === "object"
? Object.entries(x).flatMap(([k, v]) => [k, ...kalitlar(v)])
: [];
const men = {
foydalanuvchi: { id: 1, email: "aziz@example.com",
toliqIsm: "Aziz Karimov" },
sessiya: { id: 1, eslabQol: false,
yaratilgan: "2026-10-28T11:20:52.913Z" },
};
const yomon = {
foydalanuvchi: { id: 1, email: "aziz@example.com",
parolHash: "$argon2id$…", telefon: "+998901234567" },
vazifalar: [{ id: 7, matn: "Non", egasiId: 1 }],
};
for (const [nom, javob] of [["men", men], ["yomon", yomon]]) {
console.log(nom, kalitlar(javob).filter((k) => ICHKI.test(k)));
}Konsolda:
men []
yomon [ 'parolHash', 'telefon', 'egasiId' ]kalitlar massiv ichiga ham kiradi: Object.entries massivda ham ishlaydi (kalitlari "0", "1" …), shuning uchun vazifalar[0].egasiId ham topildi. Bu test taqiq ro'yxati (denylist) — u faqat o'zi bilgan nomlarni ushlaydi. Asosiy himoya esa kodda: javob uchun ustunlar aniq tanlanadi (SELECT * yo'q), kirishda Zod strictObject — ruxsat ro'yxati. Test — xavfsizlik to'ri.
Topilgan: yangi zaiflik yo'q — 25-qismdagi strictObject qarori o'zini oqladi.
3.4 API5 — BFLA
BFLA (Broken Function Level Authorization) — oddiy foydalanuvchi admin funksiyasini chaqira oladi. BOLA "kimning obyekti?" deb so'raydi, BFLA — "bu amalni kim qila oladi?". vazifalar-api da: /v1/admin/*, API kalit boshqaruvi.
Himoya — rolKerak middleware: rol har so'rovda bazadan o'qiladi. Shuning uchun admin huquqi olib tashlansa, keyingi so'rovdayoq 403 — sessiya yangilanishini kutmaydi. Test: sessiyasiz — 401, oddiy foydalanuvchi — 403.
Tekshirib ko'ring: Dilnoza
DELETE /v1/vazifalar/12yubordi, 12-vazifa — Azizniki. Bu API1 mi yoki API5?
Javob
API1 (BOLA). Vazifani o'chirish funksiyasi Dilnozaga ruxsat etilgan — u o'z vazifalarini o'chira oladi. Muammo obyektda: bu vazifa unga tegishli emas. Agar Dilnoza POST /v1/admin/foydalanuvchilar/1/bloklash ni chaqirsa — bu API5: funksiyaning o'zi unga mumkin emas.
4. Qancha: API4 va API6
API4 Unrestricted Resource Consumption — oldingi ikki darsning mavzusi: tana 16 KB, sahifa ≤ 100, timeout'lar, tezlik cheklovi, argon2 semafori. Test: limit=100000 — 400, 20 KB tana — 413.
Topilgan: 27-qism oxirida 300 ta ketma-ket so'rovga birorta ham 429 yo'q edi. 200 parallel login paytida oddiy GET p99 — 3 283 ms (semafordan keyin 733 ms).
API6 Unrestricted Access to Sensitive Business Flows — har bir so'rov "to'g'ri", lekin oqimni avtomatlashtirish biznesga zarar: botlar ro'yxatdan o'tadi, SMS pumping, chiptalarni sotib olib qayta sotish. Himoya — CAPTCHA tokenini serverda tekshirish darsidagi Turnstile, asal idish va SMS byudjeti.
Topilgan: zaiflik sifatida emas — himoya umuman yo'q edi va 28-qismda qo'shildi.
5. Atrof: API7–API10
API7 SSRF — SSRF va tashqi URL'lar bilan ishlash. Topilgan: 27-qismda fetch(WEBHOOK_URL) hech qanday tekshiruvsiz edi.
API8 Security Misconfiguration — kod to'g'ri, sozlama noto'g'ri. Bu toifada eng ko'p topilma bo'ldi:
- eng kam huquq buzilgan: Postgres'dagi sukut huquqlar
vazifalar_apiroliga sessiyalar va 2FA siri jadvallarini ham ochib qo'ygan edi — ilova ularni ishlatmasa ham.REVOKEbilan yopildi (RBAC va resurs egaligi); - CSRF: bir saytdagi boshqa origin
chiqish-hammasini bajara olardi (Tokenni qayerda saqlash va CSRF); - frontend proxy:
changeOrigin: true— bu haqda darsning oxirida, frontend bo'limida.
API9 Improper Inventory Management — siz unutgan, lekin ishlab turgan endpoint'lar: eski versiya, test yo'li, hujjatda yo'q marshrut. Topilgan: 25-qismdan beri butun v1 router ildizga ham ulangan edi — eski mijozlar uchun /vazifalar versiyasiz ham ishlashi kerak edi. Natijada keyin qo'shilgan /eksportlar va yangi /auth/* yo'llari ham versiyasiz ochiq bo'lib qoldi: /auth/men va /v1/auth/men — ikkalasi ishlardi. Hozir ildizda faqat /vazifalar va /teglar qoldi — Deprecation va Sunset sarlavhalari bilan. Bu topilma API9 ning mohiyatini yaxshi ko'rsatadi: hech kim "eski yo'lga auth qo'shaman" deb o'ylamagan — u o'z-o'zidan paydo bo'ldi.
API10 Unsafe Consumption of APIs — tashqi xizmat javobiga ko'r-ko'rona ishonish. vazifalar-api uchta tashqi tomonni iste'mol qiladi: OIDC provayderi (state, nonce, PKCE va iss tekshiriladi), Telegram (hash va muddat), Turnstile (success === true, hostname, tarmoq xatosida rad). Topilgan: Turnstile test kaliti hostname: "example.com" qaytaradi — hujjat va .env.example ga yozildi.
6. Hujumchi nigohi
Hujumchi API'ni ko'rganda shu ro'yxat bo'yicha yuradi. Uning birinchi o'n daqiqasi:
| Sinaydi | Toifa | vazifalar-api javobi |
|---|---|---|
/v1/vazifalar/1, /2, /3 … boshqa hisobdan |
API1 | 404 |
| eskirgan yoki soxta cookie | API2 | 401 |
POST tanasiga egasiId, rol |
API3 | 422 |
?limit=100000, katta tana |
API4 | 400, 413 |
/v1/admin/… oddiy hisobdan |
API5 | 403 |
/auth/men versiyasiz |
API9 | 404 |
| xato javobida stack trace qidirish | API8 | yo'q |
Test fayli aynan shu jadvalning kodi.
7. Bog'liqliklar: 7 kun qoidasi
API8 va veb ro'yxatidagi A03 (ta'minot zanjiri) ni bog'laydigan yana bir audit bor. 28-qism boshida qoida qo'yilgan edi: yangi chiqqan paket versiyasini kamida 7 kun o'rnatmaymiz — zararli versiyalar odatda shu muddatda topilib, o'chiriladi (Auth kutubxonalari va xizmatlari).
Kanon qism oxirida 27 va 28-qism package-lock.json farqini olib, har yangi paket versiyasining chiqish sanasini npm view <paket> time bilan tekshirdi. Natija noqulay bo'ldi: kanonning o'zi qoidani buzgan edi. @simplewebauthn/server (passkey kutubxonasi, Ikki faktorli autentifikatsiya va passkeys) ichki bog'liqlik sifatida @peculiar/asn1-* paketlarini ^2.6.0 diapazoni bilan so'raydi. O'rnatish paytida npm eng yangi mosini — 2.11.1 ni oldi. Biz sanasini alohida tekshirdik:
npm view @peculiar/asn1-schema time --json "2.11.0": "2026-10-12T18:25:24.013Z",
"2.11.1": "2026-10-25T12:07:38.552Z",(Natijaning ikki qatori; biz ishga tushirdik, 2026-10-28.) Passkey qo'shilgan kuni 2.11.1 atigi 3 kunlik edi. Siz o'zingiz o'rnatgan paketlar 7 kunlik bo'lsa ham, ularning tranzitiv bog'liqliklari (bog'liqlikning bog'liqligi) yangi bo'lishi mumkin.
Tuzatish — package.json dagi overrides: npm'ga "bu paketni qayerda uchratsang ham — shu versiya" deyiladi. Kanon 13 ta @peculiar/asn1-* paketini 2.11.0 ga qotirdi (2026-10-12):
"overrides": {
"jose": "6.2.12",
"@peculiar/asn1-schema": "2.11.0",
"@peculiar/asn1-x509": "2.11.0",
"@peculiar/asn1-ecc": "2.11.0"
}(Qisqartirilgan: to'liq ro'yxatda yana 10 ta @peculiar/asn1-* paketi.) Qayta audit xulosasi: "jami yangi paket versiyalari: 57; 7 kun qoidasini buzgan: 0". Passkey testlari va brauzer testlari 2.11.0 bilan o'tdi, npm audit — 0.
Kanon buni "o'z xatoim" deb yozdi. Biz ham yashirmaymiz: qoida yozish oson, tranzitiv bog'liqliklarda uni ushlab turish — qiyin. Shuning uchun u avtomatlashtirilishi kerak (npm ning yangi versiyalarida va boshqa paket menejerlarida "minimal yosh" sozlamasi bor — kanonda sinalmagan).
8. Ko'p uchraydigan xatolar
| Xato | Nega noto'g'ri | To'g'risi |
|---|---|---|
| begona obyektga 403 | mavjudligini oshkor qiladi | 404 |
| egasi ID'si so'rov tanasidan | hujumchi o'zgartiradi | sessiyadan |
SELECT * va butun obyektni qaytarish |
parol hash, telefon chiqadi | aniq ustunlar |
| rol faqat login paytida tekshiriladi | adminlik olinsa ham ishlaydi | har so'rovda bazadan |
| eski yo'lni "vaqtincha" ochiq qoldirish | yangi endpoint'lar ham ochiladi | aniq ro'yxat, Sunset |
tashqi javobga if (j.success) |
"false" ham rost |
=== true, sxema |
| "o'zimiz 7 kun kutdik" | tranzitivlar yangi | lock farqini tekshirish, overrides |
| audit bir marta | yangi kod eski teshikni qaytaradi | regressiya testlari |
9. Mashqlar
Mashqlar kurs/mashqlar/28/31-owasp-api/ da.
1-mashq (oson): toifani toping
GET /v1/eksportlar/abc— boshqa foydalanuvchining eksport fayli yuklandi./v1/auth/menjavobidaparolHashmaydoni bor./v0/vazifalarhujjatda yo'q, lekin ishlaydi va auth so'ramaydi.- Oddiy foydalanuvchi
POST /v1/admin/foydalanuvchilar/3/bloklashni bajardi. - Bot 10 000 ta hisob ochdi.
Yechim
- API1 BOLA — kanondagi haqiqiy topilmaning o'zi (eksport ishlari egasiz edi).
- API3 BOPLA — javobda ortiqcha maydon.
- API9 — unutilgan versiya.
- API5 BFLA — funksiya darajasida ruxsat yo'q.
- API6 — ro'yxatdan o'tish oqimi avtomatlashtirildi (har so'rov alohida "to'g'ri").
2-mashq (o'rta): ruxsat ro'yxati bilan javob
Taqiq ro'yxatidan (denylist) kuchliroq yo'l — javobga faqat ruxsat etilgan maydonlarni qo'yish. tanla(obyekt, ruxsat) funksiyasini yozing: ruxsat — { maydon: true } yoki ichma-ich obyektlar uchun { maydon: { ichki: true } }. Ro'yxatda yo'q maydon javobga tushmasin. Massiv bo'lsa — har elementga qo'llang.
Yechim
function tanla(x, ruxsat) {
if (Array.isArray(x)) return x.map((el) => tanla(el, ruxsat));
const natija = {};
for (const [k, qoida] of Object.entries(ruxsat)) {
if (!Object.hasOwn(x, k)) continue;
natija[k] = qoida === true ? x[k] : tanla(x[k], qoida);
}
return natija;
}
const xom = {
foydalanuvchi: { id: 1, email: "aziz@example.com",
parolHash: "$argon2id$…", telefon: "+998901234567" },
vazifalar: [{ id: 7, matn: "Non", egasiId: 1 }],
};
const RUXSAT = {
foydalanuvchi: { id: true, email: true },
vazifalar: { id: true, matn: true },
};
console.log(JSON.stringify(tanla(xom, RUXSAT)));Konsolda:
{"foydalanuvchi":{"id":1,"email":"aziz@example.com"},"vazifalar":[{"id":7,"matn":"Non"}]}Ertaga bazaga ichkiIzoh ustuni qo'shilsa — taqiq ro'yxati uni o'tkazib yuborardi, ruxsat ro'yxati (allowlist) esa uni avtomatik chiqarmaydi. Bu Xavfsizlik tamoyillari dagi "sukut bo'yicha xavfsiz". Object.hasOwn — prototipdagi kalitlarga aldanmaslik uchun.
3-mashq (qiyin): inventar tekshiruvi
inventar(hujjat, haqiqiy) funksiyasini yozing. hujjat — API.md dagi yo'llar, haqiqiy — serverda ishlayotgan yo'llar ("GET /v1/vazifalar" shaklida). Qaytarsin: hujjatsiz (ishlaydi, lekin hujjatda yo'q), olik (hujjatda bor, lekin ishlamaydi) va versiyasiz (/v1 bilan boshlanmaydigan ishlayotgan yo'llar). Hammasi saralangan.
Yechim
function inventar(hujjat, haqiqiy) {
const h = new Set(hujjat);
const r = new Set(haqiqiy);
const yol = (s) => s.split(" ")[1];
return {
hujjatsiz: [...r].filter((x) => !h.has(x)).toSorted(),
olik: [...h].filter((x) => !r.has(x)).toSorted(),
versiyasiz: [...r].filter((x) => !yol(x).startsWith("/v1/"))
.toSorted(),
};
}
const hujjat = ["GET /v1/vazifalar", "POST /v1/vazifalar",
"GET /v1/auth/men", "GET /vazifalar", "GET /v1/hisobot"];
const haqiqiy = ["GET /v1/vazifalar", "POST /v1/vazifalar",
"GET /v1/auth/men", "GET /vazifalar", "GET /auth/men",
"GET /v1/debug/kesh"];
console.log(inventar(hujjat, haqiqiy));Konsolda:
{
hujjatsiz: [ 'GET /auth/men', 'GET /v1/debug/kesh' ],
olik: [ 'GET /v1/hisobot' ],
versiyasiz: [ 'GET /auth/men', 'GET /vazifalar' ]
}GET /auth/men ikki ro'yxatda — hujjatsiz va versiyasiz. Aynan shu kanonning API9 topilmasi edi. GET /vazifalar versiyasiz, lekin hujjatda bor — ataylab qoldirilgan eski yo'l (Deprecation bilan). GET /v1/debug/kesh — unutilgan sozlash yo'li, eng xavflisi. Real loyihada haqiqiy ro'yxat Express router'dan yoki OpenAPI hujjatidan avtomatik olinadi.
10. Loyiha qadami: OWASP auditi
10.1 docs/OWASP-API.md
Yangi hujjat. Uning yuragi — asosiy jadval, darsda faqat shuni ko'rsatamiz. Bu fayl markdown jadvali, darsda uni oddiy matn sifatida beramiz. Ichidagi "holat 07" kabi belgilar — loyiha tarixidagi qadamlar. Kanon hujjatida eski atama 'oq ro'yxat' qolgan — bu kursdagi 'ruxsat ro'yxati (allowlist)' bilan bir narsa:
# vazifalar-api — OWASP API Security Top 10:2023 auditi
| # | Toifa | vazifalar-api'da qanday ko'rinadi | Test (hujum ssenariysi) | Himoya | Topilgan (28-qismda) |
|---|---|---|---|---|---|
| API1 | Broken Object Level Authorization (BOLA, IDOR) | `GET/PATCH/DELETE /v1/vazifalar/:id` — id ketma-ket son, boshqa odamnikini taxmin qilish oson | `owasp-api` API1, `sessiya`, `rls` (pg va prisma, `vazifalar_api` roli) | har so'rovda egasi sessiyadan; SQL'da `egasi_id`; **Postgres RLS** (`set_config` + eng kam huquqli rol) — WHERE unutilsa ham 0 qator; begona — **404** | **Idempotency-Key global edi** (Dilnoza Azizning javobini oldi), **eksport ishlari** egasiz edi (holat 07); 27 holatida API superuser bilan ulanib RLS'ni chetlab o'tardi (holat 20) |
| API2 | Broken Authentication | login, sessiya, parol tiklash, OTP, 2FA, API kalit | `auth`, `sessiya`, `email`, `otp`, `mfa`, `cheklov`, `api-kalit`, `owasp-api` API2 | argon2id (OWASP parametrlari), server sessiyasi (token hash, HttpOnly `__Host-`), aylantirish, bir xil javob (enumeration), tezlik cheklovi (hisob+IP), 2FA, bloklangan hisob markaziy tekshiruvda | parol tiklash so'rovi **vaqt bo'yicha** email borligini oshkor qilardi (30.0 / 12.8 ms → FonIshlar bilan 16.6 / 17.6 ms, holat 12); 2FA kodini cheklovsiz terish mumkin edi (holat 19 → 26) |
| API3 | Broken Object Property Level Authorization (BOPLA) | javobda ortiqcha maydon (parol hash, telefon); kiruvchi ortiqcha maydon (`egasiId`, `rol`) | `owasp-api` API3, `hujum` (mass assignment) | javob — aniq tanlangan ustunlar (`SELECT *` yo'q); kirish — Zod `strictObject` (oq ro'yxat, 25-qismdan) → 422 | yangi topilma yo'q (25-qism qarori ishladi) |
| API4 | Unrestricted Resource Consumption | login toshqini (argon2 — 19 MiB, ~70 ms), katta tana, `limit=100000`, ReDoS, SMS/xat yuborish | `cheklov`, `semafor`, `bot`, `owasp-api` API4; DoS o'lchovi | tana 16 KB, sahifa ≤ 100, `statement_timeout`, Slowloris timeout'lari, **Postgres tezlik cheklovi**, **argon2 semafori (4 + navbat 64 → 503)**, SMS kunlik byudjet | 27 holatida 300 so'rov — 429 yo'q (holat 26 da yopildi); 200 parallel login paytida oddiy GET p99 **3 283 ms** (semafordan keyin 733 ms, holat 29) |
| API5 | Broken Function Level Authorization (BFLA) | `/v1/admin/*`, API kalit boshqaruvi, kalit bilan `/men` | `admin`, `api-kalit`, `owasp-api` API5 | `rolKerak` (rol har so'rovda bazadan — adminlikdan olinsa darhol 403); kalit ruxsatlari (`vazifalar:oqish`/`yozish`); kalit boshqaruvi faqat sessiya bilan | — |
| API6 | Unrestricted Access to Sensitive Business Flows | ro'yxat (bot hisoblar), parol tiklash va SMS (pumping — pul) | `bot`, `cheklov` | Turnstile (server tomonda siteverify), honeypot, IP chastotasi, SMS faqat ulangan raqamga, mamlakat ro'yxati, kunlik global byudjet | — (himoya CAPTCHA darsida qo'shildi, oldin yo'q edi) |
| API7 | Server Side Request Forgery (SSRF) | `WEBHOOK_URL` (29-qismda foydalanuvchi kiritadigan manzil) | `ssrf` | `xavfsizPost`: ichki IP ro'yxati (169.254.169.254 ham), o'z DNS tekshiruvimiz + IP'ga bog'langan ulanish (DNS rebinding), redirect qayta tekshiruvi, faqat https | 27 holatida `fetch(WEBHOOK_URL)` — hech qanday tekshiruvsiz (holat 28 da yopildi) |
| API8 | Security Misconfiguration | CORS, CSP, superuser ulanish, sukut sozlamalar, `trust proxy` | `cors.e2e`, `csrf.e2e`, `rls`, `cheklov` (XFF), `owasp-api` API8 | helmet (API uchun `default-src 'none'`), CORS ro'yxati env'dan, CSRF Origin tekshiruvi, ikki rol (`vazifalar_api`, `vazifalar_auth`), production'da config fail-fast | **eng kam huquq buzilgan edi**: sukut huquqlar `vazifalar_api` ga `sessiyalar`, `mfa_totp` ni ochgan (holat 07–19, 119 da REVOKE); **bir saytdagi boshqa origin `chiqish-hammasi` ni bajara olardi** (CSRF, holat 07 → 10); frontend dev proxy `changeOrigin: true` — CSRF tekshiruvi frontendni 403 qildi va **chiqish jim muvaffaqiyatsiz bo'lib, sessiya tirik qoldi** (frontend ulanishi) |
| API9 | Improper Inventory Management | versiyasiz eski yo'llar, hujjatda yo'q endpoint'lar | `owasp-api` API9, hujum yuzasi tajribasi | ildizda faqat `/vazifalar`, `/teglar` (`Deprecation` + `Sunset`); API.md — to'liq ro'yxat | **25-qismdan beri butun v1 router ildizga ulangan edi** — `/eksportlar` va yangi `/auth/*` versiyasiz ham ochiq (holat 07) |
| API10 | Unsafe Consumption of APIs | Google OIDC, Telegram, Turnstile javoblari | `oidc`, `telegram`, `bot` | `openid-client` (state, nonce, PKCE, iss), Telegram hash/Ed25519 + muddat, Turnstile — `hostname` tekshiruvi, tarmoq xatosida **rad** (fail closed), timeout | Turnstile rasmiy test kaliti `hostname: example.com` qaytaradi — `TURNSTILE_HOSTNAME` bilan birga ishlatib bo'lmaydi (hujjat, holat 30) |Jadvalni o'qish tartibi — chapdan o'ngga: qanday ko'rinadi → qaysi test hujum qiladi → qanday yopilgan → nima topilgan. Hujjatda yana ikki bo'lim bor, ularni qisqa aytamiz:
- Frontend tomoni — 22-qism frontend'ida topilgan uchta zaiflik. Ularni darsning oxirida, frontend bo'limida batafsil ko'ramiz.
- Qolgan xavflar — ongli ravishda ochiq qoldirilganlar. Tezlik cheklagichi buzilsa — fail open. Parol tiklash xati jarayon xotirasidagi fon ishida (haqiqiy navbat — 29-qism). Servislararo HMAC nonce'lari bitta jarayon xotirasida. Production sozlamasi SMTP'siz yopiq. Haqiqiy provayderlar (Google, Telegram, OneID, SMS, email) sinalmagan.
Kanon matnida faqat ichki belgilarni almashtirdik: dars raqamlari va tajriba fayllari nomlari o'rniga mavzu nomi (masalan, "DoS o'lchovi"). "Qolgan xavflar" bo'limi muhim: hujjat faqat "nima yopilgan"ni emas, nima ongli ravishda ochiq qolganini ham aytadi. Auditor uchun bu ham himoya kabi qimmatli.
10.2 test/owasp-api.test.ts
7 ta test — jadvalning API1, API2, API3, API4, API5, API8, API9 qatorlari (API6, API7, API10 — o'z test fayllarida: bot, ssrf, oidc, telegram). Ikkitasi (telefon uchun bo'lingan):
test("API1 BOLA: begona vazifa — o'qish, o'zgartirish, " +
"o'chirish 404 (403 emas); ro'yxatda yo'q", async () => {
const { d, app } = ilova();
const aziz = await hisobOch(app, d, "aziz@example.com");
const dilnoza = await hisobOch(app, d, "dilnoza@example.com");
const v = await request(app).post("/v1/vazifalar")
.set("Cookie", aziz).send({ matn: "Azizniki" }).expect(201);
const id = String((v.body as { id: number }).id);
const yol = `/v1/vazifalar/${id}`;
await request(app).get(yol).set("Cookie", dilnoza).expect(404);
await request(app).patch(yol).set("Cookie", dilnoza)
.send({ bajarildi: true }).expect(404);
await request(app).delete(yol).set("Cookie", dilnoza).expect(404);
const r = await request(app).get("/v1/vazifalar")
.set("Cookie", dilnoza).expect(200);
const { vazifalar } = r.body as { vazifalar: unknown[] };
assert.deepEqual(vazifalar, []);
await request(app).get(yol).set("Cookie", aziz).expect(200);
});
test("API9 inventar: versiyasiz yo'llardan faqat /vazifalar va " +
"/teglar (Deprecation bilan); qolgani 404", async () => {
const { d, app } = ilova();
const aziz = await hisobOch(app, d, "aziz@example.com");
const eski = await request(app).get("/vazifalar")
.set("Cookie", aziz).expect(200);
assert.ok(eski.headers["deprecation"] !== undefined);
for (const y of ["/eksportlar/x", "/auth/men",
"/admin/foydalanuvchilar"]) {
await request(app).get(y).set("Cookie", aziz).expect(404);
}
});API1 testining oxirgi qatoriga qarang: Aziz o'z vazifasini ko'radi (200). Bu qator bo'lmasa, test "hamma joyda 404" degan buzuq kod bilan ham o'tib ketardi. Har rad etish testi yonida — ruxsat etilgan holat ham.
Ishga tushiramiz (biz ishga tushirdik: kanon nusxasi, Node 24.21.0, test bazasi — lokal PostgreSQL 17.6 klasterida kanon sxemasi):
node --test test/owasp-api.test.ts✔ API1 BOLA: begona vazifa — o'qish, o'zgartirish, o'chirish 404 (403 emas — borligi ham oshkor emas); ro'yxatda yo'q (752.3216ms)
✔ API2 autentifikatsiya: sessiyasiz, soxta cookie, soxta Bearer — 401 (ma'lumot yo'llari ham, /men ham) (360.1585ms)
✔ API3 BOPLA: javoblarda ichki maydon yo'q (/men, vazifa, admin ro'yxati); kiruvchi ortiqcha maydon — 422 (mass assignment) (523.6401ms)
✔ API4 resurs iste'moli: limit chegarasi 400, katta tana 413 (521.8301ms)
✔ API5 BFLA: oddiy foydalanuvchi admin yo'llarida 403, sessiyasiz 401 (421.291ms)
✔ API8 sozlamalar: X-Powered-By yo'q, CSP default-src 'none', xato javobida stack yo'q (290.0914ms)
✔ API9 inventar: versiyasiz yo'llardan faqat /vazifalar va /teglar (Deprecation bilan); /eksportlar, /auth, /admin — 404 (443.6433ms)
ℹ tests 7
ℹ suites 0
ℹ pass 7
ℹ fail 0
ℹ cancelled 0
ℹ skipped 0
ℹ todo 0
ℹ duration_ms 6316.0146Kanonda ham birinchi ishga tushirishdayoq 7/7 — yangi zaiflik topilmadi: hammasi oldingi darslarda yopilgan edi. Bu testlar endi qaytmaslik uchun.
10.3 .env.example va hujjatlar
.env.example ga 28-qismning hamma sozlamalari qo'shildi — qiymatsiz yoki xavfsiz sukut bilan, har biriga izoh. Bo'limdan parcha:
# ===== 28-qism: autentifikatsiya va xavfsizlik =====
# Ikki rol (sql/119): ma'lumot — vazifalar_api (RLS), auth jadvallari — vazifalar_auth. Berilmasa — bitta pool (DATABASE_URL)
# AUTH_DATABASE_URL=postgres://vazifalar_auth@127.0.0.1:5497/vazifalar
# Ilova siri (>= 32 belgi; HKDF bilan: SMS kod HMAC, kursor, API kalit, TOTP shifri, imzoli cookie'lar). Yaratish:
# node -e "console.log(require('node:crypto').randomBytes(32).toString('base64url'))"
# ILOVA_SIRI=
# true — __Host-sessiya (Secure). Faqat http'da sinash uchun false (cookie nomi "sessiya")
COOKIE_SECURE=true
# SMS kod yuboriladigan mamlakat prefikslari (vergul bilan) va kunlik global SMS byudjeti (SMS pumping)
OTP_MAMLAKATLAR=+998
SMS_KUNLIK_MAKS=1000
# Cloudflare Turnstile siri (bo'lmasa CAPTCHA o'chiq). Lokal sinov — RASMIY test kaliti 1x0000000000000000000000000000000AA
# (u hostname "example.com" qaytaradi — test kaliti bilan TURNSTILE_HOSTNAME bermang)
# TURNSTILE_SIRI=
# TURNSTILE_HOSTNAME=vazifalar.exampleTo'liq bo'limda 24 ta o'zgaruvchi: sessiya muddatlari, OIDC, Telegram, passkey va servislararo HMAC siri ham. Qoida o'zgarmadi: sir yo'q, faqat qanday yaratish haqida izoh. Yana uchta hujjat yangilandi: README.md (auth bo'limi va proxy tuzog'i), API.md (auth yo'llari, 401/403/429/503 va changelog'da v1.1), TESTLAR.md (28-qism testlari ro'yxati).
10.4 Tekshiruv va commit
Yakuniy tekshiruv (kanon, 2026-10-28, PostgreSQL 18.6): tip va lint xatosiz, testlar 240 (239 + 1 o'tkazilgan) — qism boshidagi 112 dan. owasp-api 7/7, Testcontainers 10/10, brauzer testlari 10/10 (CSRF, passkey, CORS). 14 ta migratsiya sql/ bilan bir xil, jonli API haqiqiy rollar bilan uch rejimda 18/18, npm audit (hammasi va --omit=dev) — 0.
M="docs(security): OWASP API Top 10:2023 auditi — zaiflik → test"
M+=" → himoya jadvali; test: owasp-api regressiya to'plami;"
M+=" .env.example, README, API.md 28-qism uchun"
git add docs/OWASP-API.md test/owasp-api.test.ts .env.example
git add README.md API.md TESTLAR.md package.json package-lock.json
git commit -m "$M"package.json va lock fayl — overrides tufayli.
11. Frontend'ni haqiqiy kirishga ulash
11.1 Qayerdan boshlaymiz
22-qismdagi vazifalar frontend'ida kirish soxta edi: faqat ism, parol yo'q, hammasi localStorage da. 25-qismda frontend vazifalar-api ga ulangan, lekin auth'siz. Endi server sessiyasi bor — frontend uni ishlatishi kerak.
Kanon buni haqiqiy brauzerda (Playwright, Chromium) sinadi: Vite dev server proxy orqali /v1 ni API'ga yuboradi, API — haqiqiy Postgres va rollar bilan.
11.2 Birinchi urinish: proxy tuzog'i
Avval kanon 25-qismdagi proxy sozlamasini o'zgartirmasdan, faqat kirish formasini ulab ko'rdi. Tajriba natijasidan parcha:
1) to'g'ri parol: URL /; menyu tugmasi "Aziz Karimov"; checkbox 12 ta
2) qo'shish: so'rovlar: POST /v1/vazifalar 403, GET /v1/vazifalar?limit=100 200; ekrandagi xabar: ["Saqlanmadi: So'rov boshqa sahifadan kelgan (Origin: http://127.0.0.1:4382) — rad etildi"]
4) chiqish: URL /kirish?keyin=%2F; so'rovlar: POST /v1/auth/chiqish 403; cookie'lar: __Host-sessiya; localStorage foydalanuvchi: null
4) chiqqandan keyin GET /v1/vazifalar (JS'dan): 200Kirish ishladi, ro'yxat keldi. Lekin har yozuv — 403 csrf. Sabab — vite.config.ts dagi changeOrigin: true. U proxy orqali o'tayotgan so'rovning Host sarlavhasini API manziliga (127.0.0.1:4381) almashtiradi. Brauzer esa Origin: http://127.0.0.1:4382 yuboradi. API'ning CSRF tekshiruvi (Tokenni qayerda saqlash va CSRF) Origin'ni o'z host'i bilan solishtiradi — mos emas, demak "boshqa sahifadan".
sequenceDiagram
participant B as Brauzer :4382
participant V as Vite proxy
participant A as API :4381
B->>V: POST /v1/vazifalar, Origin :4382
V->>A: Host :4381 (changeOrigin), Origin :4382
Note over A: Origin ≠ Host — CSRF
A-->>B: 403 csrfTo'rtinchi qatorlar — eng yomoni. Chiqish ham 403 oldi, lekin UI baribir "chiqdingiz" ko'rsatdi: kirish formasi paydo bo'ldi, localStorage tozalandi. Cookie esa brauzerda qoldi, sessiya serverda tirik — keyingi GET 200 qaytardi. Foydalanuvchi umumiy kompyuterda "chiqdim" deb ketadi, keyingi odam esa uning hisobida. Bu — xavfsizlikdagi eng yomon xato turi: yolg'on muvaffaqiyat.
11.3 O'zgarishlar
Kanon 10 faylni o'zgartirdi (+466 / −73). Asosiylari:
vite.config.ts — /v1 proxy'dan changeOrigin olib tashlandi. Prodakshnda nginx ham Host ni brauzerdagidek uzatadi (proxy_set_header Host $host), dev esa unga o'xshasin:
- "/v1": { target: env.API_PROXY, changeOrigin: true },
+ // 28-qism: changeOrigin YO'Q — Host saqlanadi
+ "/v1": { target: env.API_PROXY },src/xususiyatlar/auth/server.ts (yangi) — /v1/auth/men|kirish|chiqish ga so'rov va server javobidan ismni xavfsiz olish. Javob — unknown, har maydon tekshiriladi:
export function serverIsmi(malumot: unknown): Foydalanuvchi | null {
if (
typeof malumot !== "object" || malumot === null ||
!("foydalanuvchi" in malumot) ||
typeof malumot.foydalanuvchi !== "object" ||
malumot.foydalanuvchi === null ||
!("toliqIsm" in malumot.foydalanuvchi) ||
typeof malumot.foydalanuvchi.toliqIsm !== "string"
) {
return null;
}
const ism = malumot.foydalanuvchi.toliqIsm.trim()
.slice(0, ISM_ENG_KOP);
return ismXatosi(ism) === null ? { ism } : null;
}So'rovlarda credentials kerak bo'lmadi: frontend va API bir origin'da (dev — Vite proxy, prod — nginx), fetch cookie'ni sukut bo'yicha (same-origin) yuboradi. Agar API boshqa domenda bo'lsa — credentials: "include" va CORS'da credentials (CORS chuqur).
AuthKonteksti.tsx — kimlik endi serverda. localStorage da faqat ko'rsatish uchun ism qoladi — sahifa tez chizilsin. Lekin u ishonch manbai emas: ochilganda /v1/auth/men so'raladi, 401 bo'lsa — yozuv o'chadi. Chiqish esa endi faqat server rozi bo'lsa bajariladi:
async chiqish() {
const javob = await authSorov("chiqish", { method: "POST" })
.catch(() => null);
if (javob === null) {
return "Serverga ulanib bo'lmadi — chiqilmadi. " +
"Qayta urinib ko'ring.";
}
// 401 — sessiya allaqachon yo'q: chiqish maqsadiga yetilgan
if (!javob.ok && javob.status !== 401) {
return xatoMatni(await javob.json().catch(() => null));
}
foydalanuvchiNusxasiniTozala();
foydalanuvchiniSaqla(null);
setHozirKirdi(false);
ozgardi();
return null;
},saqlash.ts — foydalanuvchiNusxasiniTozala(): chiqishda, sessiya tugaganda va yangi kirishda brauzerdagi vazifalar ro'yxati va qoralama o'chiriladi (tema va til — qurilmaniki, qoladi). Query keshi ham tozalanadi. Kanon hujjatiga ko'ra tuzatishdan oldin shu brauzerda keyin kirgan odam oldingisining vazifalarini server so'rovisiz ko'rgan.
KirishFormasi.tsx — ism o'rniga email va parol (autocomplete="username" va current-password — parol menejerlari uchun), xatoda server matni ko'rinadi, email qoladi, parol tozalanadi, yuborilayotganda tugma o'chiq.
11.4 Natija
Tuzatishdan keyingi tajriba natijasidan parcha:
1) brauzer cookie'lari: __Host-sessiya (httpOnly=true, secure=true, sameSite=Lax, path=/, doimiy)
1) document.cookie (JS ko'radigani): ""
2) qo'shish: so'rovlar: POST /v1/vazifalar 201, GET /v1/vazifalar?limit=100 200; ekrandagi xabar: ["«Auth bilan qo'shildi #sinov» qo'shildi."]
4) chiqish: URL /kirish?keyin=%2F; so'rovlar: POST /v1/auth/chiqish 204; cookie'lar: yo'q; localStorage foydalanuvchi: null
4) chiqqandan keyin GET /v1/vazifalar (JS'dan): 401
4) shu brauzerda Dilnoza kirdi: darhol (server javobidan oldin) Aziz vazifasi ekranda: false; 1.5 s dan keyin: false; checkbox 6 ta; so'rovlar: POST /v1/auth/kirish 200, GET /v1/vazifalar?limit=100 200
5) localStorage'ga qo'lda "kirgan" yozuv: so'rovlar: GET /v1/vazifalar?limit=100 401, GET /v1/auth/men 401; oxirida forma: true; yozuv: nulldocument.cookie— bo'sh: JavaScript sessiya cookie'sini ko'rmaydi, XSS uni o'g'irlay olmaydi.- Chiqish — 204, cookie yo'q, keyingi so'rov — 401. UI va server bir xil narsani aytadi.
- Keyin kirgan Dilnoza Azizning vazifalarini bir lahzaga ham ko'rmadi.
localStoragega qo'lda "kirdim" yozuvini qo'yish hech narsa bermadi: server 401, yozuv o'chdi.
Chromium Secure cookie'ni http://127.0.0.1 da ham qabul qildi — localhost "ishonchli kontekst" hisoblanadi. Prodakshnda HTTPS majburiy.
11.5 22-qism testlarini yangilash
Frontend'ning o'z testlari-chi? Kanon yangi Auth.test.tsx ni yozdi (15 test: forma, server xatosi, 2FA javobi, 401 da nusxa tozalanishi, chiqish va chiqish rad etilganda UI qolishi, boshqa tab; serverIsmi jadvali). Lekin to'liq vitest ni ishga tushirganda 24 ta test yiqildi — va ular 28-qism o'zgarishlaridan oldin ham yiqilayotgan edi.
Biz buni qayta tekshirdik (22-qism frontend'i + 25-qism ulanishi, Node 24.21.0):
npx vitest run --project mantiq --project komponent Tests 24 failed | 325 passed (349)28-qism o'zgarishlari qo'shilgach — 24 failed | 336 passed (360): 11 ta yangi Auth testi o'tadi, eski 24 tasi yiqilishda davom etadi. Sabab 25-qismda: api.ts ro'yxat manzilini /vazifalar/<kalit> dan /vazifalar?limit=100 ga o'zgartirgan, testlar va MSW soxta serveri esa eski manzilni kutib qolgan. Bu ham API9 ning kichik ko'rinishi: kod o'zgardi, uning "hujjati" (testlar) — yo'q.
Tuzatish uchta faylda. MSW handler'i (tekshiruv/msw/soxta-api.ts) — manzildan kalitni olib tashlaymiz:
-// .env.test dagi VITE_API_URL bilan bir xil yo'l (kalit — istalgan)
-const YOL = "*/api/mashq/vazifalar/:kalit";
+// .env.test dagi VITE_API_URL bilan bir xil yo'l. 25-qismdan: o'z
+// API'miz — ro'yxat kalitsiz (?limit=100), egasi — sessiyadan
+const YOL = "*/api/mashq/vazifalar";
/** shu API ning istalgan so'rovi (ro'yxat ham, /:id ham) */
-const HAMMASI = /\/api\/mashq\/vazifalar\//;
+const HAMMASI = /\/api\/mashq\/vazifalar(\/|$)/;MSW manzilni ?limit=100 siz solishtiradi — so'rov parametrlari yo'lga kirmaydi. tekshiruv/api.test.js — kutilgan manzillar:
-const manzil = `${asosiyUrl}/vazifalar/k1`;
+// 25-qism: o'z API'miz — ro'yxat kalitsiz, GET to'liq sahifa bilan
+const manzil = `${asosiyUrl}/vazifalar`;
+const royxatManzili = `${manzil}?limit=100`;(va ikki joyda ro'yxat so'rovi uchun manzil o'rniga royxatManzili). tekshiruv/msw.test.tsx da uchta joyda :kalit bo'lagi olib tashlandi (*/api/mashq/vazifalar/:id, */api/mashq/vazifalar va URL regex'i). Natija (biz ishga tushirdik):
Test Files 55 passed (55)
Tests 360 passed (360)tsc -b, ESLint va Prettier — toza.
E2E testlar. 22-qismdagi Playwright testlari ham eski kirishni kutadi: kirish.setup.ts "Ismingiz" maydonini to'ldiradi, soxta API (e2e/soxta-api.ts) esa auth yo'llarini bilmaydi. Biz ularni ham yangiladik: kirish — email va parol bilan; soxta API'ga /v1/auth/men|kirish|chiqish qo'shildi — kimlik cookie orqali, ya'ni storageState bilan saqlangan "kirgan" holat ishlaydi, bo'sh holat esa 401 oladi:
await page.route(/\/v1\/auth\/(men|kirish|chiqish)$/,
async (route) => {
const yol = new URL(route.request().url()).pathname;
const sarlavhalar = await route.request().allHeaders();
const kirgan = (sarlavhalar["cookie"] ?? "")
.includes("sessiya=");
const men = { foydalanuvchi:
{ id: 1, email: "s@example.com", toliqIsm: "Sinovchi" } };
if (yol.endsWith("/kirish")) {
return route.fulfill({ json: men,
headers: { "Set-Cookie": "sessiya=e2e; Path=/; HttpOnly" } });
}
if (yol.endsWith("/chiqish")) {
return route.fulfill({ status: 204,
headers: { "Set-Cookie": "sessiya=; Path=/; Max-Age=0" } });
}
return kirgan
? route.fulfill({ json: men })
: route.fulfill({ status: 401, json: { status: 401 } });
});Vazifalar yo'lining naqshi ham kalitsiz manzilga moslandi (/\/api\/mashq\/vazifalar(\/\d+)?(\?.*)?$/); kirish.setup.ts, asosiy.spec.ts va a11y.spec.ts dagi "Ismingiz" — Email va Parol maydonlariga almashdi. Halol ogohlantirish: e2e o'zgarishlari tsc -b va ESLint'dan o'tdi, lekin biz Playwright testlarini ishga tushirmadik. O'z kompyuteringizda npm run test:e2e bilan tekshiring; route.fulfill dagi Set-Cookie brauzer kontekstiga yozilishiga e'tibor bering — e2e'ning hammasi shunga tayanadi.
11.6 Frontend commit
Frontend — alohida repo. Ikki commit: avval ishlaydigan kod, keyin testlar.
M="feat(auth): haqiqiy kirish — email va parol, server sessiyasi"
M+=" (HttpOnly cookie), chiqishda brauzer nusxasini tozalash"
git add src vite.config.ts tekshiruv/Auth.test.tsx
git commit -m "$M"
M="test: MSW va api.test 25-qism manzillariga moslandi; e2e —"
M+=" email va parol bilan kirish, soxta auth yo'llari"
git add tekshiruv e2e
git commit -m "$M"Ikkinchi xabar — namuna (kanonda bu commit yo'q edi).
12. Real ishda
- API pentest hisobotlari topilmalarni aynan API1–API10 bilan belgilaydi. BOLA — yillar davomida eng ko'p uchraydigani.
- API gateway va WAF mahsulotlari (Kong, Cloudflare API Shield va boshqalar) "OWASP API Top 10 himoyasi" deb sotiladi. Lekin BOLA va BFLA'ni ular ko'ra olmaydi: "bu vazifa kimniki" — faqat sizning kodingiz biladi.
- Inventar uchun OpenAPI hujjati CI'da haqiqiy marshrutlar bilan solishtiriladi.
- Bog'liqliklar: Dependabot, Renovate — yangi versiyalarni PR bilan taklif qiladi; ko'pchiligida "minimal yosh" sozlamasi bor.
- Intervyuda: "BOLA va BFLA farqi?", "Nega 404, 403 emas?", "Mass assignment qaysi toifa?", "Unutilgan endpoint'larni qanday topasiz?".
Xulosa
- OWASP API Top 10:2023 — API'ga xos tekshiruv ro'yxati; BOLA (API1) birinchi o'rinda.
vazifalar-apiauditi: har toifa → qanday ko'rinadi → test → himoya; 7 ta regressiya testi.- 28-qismda haqiqiy zaifliklar topildi: umumiy
Idempotency-Key, egasiz eksport, versiyasiz ochiq yo'llar, ortiqcha DB huquqlari, CSRF, vaqt orqali email oshkorligi, tekshiruvsiz webhook. - Tranzitiv bog'liqlik 7 kun qoidasini buzdi —
overridesbilan qotirildi; qoida avtomatlashtirilishi kerak. - Frontend:
changeOriginsiz proxy, HttpOnly cookie, chiqish faqat server roziligida, chiqishda brauzer nusxasi tozalanadi. - 22-qism testlari 25-qism manzillariga moslandi: 360/360.
Keyingi dars: Fayl yuklash: multipart va Multer — 29-qism boshlanadi: backend integratsiyalar. Birinchi qadam — foydalanuvchi faylini qabul qilish, va bu yerda ham bugungi ro'yxat kerak bo'ladi.
Manbalar
- OWASP API Security Top 10:2023: https://owasp.org/API-Security/editions/2023/en/0x11-t10/ (2026-10-28 da o'qildi)
- OWASP API Security Project: https://owasp.org/www-project-api-security/
- npm
overrides: https://docs.npmjs.com/cli/v11/configuring-npm/package-json#overrides - Vite
server.proxy(changeOrigin): https://vite.dev/config/server-options#server-proxy - MDN — Secure context (localhost): https://developer.mozilla.org/en-US/docs/Web/Security/Secure_Contexts
- Kanon (IlmHamroh, 2026-10-28):
docs/OWASP-API.md,owasp-api.test.ts,.env.example, bog'liqliklar auditi (57 / 0), yakuniy tekshiruv. Frontend ulanishi — haqiqiy brauzerda (Chromium headless shell 151), oldin va keyin. Biz ishga tushirdik:owasp-api.test.tsnatijasi,npm viewsanasi, frontend vitest (24 → 0 yiqilish) va test tuzatishlari (2026-10-28, Node 24.21.0, test bazasi PostgreSQL 17.6).
Izohlar (0)
Izoh yozish uchun kiring.
- Hozircha izoh yo'q. Birinchi bo'ling!