Mundarija (27)
- Bu darsda
- 1. Nega bu kerak?
- 2. Chuqur himoya
- 2.1 Bitta qatlam yetmaydi
- 2.2 O'z bazangizda sinab ko'ring
- 3. Eng kam huquq
- 4. Sukut bo'yicha xavfsiz
- 5. Xavfsiz yiqilish
- 5.1 Xato bo'lsa — eshik yopiq
- 5.2 Kanondagi misollar
- 6. Hech kimga ishonma
- 6.1 Foydalanuvchi kiritganiga ishonma
- 6.2 Zero trust: ichkarida ham ishonma
- 7. Ruxsat ro'yxati va taqiq ro'yxati
- 7.1 Qaysi biri xavfsizroq
- 7.2 Ruxsat ro'yxati ham to'g'ri tekshirilsin
- 8. Tamoyillar bir jadvalda
- 9. Hujumchi nigohi
- 10. Ko'p uchraydigan xatolar
- 11. Mashqlar
- 1-mashq (oson): qaysi tamoyil?
- 2-mashq (o'rta): yopiq yiqilish
- 3-mashq (qiyin): ruxsat ro'yxati bilan javobni tozalash
- 12. Loyiha qadami: ishonch chegaralari
- 13. Real ishda
- Xulosa
- Manbalar
Xavfsizlik tamoyillari: chuqur himoya, eng kam huquq va sukut bo'yicha xavfsizlik
Qisqacha: Har bir zaiflikni alohida eslab qolish shart emas — bir nechta umumiy qoida ko'p hujumni oldindan to'xtatadi. Chuqur himoya — bitta qulfga emas, bir necha qatlamga tayaning. Eng kam huquq — har dastur va odamga faqat kerakli ruxsat. Sukut bo'yicha xavfsiz — sozlanmagan narsa yopiq. Xavfsiz yiqilish — xato bo'lsa, eshik yopiladi. Hech kimga ishonma — har so'rov tekshiriladi. Ruxsat ro'yxati (allowlist) — "nima mumkin"ni sanang, "nima mumkin emas"ni emas.
Bu darsda
- Yettita asosiy xavfsizlik tamoyilini o'z so'zingiz bilan tushuntirasiz.
- Har tamoyilni
vazifalar-apidan haqiqiy misol bilan ko'rsatasiz. - O'z Postgres bazangizda RLS qatlami superuser bilan ishlamasligini va oddiy rol bilan ishlashini tekshirasiz.
- "Ochiq yiqilish" xatosini kodda topib, tuzatasiz.
- Ruxsat ro'yxati va taqiq ro'yxati farqini
Object.hasOwnmisolida ko'rasiz.
Oldin bilishingiz kerak: Xavfsizlik nima: CIA, tahdid va hujumchi fikrlashi, Row Level Security, Rollar va huquqlar, Env validatsiyasi va tipli config obyekti.
Oldingi darsda vazifalar-api ga hujumchi ko'zi bilan qaradik va besh xil teshik topdik. Ularni birma-bir yamash mumkin. Lekin ertaga yangi kod yoziladi va yangi teshik paydo bo'ladi. Bugun teshiklar paydo bo'lishining o'zini kamaytiradigan qoidalarni o'rganamiz.
1. Nega bu kerak?
Bank binosini tasavvur qiling. Kirishda qo'riqchi bor. Lekin pul faqat qo'riqchiga ishonib saqlanmaydi: ichkarida kamera, kassada alohida eshik, seyfda kod, kod esa faqat ikki xodimda. Kassir seyfni ochmaydi, qo'riqchi kassaga kirmaydi. Bitta odam xato qilsa yoki aldansa — keyingi qatlam ushlaydi.
Bu bank o'ylab topgan maxsus hiyla emas. Bu — bir necha oddiy qoida, ularni har qanday tizimga qo'llash mumkin. Dasturda ham xuddi shunday qoidalar bor. Ular xavfsizlik tamoyillari (security principles) deyiladi.
Tamoyilning foydasi: yangi kod yozayotganda "bu yerda qanday hujum bo'lishi mumkin?" deb hamma hujumni eslash shart emas. "Bu yerda eng kam huquq bormi? Xato bo'lsa eshik yopiladimi?" degan bir necha savol yetadi.
2. Chuqur himoya
2.1 Bitta qatlam yetmaydi
Chuqur himoya (defense in depth) — bir himoya qatlamiga emas, bir-biridan mustaqil bir nechta qatlamga tayanish. Har qatlam boshqasining xatosini ushlaydi.
vazifalar-api da "boshqa odamning vazifasini ko'rmasin" qoidasi uchun allaqachon ikki qatlam bor:
- Ilova qatlami — har so'rovda
WHERE egasi_id = $1(Parametrli so'rovlar va SQL injection dan beri). - Baza qatlami — Row Level Security: baza o'zi har qatorni tekshiradi.
Dasturchi bir joyda WHERE ni unutsa ham, RLS ushlaydi. Nazariyada. Oldingi darsda ko'rdik: API bazaga superuser bo'lib ulanadi va RLS ishlamaydi. Keling, buni o'z bazangizda tekshiramiz.
2.2 O'z bazangizda sinab ko'ring
Quyidagi so'rovlar kanon sxemasi va namuna ma'lumotlari bilan to'ldirilgan lokal bazada bajarildi (biz ishga tushirdik, PostgreSQL 17.6). Avval superuser postgres nomidan, WHERE siz:
SELECT count(*) AS jami, count(DISTINCT egasi_id) AS egalari
FROM vazifalar;Natija:
jami | egalari
------+---------
48 | 7
(1 row)Yetti egasining hammasi ko'rinadi. RLS siyosatlari jadvalda turibdi, lekin superuser ularni chetlab o'tadi. Endi xuddi shu so'rov — oddiy ilova roli vazifalar_ilova nomidan, joriy foydalanuvchi o'rnatilmagan:
SET ROLE vazifalar_ilova;
SELECT count(*) AS korinadi FROM vazifalar;Natija:
SET
korinadi
----------
0
(1 row)Nol. RLS ishladi: "kim ekansiz?" degan savolga javob yo'q — demak hech narsa ko'rinmaydi. Joriy foydalanuvchini tranzaksiya ichida o'rnatamiz (Aziz — 1):
BEGIN;
SET LOCAL ROLE vazifalar_ilova;
SELECT set_config('ilova.foydalanuvchi_id', '1', true);
SELECT count(*) AS korinadi FROM vazifalar;
ROLLBACK;Natija:
BEGIN
SET
set_config
------------
1
(1 row)
korinadi
----------
13
(1 row)
ROLLBACKFaqat Azizning 13 ta vazifasi. set_config(..., true) — "faqat shu tranzaksiya uchun" degani (Row Level Security darsidagi SET LOCAL bilan bir xil).
Va hujumchi uchun eng muhimi — o'chirishga urinish:
SET ROLE vazifalar_ilova;
DELETE FROM vazifalar WHERE id = 2;Natija:
SET
DELETE 0Xato ham yo'q, o'chirish ham yo'q. Baza nuqtai nazaridan bu foydalanuvchi uchun 2-vazifa umuman mavjud emas.
Xulosa: qatlam bor, lekin u faqat to'g'ri rol bilan ishlaydi. Chuqur himoya — qatlamlarni qo'yish emas, ularning haqiqatan ishlashini tekshirish.
flowchart TD
S[So'rov] --> V{Zod validatsiya}
V -->|xato| R1[400/422]
V --> K{Kim? sessiya}
K -->|yo'q| R2[401]
K --> W{WHERE egasi_id}
W --> L{RLS bazada}
L -->|begona qator| R3[0 qator]
L --> N[Natija]Diagrammaga qarang: so'rov to'rtta tekshiruvdan o'tadi va har biri o'zi rad eta oladi. Ikkinchi qatlam ("Kim?") hozircha yo'q — uni Session-based auth darsida qo'shamiz.
Tekshirib ko'ring: Ilova kodida
WHERE egasi_idbor ekan, RLS nima uchun kerak? Bu ortiqcha ish emasmi?
Javob
Kod — odam yozadi, odam esa xato qiladi. Yangi endpoint, yangi hisobot so'rovi, shoshilinch tuzatish — bittasida WHERE unutilishi mumkin. RLS bazaning o'zida turadi, u har so'rovga avtomatik qo'llanadi. Ikki mustaqil qatlam birdaniga xato qilishi ehtimoli ancha kam.
3. Eng kam huquq
Eng kam huquq (least privilege) — har dastur, xizmat yoki odam faqat o'z ishiga kerakli huquqqa ega bo'lsin, ortig'iga emas. Mehmonxona kartasi misoli: u faqat sizning xonangizni ochadi, butun qavatni emas. Kartani yo'qotsangiz — zarar bitta xona bilan cheklanadi.
Kanon sxemasidagi rollarga qarang:
SELECT rolname, rolsuper, rolbypassrls
FROM pg_roles WHERE rolname LIKE 'vazifalar%' OR rolname = 'postgres'
ORDER BY rolname;Natija:
rolname | rolsuper | rolbypassrls
----------------------+----------+--------------
postgres | t | t
vazifalar_api | f | f
vazifalar_hisobot | f | t
vazifalar_ilova | f | f
vazifalar_migratsiya | f | f
(5 rows)Har rolning o'z ishi bor (Rollar va huquqlar darsida yaratgansiz):
| Rol | Vazifasi | Nima qila olmaydi |
|---|---|---|
vazifalar_migratsiya |
jadvallarni yaratadi va o'zgartiradi | so'rovlarga xizmat qilmaydi |
vazifalar_api |
API ulanishi, RLS ostida | jadval o'chira olmaydi, RLS'ni chetlab o'tmaydi |
vazifalar_hisobot |
faqat o'qiydi, statistikasi uchun | yozolmaydi |
postgres |
hamma narsa | — |
Rollar to'g'ri yaratilgan. Lekin 27-qism oxirida API postgres bilan ulanayotgan edi. Rejada eng kam huquq bor, amalda yo'q. Agar API'da biror SQL injection topilsa, hujumchi superuser huquqini oladi: hamma jadval, hamma foydalanuvchi, hatto jadvallarni o'chirish.
Bu tuzatish RBAC va resurs egaligi darsida: API vazifalar_api roli bilan ulanadi va o'lchov bilan tekshiriladi.
Maslahat: Eng kam huquq faqat baza haqida emas. API kalitiga faqat kerakli ruxsatlar, CI'ga faqat kerakli sirlar, xodimga faqat kerakli serverlar. Har safar: "bu huquq bo'lmasa, nima ishlamay qoladi?" deb so'rang. Javob "hech narsa" bo'lsa — huquqni olib tashlang.
4. Sukut bo'yicha xavfsiz
Sukut bo'yicha xavfsiz (secure by default) — hech narsa sozlanmagan holat eng yopiq holat bo'lsin. Foydalanuvchi ochishni xohlasa — o'zi ataylab ochadi. Yangi telefon misoli: ekran qulfi sukut bo'yicha yoqilgan, o'chirish uchun sozlamalarga kirish kerak.
Ikki sozlama funksiyasini solishtiring. Birinchisi hamma narsani sukut bo'yicha ochadi:
function sozlamaYomon(env) {
return {
host: env.HOST ?? "0.0.0.0",
egasiId: Number(env.EGASI_ID ?? 1),
cors: env.CORS_ORIGINS ?? "*",
};
}
function sozlamaYaxshi(env) {
const cors = (env.CORS_ORIGINS ?? "").split(",").filter(Boolean);
if (env.NODE_ENV === "production" && cors.length === 0) {
throw new Error("production'da CORS_ORIGINS majburiy");
}
return { host: env.HOST ?? "127.0.0.1", cors };
}
console.log(sozlamaYomon({}));
console.log(sozlamaYaxshi({}));
try {
sozlamaYaxshi({ NODE_ENV: "production" });
} catch (e) {
console.log(e.message);
}Konsolda:
{ host: '0.0.0.0', egasiId: 1, cors: '*' }
{ host: '127.0.0.1', cors: [] }
production'da CORS_ORIGINS majburiy0.0.0.0— server hamma tarmoq kartalarida tinglaydi, ya'ni tashqaridan ham ochiq.127.0.0.1— faqat shu kompyuterdan.cors: "*"— har qanday sayt javobni o'qiy oladi. Bo'sh ro'yxat — hech kim (CORS sarlavhasi chiqmaydi).- Prodakshnda (production) CORS ro'yxati bo'lmasa — server umuman ishga tushmaydi.
Kanon config.ts dagi qatorlar aynan ikkinchi yo'lni tutgan (Env validatsiyasi darsida yozgansiz):
// Sukut — faqat lokal: reverse proxy orqasida Node porti
// tashqariga ochilmasin
HOST: z.string().min(1).default("127.0.0.1"),
// ...
.refine((e) => e.NODE_ENV !== "production"
|| e.CORS_ORIGINS.length > 0,
{ error: "production'da CORS_ORIGINS majburiy",
path: ["CORS_ORIGINS"] })Telefon ekrani uchun qatorlarni bo'ldik, ma'nosi kanondagidek.
Lekin halol bo'lamiz: kanonda sukut bo'yicha ochiq bitta sozlama ham bor — EGASI_ID: Butun(1). Sozlanmasa, har so'rov 1-foydalanuvchi (Aziz) nomidan bajariladi. Bu autentifikatsiya yo'qligida vaqtinchalik yechim edi. 28-qismda u o'rnini sessiyaga beradi va sozlamadan butunlay yo'qoladi.
5. Xavfsiz yiqilish
5.1 Xato bo'lsa — eshik yopiq
Har tizim ba'zan buziladi: baza javob bermaydi, tashqi xizmatdan javob kutish vaqti tugaydi (timeout), kod undefined ga duch keladi. Bunday paytda tizim ikki yo'ldan birini tanlaydi:
- ochiq yiqilish (fail open) — "ishlay olmadim, mayli, o'tkazib yuboraman";
- yopiq yiqilish (fail closed, fail securely) — "ishlay olmadim, demak ruxsat yo'q".
Elektr uzilganda magazin eshigi qanday bo'ladi? Agar u qulflanib qolsa — yopiq yiqilish. Agar ochilib qolsa — ochiq. Xavfsizlik nuqtai nazaridan qulflanish kerak.
function ruxsatBormiOchiq(foydalanuvchi, vazifa) {
try {
return vazifa.egasiId === foydalanuvchi.id;
} catch {
return true; // "xizmat to'xtamasin"
}
}
function ruxsatBormiYopiq(foydalanuvchi, vazifa) {
try {
return vazifa.egasiId === foydalanuvchi.id;
} catch {
return false; // shubha bo'lsa — yo'q
}
}
const vazifa = { id: 2, egasiId: 1 };
const aziz = { id: 1 };
const malika = { id: 5 };
const mehmon = undefined; // tizimga kirmagan
for (const kim of [aziz, malika, mehmon]) {
console.log(
ruxsatBormiOchiq(kim, vazifa),
ruxsatBormiYopiq(kim, vazifa),
);
}Konsolda:
true true
false false
true falseUchinchi qatorga qarang. Tizimga kirmagan odam uchun foydalanuvchi.id TypeError beradi (try / catch / finally). Birinchi funksiya xatoni ushlab, true qaytardi: mehmon Azizning vazifasiga kirdi. Malikaga esa — yo'q. Ya'ni bu kodda tizimga kirmagan odam kirgan odamdan ko'proq huquqqa ega. Bunday xato real tizimlarda uchraydi.
5.2 Kanondagi misollar
vazifalar-api da yopiq yiqilishning ikki misolini allaqachon ko'rdingiz:
- RLS: joriy foydalanuvchi o'rnatilmagan →
joriy_foydalanuvchi()NULLqaytaradi →egasi_id = NULLhech qachon rost emas → 0 qator. Yuqoridagikorinadi = 0aynan shu. - Sozlama xato → server ishga tushmaydi,
exit 78(oldingi darsdagi o'lchov). Yarim-sozlangan server ishlab turgandan ko'ra, umuman ishlamagani yaxshi.
Diqqat: Har joyda ham yopiq yiqilish to'g'ri emas. Masalan, tezlik cheklovi (rate limiting) xizmati buzilsa, butun saytni yopish — mavjudlikni (A) o'zingiz buzish. Kanon bu joyda ochiq yiqilishni ataylab tanlagan va login uchun boshqacha muqobilni ko'rsatadi — bu Tezlik cheklovi darsida. Muhimi — tanlov ongli bo'lsin,
catchichida tasodifan emas.
Tekshirib ko'ring:
catch { return true; }yozgan dasturchi nima demoqchi bo'lgan? Uning niyati yomonmi?
Javob
Niyati yaxshi: "kichik xato tufayli foydalanuvchi ishlay olmay qolmasin". Lekin u mavjudlikni (A) himoya qilib, maxfiylik va yaxlitlikni (C, I) qurbon qildi. Avtorizatsiya tekshiruvida xato bo'lsa — javob doim "ruxsat yo'q" bo'lishi kerak.
6. Hech kimga ishonma
6.1 Foydalanuvchi kiritganiga ishonma
Serverga kelgan hamma narsa — foydalanuvchi qo'lida bo'lgan: tana, URL parametrlari, sarlavhalar, cookie, hatto Content-Type. Frontend ularni to'g'ri yuboradi deb o'ylash — xato. Hujumchi frontendsiz, to'g'ridan curl bilan istagan narsani yuboradi.
«Bahor» oshxonasining buyurtma API'si misoli. Frontend { taom: "osh", narx: 35000 } yuboradi. Server narxni tanadan olsa, hujumchi narx: 1 yuboradi va oshni bir so'mga oladi. To'g'risi: mijozdan faqat nima kerakligi (taom: "osh"), narx esa serverdagi menyudan.
Bu tamoyil inglizcha "never trust user input" deb yuritiladi. Uni Validatsiya darsida Zod bilan qo'llagansiz. Bugun uni kengaytiramiz: validatsiya — "bu ma'lumot to'g'ri shaklda" degani. Lekin "bu odamga shu ma'lumotni yuborishga ruxsat bor" degani emas. Ikkinchisi — avtorizatsiya, alohida tekshiruv.
6.2 Zero trust: ichkarida ham ishonma
Eski yondashuv: "tarmoq ichidagilar — o'zimiznikilar, tashqaridagilar — begona". Firma binosi atrofida devor, ichkarida hamma eshik ochiq. Muammo: hujumchi bitta kompyuterni egallasa — u allaqachon ichkarida.
Zero trust (nol ishonch) — tarmoqdagi joylashuvga qarab ishonmaslik. Har so'rov, hatto ichki xizmatdan kelgani ham, kim yuborganini isbotlashi kerak. vazifalar-api uchun bu:
- Postgres faqat parol yoki sertifikat bilan ulanishga ruxsat beradi, "localhost'dan bo'lsa bo'ldi" emas;
- Redis'ga ham parol (kanon lokalda parolsiz, prodakshnda bu yetmaydi);
- bir xizmat boshqasini chaqirsa — imzo yoki kalit bilan (API kalitlar va servislararo autentifikatsiya).
Zero trust — katta tashkilotlarning arxitekturasi, unga oddiy dasturda to'liq erishish shart emas. Lekin g'oyasi har joyda foydali: "ichkaridan keldi" — dalil emas.
7. Ruxsat ro'yxati va taqiq ro'yxati
7.1 Qaysi biri xavfsizroq
Ikki yo'l bor:
- Taqiq ro'yxati (denylist; eski kodda — blacklist) — taqiqlangan narsalarni sanash: "
parol_hashmaydonini qaytarma". - Ruxsat ro'yxati (allowlist; eski kodda — whitelist) — ruxsat etilgan narsalarni sanash: "faqat
id,matn,bajarildi,muddatni qaytar".
Oldingi qismlarda shu g'oyani boshqa nom bilan ham uchratgan bo'lishingiz mumkin. Shu qismdan boshlab bitta nom ishlatamiz: ruxsat ro'yxati (allowlist).
To'y ro'yxati misoli: qo'riqchiga "bu besh kishini kiritma" deyish — taqiq ro'yxati. "Faqat ro'yxatdagi 200 kishini kirit" — ruxsat ro'yxati. Begona odam birinchi holatda kiradi, ikkinchisida — yo'q.
const TAQIQLANGAN = ["parol_hash", "email"];
const taqiqBilan = (maydon) => !TAQIQLANGAN.includes(maydon);
const RUXSAT = ["id", "matn", "bajarildi", "muddat"];
const ruxsatBilan = (maydon) => RUXSAT.includes(maydon);
for (const m of ["matn", "parol_hash", "PAROL_HASH", "telefon"]) {
console.log(m.padEnd(11), taqiqBilan(m), ruxsatBilan(m));
}Konsolda:
matn true true
parol_hash false false
PAROL_HASH true false
telefon true falseTaqiq ro'yxati ikki joyda yutqazdi. PAROL_HASH — katta harf bilan yozilgan, ro'yxatda yo'q, o'tib ketdi. telefon — ertaga qo'shilgan yangi maxfiy ustun, uni ro'yxatga qo'shishni hech kim eslamadi. Ruxsat ro'yxati ikkalasini ham rad etdi: u noma'lum narsani sukut bo'yicha rad etadi. Bu — "sukut bo'yicha xavfsiz" tamoyilining o'zi.
7.2 Ruxsat ro'yxati ham to'g'ri tekshirilsin
Filtrlash, saralash va maydon tanlash darsida ?sort= maydonini ruxsat ro'yxati bilan tekshirgan edik. Kanon u yerda ataylab in emas, Object.hasOwn ishlatgan. Sababi:
const USTUN = {
yaratildi: "yaratildi",
muddat: "muddat",
matn: "matn",
};
const inBilan = (maydon) => maydon in USTUN;
const hasOwnBilan = (maydon) => Object.hasOwn(USTUN, maydon);
for (const m of ["muddat", "parol_hash", "constructor", "toString"]) {
console.log(m, inBilan(m), hasOwnBilan(m));
}Konsolda:
muddat true true
parol_hash false false
constructor true false
toString true falsein operatori obyektning prototipidagi kalitlarni ham "bor" deydi (Obyekt: kalit-qiymat juftliklari). Har oddiy obyektda constructor va toString bor — ular Object.prototype dan keladi. Hujumchi ?sort=constructor yuborsa, in uni "ruxsat ro'yxatida" deb o'tkazadi. Keyin kod USTUN["constructor"] ni SQL'ga qo'yishga urinadi — kutilmagan xato yoki undan yomoni. Object.hasOwn faqat obyektning o'z kalitlarini tekshiradi.
Saboq: ruxsat ro'yxati — kuchli tamoyil, lekin uni tekshiradigan kod ham aniq bo'lishi kerak.
8. Tamoyillar bir jadvalda
| Tamoyil | Bir gapda | vazifalar-api da |
|---|---|---|
| Chuqur himoya | bir necha mustaqil qatlam | Zod + WHERE + RLS |
| Eng kam huquq | faqat kerakli ruxsat | rollar bor, lekin API superuser bilan |
| Sukut bo'yicha xavfsiz | sozlanmagan — yopiq | HOST 127.0.0.1, CORS bo'sh |
| Xavfsiz yiqilish | xato — "yo'q" | RLS NULL → 0 qator, config → exit 78 |
| Hech kimga ishonma | har kirish tekshiriladi | Zod sxemalari, strictObject |
| Zero trust | ichkaridan ham isbot | ichki xizmatlar kalit bilan |
| Ruxsat ro'yxati | ruxsat etilganni sanash | ?sort= — Object.hasOwn |
Bitta tamoyil bor, u boshqalarning hammasini birlashtiradi: hujum yuzasini kichraytirish (oldingi darsda ko'rdik). Ishlatilmaydigan kod, marshrut, huquq, bog'liqlik bo'lmasa — uni himoya qilish ham kerak emas.
9. Hujumchi nigohi
Hujumchi tamoyillarni bilmaydi — u ularning yo'qligini qidiradi. Jadvalda: hujum, u qaysi tamoyil yo'qligidan foydalanadi, unga qarshi himoya va himoyani qanday tekshiramiz:
| Hujum | Tamoyil yo'q | Himoya | Tekshiruv |
|---|---|---|---|
| SQL injection → butun baza | eng kam huquq | cheklangan rol + RLS | begona qator → 0 ta |
| sukut sozlamadagi server | sukut bo'yicha xavfsiz | 127.0.0.1, bo'sh CORS |
sozlamaYaxshi({}) |
catch { return true } |
xavfsiz yiqilish | catch → false |
mehmon → false |
narx: 1 tanada |
hech kimga ishonma | narx serverdan | narx: 1 → e'tiborsiz |
PAROL_HASH, yangi ustun |
ruxsat ro'yxati | Object.hasOwn |
maxfiy maydon yo'q |
"Tekshiruv" ustuniga qarang: har himoyaning yonida uni sinaydigan kichik misol bor. Bu darsda ularning ko'pini o'zingiz ishga tushirdingiz. Har qatordagi hujum alohida dars mavzusi bo'ladi. Lekin ularning hammasini bitta savol to'xtatadi: "bu yerda qaysi tamoyil buzilgan?".
10. Ko'p uchraydigan xatolar
| Xato | Nega xavfli | To'g'risi |
|---|---|---|
| bitta qatlamga ishonish ("bizda CORS bor") | qatlam buzilsa — himoya yo'q | kamida ikki mustaqil qatlam |
| "qulay" deb superuser bilan ulanish | bitta teshik — butun baza | alohida, cheklangan rol |
sukut qiymati * yoki 0.0.0.0 |
sozlashni unutish = ochiq eshik | sukut — yopiq, ochish ataylab |
catch da ruxsat berish |
xato hujum yo'liga aylanadi | xato bo'lsa — rad |
narx, rol, egasiId ni tanadan olish |
mijoz istaganini yozadi | server o'zi hisoblaydi |
in bilan ruxsat ro'yxati |
prototip kalitlari o'tadi | Object.hasOwn |
| taqiq ro'yxati bilan filtrlash | yangi va o'zgargan qiymatlar o'tadi | ruxsat ro'yxati |
11. Mashqlar
Mashqlar kurs/mashqlar/28/02-tamoyillar/ da.
1-mashq (oson): qaysi tamoyil?
Har holatda qaysi tamoyil buzilgan?
- Yangi xodimga birinchi kundanoq hamma serverlarga kirish berildi.
- Admin panel parolsiz ochiladi, "keyin parol qo'yamiz" deb qoldirildi.
- Fayl yuklashda faqat
.exetaqiqlangan. - Buyurtma API'si chegirmani mijoz yuborgan
chegirmamaydonidan oladi.
Yechim
- Eng kam huquq — faqat ishiga kerakli serverlar.
- Sukut bo'yicha xavfsiz — sozlanmagan holat ochiq qolgan.
- Ruxsat ro'yxati o'rniga taqiq ro'yxati —
.scr,.bat,.htao'tib ketadi (Fayl yuklash xavfsizligi darsida aynan shu). - Hech kimga ishonma — chegirmani server hisoblaydi.
2-mashq (o'rta): yopiq yiqilish
adminmi(foydalanuvchi) funksiyasini yozing: foydalanuvchi.rollar massivida "admin" bo'lsa true. Foydalanuvchi undefined bo'lsa, rollar yo'q bo'lsa yoki massiv bo'lmasa — xato tashlamasin va false qaytarsin. To'rt holatda sinang: admin, oddiy foydalanuvchi, undefined, { rollar: "admin" } (massiv emas, satr). Ishora: Array.isArray (typeof va turni to'g'ri aniqlash) va ?..
Yechim
function adminmi(foydalanuvchi) {
const rollar = foydalanuvchi?.rollar;
if (!Array.isArray(rollar)) return false;
return rollar.includes("admin");
}
console.log(adminmi({ rollar: ["admin", "foydalanuvchi"] }));
console.log(adminmi({ rollar: ["foydalanuvchi"] }));
console.log(adminmi(undefined));
console.log(adminmi({ rollar: "admin" }));Konsolda:
true
false
false
falseTo'rtinchi holat — nozik tuzoq. Satrning ham includes metodi bor: "admin".includes("admin") — true. Array.isArray tekshiruvisiz bu foydalanuvchi admin bo'lib qolardi. Kutilmagan shakl — "yo'q" degan javob.
3-mashq (qiyin): ruxsat ro'yxati bilan javobni tozalash
ochiqKorinish(qator, ruxsat) funksiyasini yozing: bazadan kelgan qator obyektidan faqat ruxsat massividagi kalitlarni yangi obyektga ko'chirsin. Qatorda yo'q kalit natijaga tushmasin. Object.hasOwn bilan tekshiring. Sinang: { id: 7, matn: "Non olish", parol_hash: "$argon2id$...", telefon: "+998 90 000 00 00" } va ruxsat ["id", "matn", "muddat"]. Ishora: Object.fromEntries va filter (Object.* metodlarining to'liq sharhi).
Yechim
function ochiqKorinish(qator, ruxsat) {
return Object.fromEntries(
ruxsat
.filter((kalit) => Object.hasOwn(qator, kalit))
.map((kalit) => [kalit, qator[kalit]]),
);
}
const qator = {
id: 7,
matn: "Non olish",
parol_hash: "$argon2id$...",
telefon: "+998 90 000 00 00",
};
console.log(ochiqKorinish(qator, ["id", "matn", "muddat"]));Konsolda:
{ id: 7, matn: 'Non olish' }Funksiya ruxsat ro'yxatidan yuradi, qatordan emas. Shuning uchun ertaga bazaga yangi maxfiy ustun qo'shilsa ham, u javobga tushmaydi. muddat qatorda yo'q — natijada ham yo'q (undefined bilan emas, umuman).
12. Loyiha qadami: ishonch chegaralari
Bu darsda ham kod o'zgarmaydi. Oldingi darsda docs/XAVFSIZLIK.md ning birinchi va uchinchi bo'limlarini yozgan edingiz. Ular orasiga ikkinchisini qo'shing — ishonch chegaralari va har chegaradagi uch tekshiruv. Kanon matni:
## 2. Ishonch chegaralari (trust boundaries)
brauzer (frontend) ──HTTPS──▶ nginx ──▶ vazifalar-api (Express) ──▶ Postgres (RLS)
▲ │ └─▶ Redis (kesh)
hujumchi sahifasi (CSRF) └──▶ tashqi: webhook URL, OIDC, SMS/email
Har chegara kesib o'tilganda: kirish tekshiriladi (Zod), kim ekanligi
aniqlanadi (autentifikatsiya), nimaga ruxsati borligi tekshiriladi
(avtorizatsiya).Kanonda diagramma o'zgacha bo'shliqlar bilan chizilgan va qavslarda qism raqamlari bor — biz ularni olib tashladik va oxirgi gapni telefon uchun qatorlarga bo'ldik. Bu bo'lim tamoyillarning qayerda qo'llanishini ko'rsatadi: har strelka — "hech kimga ishonma" qo'llanadigan joy.
Bugungi SQL tajribasini ham hujjatga eslatma qilib yozib qo'ying: "API superuser bilan ulanganda RLS ishlamaydi (48 ta vazifa, 7 egasi); vazifalar_ilova bilan — 0, foydalanuvchi o'rnatilganda — faqat o'ziniki". Bu eslatma RBAC va resurs egaligi darsida yopiladi.
Hujjat hali to'liq emas — hali commit qilmang. Keyingi darsda unga OWASP xaritasini qo'shamiz va commit qilamiz.
13. Real ishda
- Kod review da tamoyillar tayyor savol beradi: "bu
catchnima qaytaradi?", "bu rolga shuncha huquq kerakmi?", "sukut qiymati nima?". - Bulut xizmatlari (AWS, Google Cloud) huquqlarni aynan eng kam huquq tamoyili bilan beradi: har xizmatga alohida, tor ruxsat. Tajribali muhandislar
*(hamma narsa) ruxsatini ko'rganda darhol to'xtatadi. - Zero trust — Google o'zining ichki tarmog'ida BeyondCorp nomi bilan qo'llagan va sohaga keng tarqalgan yondashuv.
- Intervyuda: "Defense in depth nima, misol keltiring", "Fail open va fail closed farqi?", "Nega allowlist denylist'dan yaxshi?".
Xulosa
- Chuqur himoya — bir necha mustaqil qatlam; lekin har qatlam haqiqatan ishlashini tekshirish kerak (superuser bilan RLS ishlamadi).
- Eng kam huquq — har rol faqat o'z ishiga; API uchun superuser — xato.
- Sukut bo'yicha xavfsiz — sozlanmagan narsa yopiq (
127.0.0.1, bo'sh CORS). - Xavfsiz yiqilish — avtorizatsiyada xato bo'lsa, javob "yo'q".
- Hech kimga ishonma — mijoz yuborgan hamma narsa tekshiriladi; ichkaridan kelgani ham.
- Ruxsat ro'yxati taqiq ro'yxatidan kuchliroq; uni
Object.hasOwnbilan tekshiring.
Keyingi dars: OWASP Top 10:2025 xaritasi — dunyodagi eng keng tarqalgan 10 xavf toifasi, 2021-yildan nima o'zgardi va har biri vazifalar-api da qayerda; xavfsizlik hujjatini tugatib, commit qilamiz.
Manbalar
- OWASP Developer Guide (xavfsizlik tamoyillari): https://owasp.org/www-project-developer-guide/
- NIST SP 800-207 Zero Trust Architecture: https://csrc.nist.gov/pubs/sp/800/207/final
- PostgreSQL: Row Security Policies: https://www.postgresql.org/docs/18/ddl-rowsecurity.html
- Kanon tajribasi (IlmHamroh, 2026-10-27) va lokal sinov: SQL so'rovlar — PostgreSQL 17.6, kanon sxemasi va namuna ma'lumotlari, 2026-10-28.
Izohlar (0)
Izoh yozish uchun kiring.
- Hozircha izoh yo'q. Birinchi bo'ling!