14.6-bob: Token va secrets xavfsizligi
14-QISM — Web Xavfsizligi · 6-mavzu
1. Kirish va motivatsiya
14.5-bobda foydalanuvchini tanidik (parol). Endi savol: foydalanuvchi kirgandan keyin, har so'rovda uni qanday "eslab qolamiz" (qayta parol so'ramasdan)? Javob — token (yoki sessiya). Eng keng — JWT (JSON Web Token) — server foydalanuvchiga imzolangan "guvohnoma" beradi, foydalanuvchi uni har so'rovda ko'rsatadi, server imzoni tekshiradi (qayta DB so'rovsiz). JWT kuchli, lekin noto'g'ri ishlatish — eng keng xavfsizlik xatolaridan: zaif secret, muddatsiz token, xavfli saqlash (localStorage — XSS), maxfiy ma'lumotni token ichida. Bu bob JWT'ni xavfsiz ishlatishni va token saqlashni ko'rsatadi.
Ikkinchi yarmida — secrets (maxfiy ma'lumot — API kalit, DB parol, JWT secret) boshqaruvi. Zamonaviy ilova o'nlab secret bilan ishlaydi, va ularning bittasi sizsa — katta zarar (DB egallash, to'lov kaliti, boshqa xizmatlar). Eng keng xato — secret'ni kodga yoki git'ga qo'yish (GitHub'da minglab API kalit ochiq sizgan — botlar git'ni skanerlaydi). To'g'ri — secret env'da, yaxshisi vault (maxsus xizmat), kalit aylantirish (rotation), va sizgan secret'ni darrov bekor qilish. Bu — har production ilovaning poydevori.
Bu bob: JWT tuzilishi (header.payload.signature), JWT xavfsiz ishlatish (secret, algoritm, muddat), JWT keng xatolar (alg=none, zaif secret, maxfiy ma'lumot), access/refresh token strategiyasi, token saqlash (cookie vs localStorage — XSS/CSRF), secrets boshqaruvi (env, vault, rotation), va API kalit xavfsizligi. Token va secrets xavfsizligi mavzusi to'liq ochib beriladi.
O'xshatish: Token — bu konsertga kirish bilaguzugi. Kirishda (login — parol bilan) sizga bilaguzuk (token) beriladi — endi har xonaga kirishda qayta chipta ko'rsatmaysiz, faqat bilaguzukni (token). Bilaguzukda muhr (imzo — signature) bor — soxta bilaguzuk qila olmaysiz (muhr maxfiy — faqat tashkilotchida). JWT secret — muhr bosadigan asbob (uni sizsa — har kim soxta bilaguzuk yasaydi — barcha xona ochiq). Muddat — bilaguzuk faqat bugun amal qiladi (yo'qotsangiz — ertaga ishlamaydi). localStorage'da saqlash — bilaguzukni stol ustida qoldirish (har kim — XSS — o'g'irlaydi); HttpOnly cookie — uni qo'lingizga bog'lash (JavaScript ko'rmaydi). Secrets — bu butun tashkilotning kalitlar to'plami: bittasi (muhr asbobi, DB kaliti) yo'qolsa — katta muammo. Shuning uchun kalitlarni seyfda (vault), kodda emas, saqlaysiz.
Nega muhim?
- JWT keng — zamonaviy API auth'ning standarti (xato ishlatish — keng zaiflik).
- Secret sizishi — bitta secret = katta zarar (DB, to'lov, boshqa xizmatlar).
- GitHub leak — secret kodda/git'da = botlar topadi (minglab kalit sizgan).
- Token saqlash — localStorage (XSS) vs cookie (CSRF) — to'g'ri tanlash muhim.
2. Nazariya — chuqur tushuntirish
2.1. JWT tuzilishi
JWT — imzolangan token (uch qism, nuqta bilan ajratilgan):
eyJhbGsi... . eyJzdWIi... . SflKxwRJ...
└─ HEADER ─┘ └─ PAYLOAD ─┘ └ SIGNATURE ┘
1. HEADER — algoritm + tur:
{ "alg": "HS256", "typ": "JWT" }
2. PAYLOAD — ma'lumot (claims) — foydalanuvchi ID, rol, muddat:
{ "sub": "user123", "role": "user", "exp": 1735000000 }
PAYLOAD SHIFRLANMAGAN — faqat base64 (har kim O'QIY oladi — maxfiy ma'lumot QO'YMA!)
3. SIGNATURE — imzo (header + payload + SECRET):
HMACSHA256(base64(header) + "." + base64(payload), SECRET)
Imzo — soxtalashtirishni to'sadi (secret'siz to'g'ri imzo yasab bo'lmaydi)
TEKSHIRISH: server imzoni qayta hisoblab, mos kelsa — ishonadi (DB so'rovsiz)
JWT — header.payload.signature; payload OCHIQ (base64 — shifr emas), imzo himoyalaydi
Imzo bilan — server token haqiqiyligini secret bilan tekshiradi (DB'siz, tez)JWT tuzilishi — JSON Web Token qanday tuzilgan. JWT — imzolangan token, uch qismdan iborat (nuqta
.bilan ajratilgan):header.payload.signature. (1) Header — algoritm va tur:{ "alg": "HS256", "typ": "JWT" }(imzo qaysi algoritm bilan); (2) Payload (claims) — ma'lumot:{ "sub": "user123", "role": "user", "exp": 1735000000 }(foydalanuvchi ID, rol, muddat —exp); juda muhim — payload shifrlanmagan (faqat base64 kodlangan — har kimjwt.ioda yoki base64 dekod bilan o'qiy oladi) — shuning uchun maxfiy ma'lumot (parol, karta) payload'ga qo'yma (har kim ko'radi); (3) Signature (imzo) —HMACSHA256(base64(header) + "." + base64(payload), SECRET)— header va payload'ni secret bilan imzolaydi; imzo soxtalashtirish to'sadi (secret'siz to'g'ri imzo yasab bo'lmaydi — hujumchi payload'ni o'zgartirsa — masalanrole: admin— imzo mos kelmaydi). Tekshirish: server imzoni qayta hisoblaydi (o'z secret'i bilan), agar mos kelsa — token haqiqiy (DB so'rovsiz — tez). Ikki nuqta: (1) JWT —header.payload.signature; payload ochiq (base64 — shifr emas — maxfiy ma'lumot qo'yma), imzo himoyalaydi (o'zgartirishni to'sadi); (2) imzo bilan — server token haqiqiyligini secret bilan tekshiradi (DB'siz, tez — bu JWT'ning afzalligi — stateless — 13.9: 2.4). JWT'ning kuchi — imzo (soxtalashtirib bo'lmaydi) va statelesslik (DB so'rovsiz tekshirish). Kamchiligi — payload ochiq (maxfiy ma'lumot qo'yma) va bekor qilish qiyin (muddat tugaguncha amal — 13.9: 2.4). JWT tuzilishini tushunish — uni xavfsiz ishlatishning asosi.
2.2. JWT keng xatolari
JWT KENG XAVFSIZLIK XATOLARI (eng ko'p uchraydigan):
1. ZAIF SECRET ("secret", "12345", qisqa):
hujumchi secret'ni taxmin/brute force soxta token (admin) yasaydi
kuchli, uzun, tasodifiy secret (32+ bayt — env'da)
2. alg=none HUJUMI (imzo "yo'q" deb aldash):
hujumchi header'ni { "alg": "none" } qiladi imzo tekshirilmaydi
algoritmni SERVER belgilaydi (token'dan olma — verify({ algorithms: ["HS256"] }))
3. MAXFIY MA'LUMOT payload'da (ochiq — 2.1):
parol, karta payload'da har kim o'qiydi
payload'da faqat ID, rol (maxfiy emas)
4. MUDDATSIZ TOKEN (exp yo'q):
o'g'irlangan token CHEKSIZ ishlaydi
qisqa muddat (access — 15 daqiqa) + refresh 2.3-bob
5. ALGORITM CHALKASHLIGI (RS256 HS256):
public key'ni secret sifatida ishlatish (imzo soxtalashtirilADI)
algoritmni qat'iy belgila
JWT xatolari — zaif secret, alg=none, maxfiy payload, muddatsiz, algoritm chalkashligi
Kutubxona to'g'ri ishlatilsa (algoritm belgila, secret kuchli) — ko'pini oldini oladiJWT keng xatolari — JWT'ni noto'g'ri ishlatishning eng keng turlari. (1) Zaif secret (
"secret","12345", qisqa): hujumchi secret'ni taxmin yoki brute force qiladi o'z soxta token'ini (role: admin) yasaydi va imzolaydi (secret bilsa, har qanday token yasash mumkin) himoya — kuchli, uzun, tasodifiy secret (32+ bayt —crypto.randomBytes— env'da); (2) alg=none hujumi: JWT spetsifikatsiyasida"alg": "none"(imzo yo'q) bor — hujumchi header'ni{ "alg": "none" }qilib, imzoni olib tashlaydi agar server algoritmni token'dan olsa, imzo tekshirilmaydi (token o'zgartirilsa qabul qilinadi) himoya — algoritmni server belgilaydi (verify(token, secret, { algorithms: ["HS256"] })— token'dan olma); (3) maxfiy ma'lumot payload'da (2.1 — payload ochiq): parol, karta payload'da har kim o'qiydi faqat ID, rol (maxfiy emas) qo'y; (4) muddatsiz token (expyo'q): o'g'irlangan token cheksiz ishlaydi qisqa muddat (access — 15 daqiqa) + refresh 2.3-bob; (5) algoritm chalkashligi (RS256 HS256): asimmetrik (RS256 — public/private key) ishlatsangiz, hujumchi algoritmni HS256'ga o'zgartirib, public key'ni secret sifatida ishlatishi mumkin (public key ochiq — imzo soxtalashtiriladi) algoritmni qat'iy belgila. Ikki nuqta: (1) JWT xatolari — zaif secret, alg=none, maxfiy payload, muddatsiz, algoritm chalkashligi (eng keng beshtasi); (2) kutubxona to'g'ri ishlatilsa (algoritm belgila, secret kuchli, muddat qo'y) — ko'pini avtomatik oldini oladi (zamonaviy kutubxonalaralg=noneni default rad qiladi). JWT kuchli, lekin noto'g'ri ishlatish keng (bu xatolar). To'g'ri: kuchli secret (env) + algoritm qat'iy belgila + muddat + maxfiy ma'lumot yo'q. Auth.js 13.9-bob bularni avtomatik qiladi (xavfsiz default). Qo'lda JWT yozsangiz — bu xatolarni bil.
2.3. Access va refresh token
ACCESS + REFRESH TOKEN — xavfsizlik va qulaylik balansi:
MUAMMO: token muddati:
uzun muddat (qulay, lekin o'g'irlansa uzoq xavf)
qisqa muddat (xavfsiz, lekin tez-tez qayta login — noqulay)
YECHIM — IKKI token:
1. ACCESS TOKEN (qisqa — 15 daqiqa):
har so'rovda ishlatiladi (API'ga); o'g'irlansa — 15 daqiqa xavf
xotirada/JS'da (qisqa muddat — kam xavf)
2. REFRESH TOKEN (uzun — 7 kun):
faqat YANGI access token olish uchun (kam ishlatiladi)
HttpOnly cookie (XSS'dan himoya); DB'da saqlanadi (bekor qilish uchun)
OQIM:
Login access (15 daq) + refresh (7 kun)
Access tugasa refresh bilan yangi access (qayta login YO'Q)
Logout/xavf refresh DB'dan o'chiriladi (bekor — barcha qurilma)
Access (qisqa — API) + refresh (uzun — yangi access olish, HttpOnly, DB'da)
Balans — qisqa access (kam xavf) + refresh (qulay — qayta login yo'q, bekor qilish mumkin)Access va refresh token — xavfsizlik va qulaylik balansi. Muammo: token muddati — uzun muddat (qulay — kam qayta login, lekin o'g'irlansa uzoq xavf), qisqa muddat (xavfsiz — o'g'irlansa kam xavf, lekin tez-tez qayta login — noqulay). Yechim — ikki token: (1) access token (qisqa — 15 daqiqa): har API so'rovida ishlatiladi (
Authorization: Bearer), o'g'irlansa faqat 15 daqiqa xavf (tez eskiriydi); xotirada yoki qisqa muddat saqlanadi; (2) refresh token (uzun — 7 kun): faqat yangi access token olish uchun (kam ishlatiladi — har 15 daqiqada bir marta), HttpOnly cookie (XSS'dan himoya — 14.2 — JS o'qiy olmaydi), va DB'da saqlanadi (bekor qilish uchun). Oqim: login access (15 daq) + refresh (7 kun) beriladi; access tugasa (15 daqiqadan keyin) refresh token bilan yangi access olinadi (qayta login yo'q — silliq); logout yoki xavf (o'g'irlik shubhasi) refresh token DB'dan o'chiriladi (bekor — endi yangi access olib bo'lmaydi — barcha qurilmada chiqarish). Ikki nuqta: (1) access (qisqa — API'da, o'g'irlansa kam xavf) + refresh (uzun — yangi access olish, HttpOnly cookie, DB'da bekor qilish uchun); (2) balans — qisqa access (xavfsizlik — o'g'irlansa 15 daqiqa) + refresh (qulaylik — qayta login yo'q, va bekor qilish mumkin — DB'dan o'chir). Bu — zamonaviy token auth'ning standart naqshi (JWT muddatsizlik muammosini — 13.9: 2.4 — qisman hal qiladi: access qisqa, refresh bekor qilinadi). Refresh token rotation (har ishlatilganda yangi refresh — eski bekor) — yanada xavfsiz (o'g'irlangan refresh bir marta ishlaydi). Access + refresh — JWT'ning amaliy, xavfsiz ishlatilishi.
2.4. Token saqlash (cookie vs localStorage)
TOKEN SAQLASH — qaerda? (XSS va CSRF balansi):
┌─────────────────┬──────────────────────┬──────────────────────┐
│ │ localStorage │ HttpOnly cookie │
├─────────────────┼──────────────────────┼──────────────────────┤
│ XSS │ JS o'qiydi (o'g'irlik)│ JS o'qiy olmaydi │
│ CSRF │ yo'q (header) │ bor (SameSite kerak)│
│ Qulaylik │ oson (JS qo'shadi) │ avtomatik (brauzer) │
└─────────────────┴──────────────────────┴──────────────────────┘
TAVSIYA (zamonaviy):
HttpOnly cookie (access + refresh) — XSS'dan himoya (eng katta xavf)
+ SameSite (CSRF) + Secure (HTTPS)
localStorage — XSS bo'lsa token o'g'irlanadi (qo'shimcha himoya bilan ehtiyot)
NEGA HttpOnly AFZAL:
XSS — eng keng frontend hujumi 14.2-bob; HttpOnly cookie XSS'da token'ni himoyalaydi
CSRF — SameSite bilan oson hal (14.4)
Token saqlash — HttpOnly cookie afzal (XSS himoya); localStorage XSS'ga zaif
Cookie: HttpOnly (XSS) + SameSite (CSRF) + Secure (HTTPS) — uch bayroqToken saqlash (cookie vs localStorage) — token'ni qaerda saqlash (XSS va CSRF balansi). Ikki variant: (1) localStorage — JavaScript o'qiydi: XSS'ga zaif (14.2 — agar XSS bo'lsa, hujumchi
localStorage.getItem("token")bilan token'ni o'g'irlaydi — eng katta xavf), lekin CSRF yo'q (token header'da qo'lda qo'shiladi — brauzer avtomatik qo'shmaydi — 14.4); (2) HttpOnly cookie — JavaScript o'qiy olmaydi: XSS'dan himoyalangan (document.cookietoken'ni ko'rmaydi — XSS bo'lsa ham o'g'irlanmaydi — 14.2: 2.3), lekin CSRF bor (brauzer avtomatik qo'shadi — SameSite kerak — 14.4). Tavsiya (zamonaviy): HttpOnly cookie (access + refresh) — XSS'dan himoya (eng katta xavf — XSS keng) + SameSite (CSRF — 14.4) + Secure (HTTPS). Nega HttpOnly afzal: XSS — eng keng frontend hujumi (14.2 — har sayt potensial nishon), va HttpOnly cookie XSS holatida ham token'ni himoyalaydi (JS o'qiy olmaydi); CSRF esa SameSite bilan oson hal qilinadi (14.4 — bir bayroq). Ya'ni XSS'ni hal qilish (HttpOnly) CSRF'ni hal qilishdan (SameSite) muhimroq, chunki XSS'da token to'liq o'g'irlanadi. Ikki nuqta: (1) token saqlash — HttpOnly cookie afzal (XSS himoya — eng katta xavf), localStorage XSS'ga zaif (ko'p qo'llanma "JWT localStorage'da" deydi — eski/xato maslahat); (2) cookie uch bayroq — HttpOnly (XSS) + SameSite (CSRF) + Secure (HTTPS). Bu munozarali mavzu (ba'zilar localStorage'ni himoya qiladi), lekin zamonaviy konsensus — HttpOnly cookie (XSS'dan himoya muhimroq). Agar localStorage ishlatsangiz — XSS'dan juda ehtiyot bo'lish kerak (CSP, sanitizatsiya — 14.2). Eng xavfsiz — HttpOnly cookie + qisqa access token + refresh rotation. Token saqlash — token auth'ning eng muhim xavfsizlik qarori.
2.5. Secrets boshqaruvi
SECRETS — maxfiy ma'lumot (API kalit, DB parol, JWT secret) boshqaruvi:
ENG KENG XATO — secret kodda yoki git'da:
const apiKey = "sk_live_abc123..."; // kodda — git'ga ketadi GitHub'da OCHIQ!
botlar git repolarni skanerlaydi bir necha daqiqada topadi suiiste'mol
TO'G'RI — secret env'da (kodda/git'da EMAS):
const apiKey = process.env.STRIPE_SECRET_KEY; // env'dan
// .env git'da YO'Q (.gitignore); production'da platforma sozlamasi (Vercel/vault)
DARAJALAR (xavfsizlik tartibi):
1. .env fayl (.gitignore) — development (oddiy)
2. Platforma env (Vercel/Railway sozlamasi) — production (yaxshi)
3. SECRETS MANAGER / VAULT (AWS Secrets Manager, HashiCorp Vault) — eng yaxshi
markaziy, shifrlangan, kirish nazorati, audit, rotation
Secret HECH QACHON kodda/git'da — env yoki vault (sizsa — darrov bekor + rotation)
Git'ga ketgan secret — BUTUNLAY bekor qil (git tarixida qoladi — o'chirish yetarli emas)Secrets boshqaruvi — maxfiy ma'lumotni (API kalit, DB parol, JWT secret) xavfsiz saqlash. Eng keng xato — secret'ni kodga yoki git'ga qo'yish:
const apiKey = "sk_live_abc123..."— kodda yozilgan secret git'ga ketadi, va agar repo public (yoki sizsa) — GitHub'da ochiq (botlar git repolarni doimiy skanerlaydi — yangi commit'larni tekshiradi — secret'ni bir necha daqiqada topadi va suiiste'mol qiladi — to'lov kaliti bilan pul, DB bilan ma'lumot). Bu juda keng (har kun minglab kalit GitHub'da sizadi). To'g'ri — secret env'da:process.env.STRIPE_SECRET_KEY(kodda faqat nomi, qiymat env'da — 13.10: 2.3),.envgit'da yo'q (.gitignore), production'da platforma sozlamasi (Vercel/server). Darajalar (xavfsizlik tartibi): (1).envfayl (.gitignore) — development (oddiy); (2) platforma env (Vercel/Railway sozlamasi) — production (yaxshi — shifrlangan, kodda yo'q); (3) secrets manager/vault (AWS Secrets Manager, HashiCorp Vault, Doppler) — eng yaxshi (markaziy, shifrlangan, kirish nazorati — kim qaysi secret'ga, audit — kim qachon o'qidi, rotation — avtomatik kalit aylantirish). Ikki nuqta: (1) secret hech qachon kodda/git'da — env yoki vault (agar sizsa — darrov bekor qil + rotation — yangi kalit); (2) git'ga ketgan secret — butunlay bekor qil (git tarixida qoladi — fayldan o'chirish yetarli emas — git history'da eski commit'da bor — har kim ko'ra oladi — shuning uchun bekor qilish — yangi kalit — yagona yechim). Bu — eng keng, eng oson oldini olinadigan xavfsizlik xatosi (secret kodda git sizish). Qoida: har secret env/vault'da,.envgit'da yo'q, git'ga ketgan secret darrov bekor. Pre-commit hook (git-secrets, gitleaks) — secret commit'ni avtomatik to'sadi (15-QISM). Secrets — ilova xavfsizligining poydevori (bittasi sizsa — katta zarar).
2.6. API kalit va kalit aylantirish (rotation)
API KALIT XAVFSIZLIGI va ROTATION:
API KALIT TURLARI:
SERVER kaliti (secret — sk_live_...) — server'da (env), brauzerga YO'Q (13.10: 2.3)
CLIENT kaliti (public — pk_...) — brauzerda OK (faqat public amallar)
har xizmat har xil (Stripe, OpenAI, AWS — to'g'ri turini ishlat)
API KALIT BEST PRACTICES:
Eng kam imtiyoz (least privilege — kalit faqat kerakli amalga — 14.1)
Domen/IP cheklash (kalit faqat sizning serveringizdan)
Alohida kalitlar (dev/prod, har xizmat — bittasi sizsa qolgani xavfsiz)
ROTATION (kalit aylantirish):
kalitlarni DAVRIY yangilash (eski bekor, yangi) — sizgan kalit muddatli
avtomatik (vault) yoki qo'lda (muntazam)
sizish bo'lsa — DARROV rotation (eski bekor)
API kalit — server (secret) brauzerga yo'q; least privilege + domen cheklash + alohida kalit
Rotation — kalitlarni davriy yangila (sizsa muddatli); sizish darrov rotationAPI kalit va kalit aylantirish (rotation) — API kalitlarni xavfsiz boshqarish. API kalit turlari: (1) server kaliti (secret —
sk_live_...) — server'da (env), brauzerga yo'q (13.10: 2.3 —NEXT_PUBLIC_emas — secret brauzerda ko'rinsa o'g'irlanadi); (2) client kaliti (public —pk_...) — brauzerda OK (faqat public amallar — masalan Stripe public key — to'lov formasi uchun — zarar kam); (3) har xizmat har xil (Stripe, OpenAI, AWS — to'g'ri turini ishlat — secret vs public). API kalit best practices: (1) eng kam imtiyoz (least privilege — 14.1: 2.3 — kalit faqat kerakli amalga — masalan faqat o'qish, faqat ma'lum endpoint — agar sizsa, zarar cheklangan); (2) domen/IP cheklash (kalit faqat sizning serveringizdan ishlasin — boshqa joydan rad — sizsa ham ishlamaydi); (3) alohida kalitlar (dev/prod alohida, har xizmat alohida — bittasi sizsa qolgani xavfsiz — izolyatsiya). Rotation (kalit aylantirish): kalitlarni davriy yangilash (eski bekor, yangi — sizgan kalit faqat aylantirishgacha amal — muddatli zarar), avtomatik (vault — 2.5) yoki qo'lda (muntazam — har necha oy), va sizish bo'lsa — darrov rotation (eski kalitni darrov bekor, yangisini ber). Ikki nuqta: (1) API kalit — server (secret) brauzerga yo'q 13.10-bob, least privilege + domen cheklash + alohida kalit (dev/prod, har xizmat); (2) rotation — kalitlarni davriy yangila (sizsa muddatli zarar), sizish bo'lsa darrov rotation (eski bekor). Rotation — secret sizishining zararini cheklaydi (sizgan kalit cheksiz emas — aylantiriladi). Ko'p ilova rotation qilmaydi (bir kalit yillar — sizsa cheksiz zarar). Best — vault bilan avtomatik rotation, yoki muntazam qo'lda. API kalit + secrets boshqaruvi 2.5-bob — birga maxfiy ma'lumot himoyasi (env/vault + least privilege + rotation). Bu — production ilovaning maxfiy ma'lumot poydevori.
2.7. JWT imzo algoritmlari — HS256 vs RS256/ES256 (qachon qaysi)
JWT IMZO ALGORITMLARI — simmetrik vs asimmetrik:
1. HS256 (HMAC-SHA256) — SIMMETRIK (bitta maxfiy kalit):
bir SECRET bilan imzolaydi VA tekshiradi (imzolagan = tekshirgan)
tez, oddiy; lekin secret'ni har tekshiruvchi bilishi shart
Bir servis o'zi imzolaydi va o'zi tekshiradi (monolit)
Ko'p servis tekshirsa — hammasida secret sizish yuzasi katta
2. RS256 (RSA-SHA256) / ES256 (ECDSA-SHA256) — ASIMMETRIK (juft kalit):
PRIVATE key bilan imzolaydi (faqat auth-server), PUBLIC key bilan tekshiradi
tekshiruvchi faqat PUBLIC key oladi (imzolay olmaydi — soxta token yasay olmaydi)
Ko'p servis / mikroservis (har biri public key bilan tekshiradi — private bitta joyda)
OIDC/OAuth provayder (Auth0, Google) — public key JWKS orqali tarqatadi
ES256 — RS256'dan qisqa kalit, tez (elliptik egri chiziq) — zamonaviy tanlov
QACHON QAYSI:
HS256 — monolit (bitta servis imzolaydi + tekshiradi), oddiy, tez
RS256/ES256 — imzolovchi ≠ tekshiruvchi (mikroservis, 3-tomon, OIDC)
HS256 — bitta secret (imzo=tekshir); RS256/ES256 — private (imzo) + public (tekshir)
Ko'p tekshiruvchi bo'lsa — ASIMMETRIK (public tarqat, private yashir)JWT imzo algoritmlari — imzoni qanday hisoblash (simmetrik vs asimmetrik). (1) HS256 (HMAC-SHA256) — simmetrik: bitta maxfiy kalit (secret) bilan token imzolanadi va tekshiriladi (imzolagan tomon va tekshiruvchi tomon bir xil secret'ni biladi). Tez va oddiy — bitta servis o'zi imzolab, o'zi tekshiradigan holatda (monolit) ideal. Kamchiligi — agar token'ni ko'p servis tekshirishi kerak bo'lsa, secret hammasida bo'ladi (secret'ni bir joy sizsa — hamma token soxtalashtiriladi — sizish yuzasi katta). (2) RS256 (RSA-SHA256) yoki ES256 (ECDSA-SHA256) — asimmetrik: juft kalit — private key bilan imzolanadi (faqat auth-server biladi) va public key bilan tekshiriladi (tekshiruvchilarga tarqatiladi). Tekshiruvchi faqat public key oladi — u imzolay olmaydi (soxta token yasay olmaydi) — bu asosiy afzallik: imzo huquqi bitta joyda (private), tekshirish hamma joyda (public). Shuning uchun mikroservis (har servis public key bilan tekshiradi, private bitta auth-serverda) va OIDC/OAuth provayderlar (Google, Auth0 — public kalitlarni JWKS endpoint orqali tarqatadi — 2.8) uchun asimmetrik standart. ES256 (elliptik egri chiziq) RS256'dan qisqa kalit va tezroq — zamonaviy tanlov. Qachon qaysi: HS256 — monolit (bitta servis imzolaydi va tekshiradi — oddiy, tez); RS256/ES256 — imzolovchi tekshiruvchidan farq qilsa (mikroservis, 3-tomon integratsiya, OIDC). Ikki nuqta: (1) HS256 — bitta secret (imzo = tekshir kaliti bir xil); RS256/ES256 — private (imzo) + public (tekshir) juft; (2) ko'p tekshiruvchi bo'lsa asimmetrik ishlat (public'ni tarqating, private'ni yashiring). Bu tanlov algoritm chalkashligi hujumi bilan bog'liq 2.2-bob: agar server RS256 kutayotgan bo'lsa-yu, algoritmni token'dan olsa, hujumchi HS256'ga o'zgartirib, public key'ni HMAC secret sifatida ishlatishi mumkin (public ochiq — imzo soxtalashtiriladi) — shuning uchun
verifyda algoritm har doim qat'iy belgilanadi (2.2, Misol 1).
2.8. Standart claim'lar va JWK/kid kalit boshqaruvi
STANDART CLAIM'LAR (RFC 7519) — payload'da qanday maydonlar:
iss (issuer) — token'ni kim bergan (auth-server) verify: kutilgan iss'mi
sub (subject) — kim haqida (foydalanuvchi ID)
aud (audience) — token kim uchun (qaysi API/servis) verify: bu servis aud'dami
exp (expiry) — muddat tugash vaqti verify: hozir < exp
nbf (not before) — bundan oldin amal qilmaydi verify: hozir >= nbf
iat (issued at) — qachon berilgan yosh tekshirish, rotatsiya
jti (JWT ID) — token identifikatori denylist / reuse aniqlash
VALIDATSIYA: faqat imzo emas — iss/aud/exp/nbf HAM tekshiriladi
(imzo to'g'ri, lekin boshqa servis uchun token aud rad qiladi)
JWK / kid (asimmetrik kalit boshqaruvi va rotatsiya):
JWKS — public kalitlar to'plami (JSON) /.well-known/jwks.json da
header'da "kid" (key id) qaysi kalit bilan imzolangan
tekshiruvchi kid bo'yicha JWKS'dan to'g'ri public key'ni topadi
ROTATSIYA: yangi kalit qo'shiladi (yangi kid), eski biroz saqlanadi
(eski token'lar hali amal) keyin eski olib tashlanadi
kid + JWKS — kalitni tokenni buzmasdan aylantirish imkoniStandart claim'lar va JWK/kid — payload maydonlarini to'g'ri ishlatish va asimmetrik kalitlarni boshqarish. Standart claim'lar (RFC 7519 — registrlangan maydonlar):
iss(issuer — token'ni kim bergan),sub(subject — kim haqida, odatda foydalanuvchi ID),aud(audience — token qaysi API/servis uchun mo'ljallangan),exp(expiry — muddat tugashUnixvaqti),nbf(not before — bundan oldin amal qilmaydi),iat(issued at — qachon berilgan),jti(JWT ID — noyob identifikator — denylist va reuse aniqlash uchun — 2.9). Juda muhim — token'ni tekshirishda faqat imzo emas,iss/aud/exp/nbfham tekshiriladi: imzo to'g'ri bo'lishi mumkin (haqiqiy auth-serverdan), lekin token boshqa servis uchun berilgan bo'lsa (audmos emas) — rad qilinishi kerak (aks holda A servis uchun token B servisda ishlatiladi). Kutubxona (jsonwebtoken,jose)verifyda{ issuer, audience }parametrlarini beradi — ular avtomatik tekshiriladi. JWK/kid (asimmetrik kalit boshqaruvi va rotatsiya — 2.7 bilan): JWKS (JSON Web Key Set) — public kalitlar to'plami, odatda/.well-known/jwks.jsonmanzilida ochiq turadi; token header'idakid(key ID) bo'ladi — u token qaysi kalit bilan imzolanganini ko'rsatadi; tekshiruvchikidbo'yicha JWKS'dan to'g'ri public key'ni topadi. Bu rotatsiyani osonlashtiradi: yangi kalit qo'shiladi (yangikidbilan), eski kalit biroz vaqt saqlanadi (u bilan imzolangan token'lar hali amal qiladi), keyin olib tashlanadi — token'larni buzmasdan kalit aylantiriladi. Ikki nuqta: (1) validatsiya — imzodan tashqariiss/aud/exp/nbfham tekshiring (imzo to'g'ri, lekin noto'g'ri auditoriya — rad); (2)kid+ JWKS — asimmetrik kalitni token'larni sindirmasdan aylantirish mexanizmi. Bu OIDC/OAuth provayderlarning (Google, Auth0) ishlash usuli — sizning ilovangiz ularning JWKS'ini o'qib,kidbo'yicha token'larni tekshiradi.
2.9. Token bekor qilish (revocation) va JWE
JWT MUAMMOSI: stateless BEKOR QILISH qiyin (muddat tugaguncha amal).
Yechimlar (tez darajadan kuchli darajagacha):
1. QISQA exp + refresh 2.3-bob — access 15 daqiqa zarar oynasi kichik (asosiy)
2. DENYLIST (blacklist) — bekor qilingan jti'lar Redis'da (exp'gacha saqlanadi)
verify: jti denylist'dami? ha bo'lsa rad
Redis TTL = token exp (avtomatik tozalanadi — o'sib ketmaydi)
3. TOKEN VERSIONING — user.tokenVersion DB'da; payload'da ham ver
parol o'zgarsa / "hamma qurilmadan chiq" tokenVersion++
verify: payload.ver === user.tokenVersion? eski hammasi bekor
4. REFRESH-only bekor 2.3-bob — access qisqa, refresh DB'da o'chir
Toza stateless bekor yo'q qisqa exp + denylist/versioning (yarim-stateful)
JWE — SHIFRLANGAN token (JWS imzolangan, JWE shifrlangan):
JWT odatda JWS (imzolangan, payload OCHIQ — 2.1)
JWE — payload ham SHIFRLANGAN (o'qib bo'lmaydi) maxfiy claim kerak bo'lsa
lekin: baribir payload'ga maxfiy ma'lumot qo'ymaslik eng yaxshi amaliyot
Odatda JWS + qisqa umr yetarli; JWE — payload maxfiyligi zarur bo'lgan kam holatToken bekor qilish (revocation) va JWE — JWT'ning stateless tabiatidan kelib chiqadigan eng katta amaliy muammo. Muammo: imzolangan JWT server holatidan mustaqil — token to'g'ri imzolangan va muddati tugamagan bo'lsa, server uni qabul qiladi (DB'ga qaramaydi). Demak o'g'irlangan yoki "chiqarilishi kerak bo'lgan" token'ni darrov bekor qilib bo'lmaydi (muddat tugaguncha amal qiladi). Yechimlar (tez darajadan kuchliroq darajagacha): (1) qisqa
exp+ refresh 2.3-bob — access token 15 daqiqa bo'lsa, zarar oynasi 15 daqiqa — bu asosiy va eng oddiy yechim; (2) denylist (blacklist/rad ro'yxati) — bekor qilingan token'larningjti'larini Redis'da saqlash,verifyda har token uchun "denylist'dami?" deb tekshirish — agar bor bo'lsa rad; Redis'da TTL tokenexp'iga teng qilinadi (token muddati tugagach avtomatik o'chadi — ro'yxat cheksiz o'smaydi); (3) token versioning — foydalanuvchidatokenVersion(DB'da) va payload'da hamver; parol o'zgarganda yoki "hamma qurilmadan chiqish" bosilgandatokenVersionni oshirishverifydapayload.ver === user.tokenVersiontekshiriladi — bir zarbada foydalanuvchining barcha eski token'lari bekor bo'ladi (bu bitta DB o'qishni talab qiladi — toza stateless emas, lekin arzon); (4) refresh-only bekor 2.3-bob — access qisqa, refresh DB'da — refresh'ni o'chirish orqali seansni tugatish. Nuqta: toza stateless bekor qilish mumkin emas — qisqaexp+ denylist yoki versioning (yarim-stateful) birgalikda ishlatiladi. JWE (JSON Web Encryption): odatiy JWT — JWS (JSON Web Signature — imzolangan, payload ochiq — 2.1). JWE esa payload'ni ham shifrlaydi (o'qib bo'lmaydi) — agar token ichida maxfiy claim tashish zarur bo'lsa ishlatiladi. Lekin eng yaxshi amaliyot baribir payload'ga maxfiy ma'lumot qo'ymaslik — shuning uchun JWE kam holatlarda kerak bo'ladi; ko'pincha JWS + qisqa umr yetarli. Amaliy xulosa: bekor qilish talabi bo'lsa (bank, nozik ilova), yo database sessiya (13.9: 2.4, Misol 5) ni tanlang, yoki qisqa access + denylist/versioning qo'shing.
2.10. Hashing vs shifrlash vs kodlash (muhim farq)
UCHTASI HAR XIL — ARALASHTIRMANG (eng keng tushunmovchilik):
1. KODLASH (encoding) — base64, URL-encode, hex:
maqsad: FORMAT (ma'lumotni tashish uchun) — MAXFIYLIK EMAS
teskari: OSON (har kim dekod qiladi — kalit yo'q)
misol: JWT payload base64 (2.1 — har kim o'qiydi!)
hech qachon "yashirish" uchun ishlatmang
2. HASHING — SHA-256, bcrypt, argon2:
maqsad: BIR TOMONLAMA barmoq izi (parol, imzo, butunlik)
teskari: MUMKIN EMAS (hash'dan asl matnni tiklab bo'lmaydi)
parol bcrypt/argon2 (sekin, sho'r — 14.5); butunlik SHA-256
parolga SHA-256 EMAS — bcrypt/argon2 (sekin, brute force'ga qarshi)
3. SHIFRLASH (encryption) — AES-GCM, RSA:
maqsad: MAXFIYLIK — kalit bilan yashirish, KALIT bilan qaytarish
teskari: kalit bilan MUMKIN (kalitsiz — yo'q)
maxfiy ma'lumot saqlash/uzatish (DB'da karta, JWE payload)
Kodlash ≠ shifrlash (base64 himoya EMAS); hash bir tomonlama; shifr qaytariladi
Parol HASH (bcrypt); maxfiy saqlash SHIFR (AES); tashish KODLASH (base64)Hashing vs shifrlash vs kodlash — bu uchtasi tez-tez aralashtiriladi, ammo ular butunlay boshqa maqsadlarga xizmat qiladi (bu farqni tushunmaslik jiddiy xatolarga olib keladi — masalan "base64 bilan yashirdim" degan yolg'on xavfsizlik hissi). (1) Kodlash (encoding — base64, URL-encode, hex): maqsadi — ma'lumotni formatlaydi (matnli kanal orqali tashish uchun, masalan binary ma'lumotni matnga) — maxfiylik emas; teskari qilish oson (kalit kerak emas — har kim dekod qiladi). JWT payload base64 2.1-bob — aynan shu: har kim o'qiydi. Hech qachon "yashirish" uchun kodlashni ishlatmang. (2) Hashing (SHA-256, bcrypt, argon2): maqsadi — bir tomonlama barmoq izi; hash'dan asl matnni tiklab bo'lmaydi (matematik jihatdan bir tomonlama). Ikki holatda: parol saqlash —
bcrypt/argon2(ataylab sekin va sho'rlangan — brute force'ga qarshi — 14.5); butunlik/imzo —SHA-256(tez — HMAC, checksum uchun). Muhim — parolga tezSHA-256emas 14.5-bob, sekinbcrypt/argon2. (3) Shifrlash (encryption — AES-GCM, RSA): maqsadi — maxfiylik; kalit bilan yashiriladi va o'sha (yoki juft) kalit bilan qaytariladi (teskari qilinadigan — kodlashdan farqi shu: kalit kerak). Maxfiy ma'lumotni saqlash (DB'da karta raqami) yoki uzatishda ishlatiladi. Ikki nuqta: (1) kodlash shifrlash emas (base64 hech qanday himoya bermaydi); hash bir tomonlama (qaytmaydi); shifr qaytariladi (kalit bilan); (2) parol uchun hash (bcrypt), maxfiy saqlash uchun shifr (AES), tashish/format uchun kodlash (base64). Amaliy qoida: "yashirish kerakmi, qaytarish kerakmi?" — qaytarish kerak bo'lmasa (parol) hash; qaytarish kerak bo'lsa (karta) shifr; hech biri kerak bo'lmasa (format) kodlash.
2.11. Kriptografik primitivlar — CSPRNG, constant-time, AES-GCM, envelope
XAVFSIZLIKDA XOM KRIPTO — TO'G'RI PRIMITIV MUHIM:
1. TASODIFIYLIK — crypto.randomBytes vs Math.random:
Math.random() — TAXMIN QILINADI (kriptografik EMAS) token/secret UCHUN EMAS
crypto.randomBytes(32) — CSPRNG (kriptografik tasodifiy) token, secret, jti
har secret/token crypto.randomBytes (Math.random hech qachon)
2. CONSTANT-TIME COMPARE — timing hujumi:
a === b / == — ERTA to'xtaydi (birinchi farqda) vaqt sirni oshkor qiladi
crypto.timingSafeEqual(a, b) — DOIM bir xil vaqt timing hujum yo'q
secret/token/imzo solishtirish timingSafeEqual (=== EMAS)
3. SIMMETRIK SHIFR — AES-256-GCM (authenticated encryption):
GCM — shifrlaydi VA butunlikni tekshiradi (auth tag) o'zgartirish aniqlanadi
har shifrlashda YANGI IV (nonce) — takrorlanmasin
AES-GCM (ECB EMAS — ECB naqsh chiqaradi, xavfli)
4. ASIMMETRIK — RSA / ECC (juft kalit): kalit almashish, imzo 2.7-bob
5. ENVELOPE ENCRYPTION (KMS) — kalitni kalit bilan shifrlash:
ma'lumot DEK (data key) bilan shifr; DEK KEK (KMS master) bilan shifr
KEK hech qachon KMS'dan chiqmaydi DEK sizsa ham asl ma'lumot xavfsiz
at-rest (disk/DB shifr) + in-transit (TLS — 14.7) — ikkalasi kerakKriptografik primitivlar — xavfsizlik kodida to'g'ri "qurilish bloklari"ni ishlatish (noto'g'ri primitiv — nozik, lekin jiddiy zaiflik). (1) Tasodifiylik —
Math.random()kriptografik emas (natijasi taxmin qilinadigan — psevdo-tasodifiy) token, secret,jti, parol tiklash kodi uchun hech qachon ishlatmang;crypto.randomBytes(32)— CSPRNG (kriptografik xavfsiz psevdo-tasodifiy generator) barcha secret/token shu bilan. (2) Constant-time compare —===yoki==bilan solishtirish erta to'xtaydi (birinchi farq bo'lgan baytda) — bu vaqt farqi orqali hujumchi sirni bayt-bayt taxmin qilishi mumkin (timing hujumi);crypto.timingSafeEqual(a, b)doimo bir xil vaqt sarflaydi (farq qayerda bo'lishidan qat'i nazar) token, imzo, secret solishtirishda shuni ishlating (webhook imzosi — 2.13, API kalit tekshiruvi). (3) Simmetrik shifr —AES-256-GCM— authenticated encryption: shifrlaydi va butunlikni tekshiradi (auth tag — ma'lumot o'zgartirilsa dekodlashda aniqlanadi); har shifrlashda yangi IV (nonce — takrorlanmasligi shart);AES-ECBni ishlatmang (naqshni oshkor qiladi — xavfli). (4) Asimmetrik — RSA/ECC (juft kalit) — kalit almashish va imzo uchun 2.7-bob. (5) Envelope encryption (KMS bilan) — kalitni kalit bilan shifrlash: ma'lumot DEK (data encryption key) bilan shifrlanadi, DEK esa KEK (key encryption key — KMS master kalit) bilan shifrlanadi; KEK hech qachon KMS'dan chiqmaydi (faqat KMS ichida shifrlaydi/qaytaradi) — shuning uchun shifrlangan DEK sizsa ham, asl ma'lumot xavfsiz (DEK'ni ochish uchun KMS kerak). Ikki nuqta: (1) tasodif —crypto.randomBytes, solishtirish —timingSafeEqual, shifr —AES-GCM(to'g'ri primitiv tanlash); (2) at-rest (diskda/DB'da shifrlangan) va in-transit (uzatishda TLS — 14.7: 2) — ikkalasi ham kerak (biri yetarli emas). Xom kriptoni o'zingiz yozmang (masalan o'z shifr algoritmingiz) — sinovdan o'tgan kutubxona (Nodecrypto,libsodium) va yuqori darajali xizmatlarni (KMS) ishlating.
2.12. TLS/sertifikat, OAuth token va session entropiyasi
TRANSPORT VA TASHQI TOKEN'LAR:
TLS (in-transit shifr) — token/secret tarmoqda OCHIQ ketmasin (14.7: 2)
HTTPS majburiy; Secure cookie bayrog'i (faqat HTTPS'da yuborilsin — 2.4)
SERTIFIKAT — server haqiqiyligini tasdiqlaydi (MITM oldini) tekshiring, e'tiborsiz qoldirmang
OAUTH / OIDC TOKEN'LARI:
access_token (API'ga), refresh_token (yangilash), id_token (OIDC — kim — JWT)
provayder (Google, GitHub) imzolaydi (RS256 — 2.7); JWKS bilan tekshiring
scope — token nimaga ruxsat (least privilege — faqat kerakligini so'rang)
SESSION / TOKEN ENTROPIYASI:
session ID / opaque token — YETARLI ENTROPIYA (>= 128 bit) + CSPRNG
qisqa/taxminiy ID guessing/brute force hisob egallash
crypto.randomBytes(32) (256 bit) — xavfsiz standart
TLS (in-transit) + Secure cookie; OAuth token — RS256/JWKS, scope cheklangTLS/sertifikat, OAuth token va session entropiyasi — token/secretlarning tarmoq va tashqi provayder tomoni. TLS (in-transit shifrlash — 14.7: 2): token va secret'lar tarmoq orqali ochiq (shifrlanmagan) ketmasligi shart — aks holda tarmoqni tinglagan hujumchi ularni o'qiydi; shuning uchun HTTPS majburiy va cookie'da
Securebayrog'i qo'yiladi (cookie faqat HTTPS orqali yuboriladi — 2.4). Sertifikat server haqiqiyligini tasdiqlaydi (MITM — o'rtadagi odam hujumini oldini oladi) — mijoz sertifikatni tekshirishi shart (masalanNODE_TLS_REJECT_UNAUTHORIZED=0bilan e'tiborsiz qoldirmang — bu himoyani o'chiradi; TLS batafsil — 14.7). OAuth/OIDC token'lari:access_token(resurs API'ga kirish),refresh_token(yangilash),id_token(OIDC — foydalanuvchi kimligi — JWT formatida); bu token'larni provayder (Google, GitHub, Auth0) o'z private kaliti bilan imzolaydi (odatda RS256 — 2.7), sizning ilovangiz provayderning JWKS'i 2.8-bob orqali public kalit bilan tekshiradi;scope— token nimaga ruxsat berishini belgilaydi (least privilege — 14.1 — faqat kerakli ruxsatni so'rang, "hamma narsa"ni emas). Session/token entropiyasi: session ID yoki opaque (JWT emas — tasodifiy) token yetarli entropiyaga ega bo'lishi kerak (kamida 128 bit, yaxshisi 256) va CSPRNG bilan yaratilishi shart 2.11-bob — qisqa yoki taxminiy ID guessing/brute force orqali topilib, hisob egallanadi;crypto.randomBytes(32)(256 bit) — xavfsiz standart. Nuqta: TLS (in-transit) +Securecookie token'ni tarmoqda himoyalaydi; OAuth token'larini RS256/JWKS bilan tekshiring vascopeni cheklang. Bu qatlam token/secret xavfsizligini tarmoq 14.7-bob va tashqi auth provayder (OAuth) darajalari bilan bog'laydi.
2.13. API kalit generatsiyasi va webhook imzosi (HMAC)
API KALIT GENERATSIYASI — o'z API'ngiz uchun kalit berish:
GENERATSIYA: crypto.randomBytes(32) (CSPRNG — 2.11)
PREFIX: "sk_live_" + tasodifiy tur/muhitni ko'rsatadi, skanerlar tanidi
SAQLASH: DB'da HASH (SHA-256) — asl kalit BIR MARTA ko'rsatiladi (parol kabi — 14.5)
DB sizsa — kalitlar himoyalangan (hash'dan asl tiklanmaydi)
SCOPE: kalit nimaga ruxsat (least privilege — 14.1)
tekshirish: kelgan kalitni hash DB'dagi hash bilan timingSafeEqual
WEBHOOK IMZOSI — tashqi xizmat (Stripe, GitHub) kelgan so'rovni tekshirish:
provayder body'ni maxfiy signing secret bilan HMAC qiladi header'da imzo
siz o'z HMAC'ingizni hisoblab, timingSafeEqual bilan solishtirasiz 2.11-bob
mos kelsa — so'rov haqiqiy (aks holda soxta — rad)
RAW body ustidan HMAC (JSON.parse'dan OLDIN — bayt-ba-bayt) + timing-safe
API kalit — DB'da HASH; webhook — HMAC imzo + timingSafeEqual (8.20)API kalit generatsiyasi va webhook imzosi — token/secret naqshlarini o'z API'ngizga qo'llash. API kalit generatsiyasi (o'z ilovangiz mijozlarga API kalit bersa): (1) generatsiya —
crypto.randomBytes(32)(CSPRNG — 2.11 — taxmin qilinmaydigan); (2) prefix — kalit oldigask_live_/sk_test_kabi belgi qo'yiladi (turini va muhitni ko'rsatadi; qo'shimcha foyda — gitleaks kabi skanerlar bu naqshni tanib, git'ga sizgan kalitni topadi — 2.5); (3) saqlash — kalitni DB'da hash holda (SHA-256) saqlang, asl kalit foydalanuvchiga bir marta ko'rsatiladi (parol kabi — 14.5 — keyin faqat hash qoladi) — shunda DB sizsa ham kalitlar himoyalangan (hash'dan asl kalit tiklanmaydi); (4) scope — har kalit nimaga ruxsat berishini belgilang (least privilege — 14.1); (5) tekshirish — kelgan kalitni hash qilib, DB'dagi hash bilantimingSafeEqual2.11-bob orqali solishtiring. Webhook imzosi (tashqi xizmat — Stripe, GitHub — sizning endpoint'ingizga so'rov yuborganda, uning haqiqiyligini tekshirish — 8.20): provayder so'rov body'sini o'zining maxfiy signing secret'i bilan HMAC qilib, natijani header'ga (masalanStripe-Signature) qo'yadi; siz o'sha secret bilan (u sizda ham bor — provayder bergan) body ustidan o'z HMAC'ingizni hisoblaysiz va header'dagi imzo bilantimingSafeEqualorqali solishtirasiz — mos kelsa so'rov haqiqiy (aks holda soxta — kimdir webhook'ni qalbakilashtirmoqda — rad qiling). Muhim — HMAC raw (xom) body ustidan hisoblanadi (JSON.parse'dan oldin, bayt-ba-bayt — chunki qayta serializatsiya baytlarni o'zgartirishi mumkin) va solishtirish timing-safe bo'lishi shart. Ikki nuqta: (1) API kalit — DB'da hash saqlang (parol kabi), tekshiruvdatimingSafeEqual; (2) webhook — HMAC imzo (raw body + shared secret) vatimingSafeEqualbilan tekshiring 8.20-bob. Bu ikkalasi ham xuddi JWT imzosi 2.1-bob va parol hash 14.5-bob kabi bir xil primitivlarga (HMAC, hash, timing-safe compare — 2.11) tayanadi — token/secret xavfsizligining amaliy qo'llanilishi.
3. Sintaksis — tez ma'lumotnoma
JWT TUZILISH 2.1-bob: header.payload.signature; payload OCHIQ (base64)
JWT VERIFY 2.2-bob: jwt.verify(token, secret, { algorithms: ["HS256"] })
JWT SECRET 2.2-bob: crypto.randomBytes(32) (kuchli, env'da)
ACCESS/REFRESH 2.3-bob:access 15min (API) + refresh 7kun (HttpOnly cookie, DB)
SAQLASH 2.4-bob: HttpOnly + SameSite + Secure cookie (localStorage emas)
SECRET 2.5-bob: process.env.X (kodda/git'da emas; .gitignore)
API KALIT 2.6-bob: server secret (env) | client public (pk_); least privilege
ROTATION 2.6-bob: davriy yangilash; sizish darrov bekor
ALGORITM 2.7-bob: HS256 (monolit, bitta secret) | RS256/ES256 (mikroservis, juft kalit)
CLAIM VERIFY 2.8-bob: verify(token, key, { algorithms, issuer, audience }) + exp/nbf
JWK/kid 2.8-bob: JWKS (public kalitlar) + kid kalit rotatsiya
BEKOR QILISH 2.9-bob: qisqa exp + denylist (Redis jti) | tokenVersion (DB)
FARQ 2.10-bob: kodlash (base64) ≠ shifr (AES) ≠ hash (bcrypt/SHA-256)
TASODIF 2.11-bob: crypto.randomBytes(32) (Math.random EMAS)
SOLISHTIR 2.11-bob: crypto.timingSafeEqual (=== EMAS — timing)
SHIFR 2.11-bob: AES-256-GCM (auth encryption, yangi IV); envelope=KMS
WEBHOOK 2.13-bob: HMAC imzo + timingSafeEqual verify 8.20-bob
API KALIT GEN: prefix + crypto.randomBytes; DB'da HASH saqla (2.13, Misol 8)4. Batafsil misollar
Har misol: Maqsad + izohli kod + "Bu nima qiladi".
Misol 1 — Xavfsiz JWT yaratish va tekshirish (2.1, 2.2)
Maqsad: JWT'ni to'g'ri (kuchli secret, algoritm belgilangan, muddat) yaratish va tekshirish. Bu keng xatolardan qochish.
import jwt from "jsonwebtoken";
// SECRET — kuchli, env'dan (kodda emas — 2.5):
const JWT_SECRET = process.env.JWT_SECRET!; // crypto.randomBytes(32).toString("hex")
// YARATISH — faqat kerakli ma'lumot (maxfiy emas — 2.2):
function createAccessToken(user: { id: string; role: string }) {
return jwt.sign(
{ sub: user.id, role: user.role }, // faqat ID, rol (parol/maxfiy YO'Q — payload ochiq)
JWT_SECRET,
{ algorithm: "HS256", expiresIn: "15m" } // algoritm + qisqa muddat (2.3)
);
}
// TEKSHIRISH — algoritm QAT'IY belgilangan (alg=none oldini — 2.2):
function verifyToken(token: string) {
try {
return jwt.verify(token, JWT_SECRET, {
algorithms: ["HS256"], // FAQAT HS256 (token'dan olma — alg=none/RS256 chalkashligi oldini)
});
} catch {
return null; // yaroqsiz/muddati tugagan
}
}Bu nima qiladi: Bu — xavfsiz JWT (keng xatolardan qochish — 2.1, 2.2). Secret: process.env.JWT_SECRET — kuchli (crypto.randomBytes(32) — 32 bayt tasodifiy — taxmin/brute force qilib bo'lmaydi — 2.2), env'dan (kodda emas — 2.5). Yaratish (createAccessToken): jwt.sign(...) — (1) payload'da faqat sub (foydalanuvchi ID) va role (maxfiy emas — 2.2 — parol, karta qo'yma — payload ochiq, har kim o'qiydi); (2) algorithm: "HS256" (algoritm aniq), expiresIn: "15m" (15 daqiqa muddat — qisqa access — 2.3 — o'g'irlansa kam xavf). Tekshirish (verifyToken): jwt.verify(token, JWT_SECRET, { algorithms: ["HS256"] }) — eng muhim — algorithms: ["HS256"] (algoritm qat'iy belgilangan — token header'dan olma) — bu alg=none hujumini (hujumchi alg: none qilsa — rad, chunki faqat HS256 qabul) va algoritm chalkashligi (RS256HS256) ni oldini oladi 2.2-bob; try/catch — yaroqsiz yoki muddati tugagan token — null. Demak bu JWT to'rt xatoni oldini oladi: zaif secret (kuchli, env), maxfiy ma'lumot (faqat ID/rol), muddatsiz (15m), alg=none/chalkashlik (algoritm qat'iy). Eng keng xato — jwt.verify(token, secret) (algoritm belgilamasdan — alg=none ga zaif) yoki zaif secret ("secret"). To'g'ri — kuchli secret + algoritm qat'iy + qisqa muddat + maxfiy ma'lumot yo'q. Zamonaviy kutubxonalar (jose, jsonwebtoken yangi versiyalar) ko'pini default to'g'ri qiladi, lekin algoritmni aniq belgilash har doim yaxshi amaliyot. Auth.js 13.9-bob buni avtomatik qiladi — qo'lda JWT yozsangiz, bu naqsh.
Misol 2 — Access + refresh token oqimi (2.3)
Maqsad: Access va refresh token bilan to'liq auth oqimi — qisqa access, uzun refresh, yangilash. Bu xavfsizlik va qulaylik balansi.
import { cookies } from "next/headers";
// LOGIN — access + refresh berish:
async function login(user: User) {
const accessToken = createAccessToken(user); // 15 daqiqa (Misol 1)
const refreshToken = crypto.randomBytes(32).toString("hex"); // tasodifiy (JWT emas — DB'da)
// Refresh token DB'da HASH holda (bekor qilish + sizsa himoya):
await db.refreshToken.create({
data: { tokenHash: sha256(refreshToken), userId: user.id, expiresAt: addDays(7) },
});
const store = await cookies();
// Ikkala token — HttpOnly cookie (XSS himoya — 2.4):
store.set("access", accessToken, { httpOnly: true, secure: true, sameSite: "lax", maxAge: 900 });
store.set("refresh", refreshToken, { httpOnly: true, secure: true, sameSite: "lax", maxAge: 604800, path: "/api/refresh" });
}
// YANGILASH — access tugaganda (refresh bilan):
async function refresh(refreshToken: string) {
const record = await db.refreshToken.findUnique({ where: { tokenHash: sha256(refreshToken) } });
if (!record || record.expiresAt < new Date()) throw new Error("Qayta kiring");
const user = await db.user.findUnique({ where: { id: record.userId } });
// ROTATION — eski refresh bekor, yangi (o'g'irlangan refresh bir marta — 2.3):
await db.refreshToken.delete({ where: { id: record.id } });
return login(user!); // yangi access + refresh
}
// LOGOUT — refresh DB'dan o'chir (bekor):
async function logout(refreshToken: string) {
await db.refreshToken.deleteMany({ where: { tokenHash: sha256(refreshToken) } });
}Bu nima qiladi: Bu — access + refresh token oqimi (xavfsizlik + qulaylik — 2.3). Login: (1) access token (15 daqiqa JWT — Misol 1 — API so'rovlari uchun); (2) refresh token (crypto.randomBytes — tasodifiy, JWT emas — DB'da saqlanadi — bekor qilish uchun); (3) refresh token DB'da hash holda (sha256 — agar DB sizsa, refresh tokenlar himoyalangan — 14.5: Misol 5 kabi); (4) ikkala token HttpOnly cookie (XSS himoya — 2.4): access (15 daqiqa — maxAge: 900), refresh (7 kun — maxAge: 604800, path: "/api/refresh" — refresh faqat yangilash endpoint'iga yuboriladi — kam ta'sir yuzasi). Yangilash (refresh): access tugaganda (15 daqiqadan keyin), refresh token bilan: (1) DB'dan refresh'ni topish (hash bo'yicha) + muddat tekshir; (2) rotation 2.3-bob — eski refresh token'ni o'chirish (delete) va yangi access + refresh berish (login) — bu refresh rotation: o'g'irlangan refresh token faqat bir marta ishlaydi (agar hujumchi va foydalanuvchi ikkalasi ishlatsa — biri eski (bekor) bilan urinadi — aniqlanadi). Logout (logout): refresh token'ni DB'dan o'chirish (bekor — endi yangi access olib bo'lmaydi). Demak: qisqa access (o'g'irlansa 15 daqiqa xavf), uzun refresh (qulay — qayta login yo'q), HttpOnly (XSS himoya), DB'da refresh (bekor qilish — logout, xavf), rotation (o'g'irlangan refresh bir marta). Bu — JWT'ning muddatsizlik muammosini (13.9: 2.4) hal qiladi (access qisqa, refresh DB'da bekor qilinadi). Zamonaviy token auth'ning to'liq, xavfsiz naqshi. Murakkabroq (sessiyadan), lekin xavfsiz va miqyoslanadigan (stateless access + bekor qilinadigan refresh).
Misol 3 — Secret'ni env'dan (kodda emas — 2.5)
Maqsad: Secret'larni to'g'ri (env'dan, kodda emas) ishlatish va git'dan himoyalash. Bu eng keng secret xatosini oldini oladi.
// XAVFLI — secret kodda (git'ga ketadi — GitHub'da ochiq — 2.5):
const stripe = new Stripe("sk_live_51abc..."); // KODDA — git bot topadi!
const dbUrl = "postgresql://user:parol123@host/db";
// XAVFSIZ — env'dan (kodda faqat nom):
const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!);
const dbUrl = process.env.DATABASE_URL!;
// Env tekshir (ishga tushishda — yo'q bo'lsa darrov xato):
function requireEnv(name: string): string {
const value = process.env[name];
if (!value) throw new Error(`Environment variable ${name} kerak`);
return value;
}
const JWT_SECRET = requireEnv("JWT_SECRET");# .gitignore — .env HECH QACHON git'da:
.env
.env.local
.env*.local
# .env.example (git'da OK — namuna, qiymatSIZ):
STRIPE_SECRET_KEY=
DATABASE_URL=
JWT_SECRET=
# Agar secret git'ga ketgan bo'lsa — DARROV bekor qil (git tarixida qoladi!):
# 1. Yangi kalit yarat (provayder console)
# 2. Eski kalitni bekor qil (revoke)
# 3. (ixtiyoriy) git tarixini tozala (git-filter-repo) — lekin BEKOR asosiyBu nima qiladi: Bu — secret'larni to'g'ri ishlatish (eng keng secret xatosini oldini olish — 2.5). Xavfli kod: secret'ni (sk_live_..., DB parol) to'g'ridan kodga yozish — bu git'ga ketadi (commit), va GitHub'da (public yoki sizsa) ochiq — botlar git'ni skanerlab, secret'ni daqiqada topadi (to'lov kaliti bilan pul, DB bilan ma'lumot o'g'irlik). Xavfsiz kod: secret env'dan (process.env.STRIPE_SECRET_KEY — kodda faqat nom, qiymat env'da — 13.10: 2.3), requireEnv (ishga tushishda env borligini tekshir — yo'q bo'lsa darrov xato — production'da "undefined secret" muammosini oldini oladi). .gitignore: .env git'da hech qachon (.env, .env.local, .env*.local — barcha env fayllar) — secret git tarixiga tushmasligi uchun. .env.example (git'da OK) — namuna (qaysi env kerak — qiymatsiz — boshqa dasturchilar biladi qaysi secret kerak, lekin qiymatlar yo'q). Eng muhim eslatma: agar secret git'ga ketgan bo'lsa — darrov bekor qil (yangi kalit yarat, eskisini revoke) — chunki git tarixida qoladi (fayldan o'chirish yetarli emas — eski commit'da bor — git log bilan har kim ko'radi — git history'ni tozalash murakkab va to'liq emas) — yagona ishonchli yechim — kalitni bekor qilish (eski kalit ishlamaydi — sizsa ham zarar yo'q). Bu — eng keng, eng oson oldini olinadigan xavfsizlik xatosi (har kun GitHub'da minglab secret sizadi). Qoida: secret env'da, .env git'da yo'q, git'ga ketgan secret darrov bekor. Pre-commit hook (gitleaks — 15-QISM) secret commit'ni avtomatik to'sadi.
Misol 4 — API kalit himoyasi (server proxy — 2.6)
Maqsad: Tashqi API kalitni brauzerga chiqarmasdan ishlatish — server proxy orqali. Bu kalit sizishini oldini oladi.
// XAVFLI — API kalit brauzerda (Client Component'da — sizadi):
"use client";
async function getWeather() {
// NEXT_PUBLIC_ brauzerda har kim devtools'da ko'radi! (13.10: 2.3)
const res = await fetch(`https://api.weather.com/data?key=${process.env.NEXT_PUBLIC_WEATHER_KEY}`);
}
// XAVFSIZ — server proxy (kalit server'da qoladi):
// app/api/weather/route.ts — Route Handler (server):
export async function GET(request: Request) {
const city = new URL(request.url).searchParams.get("city");
// kalit SERVER'da (env — brauzerga YO'Q):
const res = await fetch(`https://api.weather.com/data?city=${city}&key=${process.env.WEATHER_KEY}`);
const data = await res.json();
return Response.json(data); // faqat NATIJA brauzerga (kalit emas)
}
// Client faqat o'z server'iga so'rov (kalitsiz):
// fetch("/api/weather?city=Toshkent") kalit ko'rinmaydiBu nima qiladi: Bu — API kalit himoyasi (server proxy — 2.6). Muammo: tashqi API (ob-havo, OpenAI, xarita) kalitini ishlatish kerak, lekin kalit secret (sizsa — boshqalar sizning hisobingizdan foydalanadi — pul, limit). Xavfli kod: kalitni Client Component'da (NEXT_PUBLIC_WEATHER_KEY) ishlatish — NEXT_PUBLIC_ brauzerga chiqadi (13.10: 2.3) — har kim brauzer devtools'da (Network tab — so'rov URL'ida kalit ko'rinadi) yoki manba kodda kalitni ko'radi va o'g'irlaydi (sizning hisobingizdan foydalanadi). Xavfsiz kod — server proxy: (1) Client to'g'ridan tashqi API'ga emas, balki o'z server'ingizga (/api/weather) so'rov yuboradi (kalitsiz — fetch("/api/weather?city=Toshkent")); (2) Route Handler (server — 13.6) tashqi API'ga so'rov yuboradi, va kalit server'da (process.env.WEATHER_KEY — NEXT_PUBLIC_ emas — brauzerga chiqmaydi — 13.10: 2.3); (3) server faqat natijani (ob-havo ma'lumoti) brauzerga qaytaradi (kalit emas). Demak kalit hech qachon brauzerga bormaydi (server'da qoladi) — sizish yo'q. Nega proxy: ko'p tashqi API kaliti secret (frontend'dan to'g'ridan ishlatib bo'lmaydi — sizadi) — server proxy orqali (frontend o'z server tashqi API) kalit yashirin qoladi. Bu eng keng naqsh (har secret API kaliti — server orqali). Faqat public kalitlar (Stripe pk_, Google Maps public — domen cheklash bilan) frontend'da OK 2.6-bob. Proxy qo'shimcha — server'da rate limit, kesh, validatsiya (frontend to'g'ridan tashqi API'ga ketsa — bular yo'q). Server proxy — API kalit himoyasining standart usuli (kalit server'da, frontend faqat o'z server'iga). Bu secret API kalitlarini frontend ilovada ishlatishning yagona xavfsiz yo'li.
Misol 5 — JWT vs sessiya tanlash (2.3, 13.9: 2.4)
Maqsad: JWT (token) va database sessiya orasida to'g'ri tanlash — har birining afzalligi/kamchiligi. Bu auth arxitektura qarori.
JWT (STATELESS) vs DATABASE SESSIYA — qachon qaysi:
┌──────────────────┬──────────────────────┬──────────────────────┐
│ │ JWT (token) │ Database sessiya │
├──────────────────┼──────────────────────┼──────────────────────┤
│ Tekshirish │ secret (DB'siz, tez) │ har so'rov DB │
│ Bekor qilish │ qiyin (muddatgacha) │ oson (DB'dan o'chir) │
│ Miqyos │ oson (stateless) │ DB yuki │
│ Mikroservis │ (har servis tekshir)│ markaziy sessiya DB │
│ Mobil/SPA │ (Bearer header) │ cookie kerak │
└──────────────────┴──────────────────────┴──────────────────────┘
QACHON JWT:
Mikroservislar (har servis o'zi tekshiradi — DB markaziy emas)
Mobil app / 3-tomon API (Bearer header)
Miqyos (stateless — DB yuki yo'q)
lekin: bekor qilish qiyin qisqa access + refresh 2.3-bob
QACHON SESSIYA:
Oddiy web ilova (server-rendered — Next.js)
Darrov bekor qilish kerak (bank, nozik — 13.9: 2.4)
Soddaroq (kam xato — Auth.js boshqaradi)
JWT — stateless, mikroservis/mobil; sessiya — oddiy web, darrov bekor
Ko'p web ilova — sessiya (Auth.js); API/mikroservis/mobil — JWT (access+refresh)Bu nima qiladi: Bu — JWT vs database sessiya tanlash (auth arxitektura qarori — 2.3, 13.9: 2.4). Ikki yondashuv, har birining o'rni: JWT (stateless — token o'zida ma'lumot, server DB'siz tekshiradi): afzalligi — tekshirish tez (secret bilan — DB so'rovsiz), miqyos oson (stateless — har server tekshira oladi), mikroservis (har servis o'zi tekshiradi — markaziy sessiya DB kerak emas), mobil/SPA (Bearer header); kamchiligi — bekor qilish qiyin (token muddat tugaguncha amal — 13.9: 2.4 — shuning uchun qisqa access + refresh — 2.3). Database sessiya (sessiya DB'da — server har so'rovda DB tekshiradi): afzalligi — bekor qilish oson (DB'dan o'chir — darrov), soddaroq (Auth.js boshqaradi — kam xato); kamchiligi — har so'rov DB yuki, miqyos uchun markaziy sessiya DB. Qachon JWT: mikroservislar (har servis mustaqil tekshiradi), mobil/3-tomon API (Bearer header — cookie yo'q), miqyos (stateless). Qachon sessiya: oddiy web ilova (Next.js server-rendered), darrov bekor qilish kerak (bank, nozik — 13.9: 2.4), soddaroq. Ikki nuqta: (1) JWT — stateless (mikroservis/mobil/miqyos), sessiya — oddiy web (darrov bekor, sodda); (2) ko'p web ilova — sessiya (Auth.js — 13.9), API/mikroservis/mobil — JWT (access+refresh — 2.3). Bu munozarali (ko'p odam "JWT har doim" deydi — xato — JWT bekor qilish muammosi bor). To'g'ri tanlov kontekstga bog'liq: oddiy web — sessiya (sodda, xavfsiz, Auth.js); API/mobil/mikroservis — JWT (stateless kerak). Ko'pincha ikkalasi (web — sessiya cookie, mobil API — JWT). Auth.js (13.9: 2.4) ikkalasini qo'llaydi (strategy: "jwt" yoki "database"). Bu qaror — auth arxitekturasining asosi (loyiha turiga qarab — bir to'g'ri javob yo'q). Tushunish — har birining afzalligi/kamchiligi (JWT — tez/miqyos, bekor qiyin; sessiya — bekor oson, DB yuki).
Misol 6 — Token bekor qilish: denylist va tokenVersion (2.9)
Maqsad: Stateless JWT'ni amalda bekor qilish — Redis denylist (bitta token) va tokenVersion (barcha token). Bu JWT'ning eng katta amaliy muammosini hal qiladi.
import jwt from "jsonwebtoken";
import { redis } from "@/lib/redis";
// 1. DENYLIST — bitta token'ni bekor qilish (logout, o'g'irlik shubhasi):
async function revokeToken(token: string) {
const payload = jwt.decode(token) as { jti: string; exp: number };
const ttl = payload.exp - Math.floor(Date.now() / 1000); // token qancha yashaydi
if (ttl > 0) await redis.set(`denylist:${payload.jti}`, "1", { EX: ttl });
// TTL = token exp muddat tugagach Redis'dan o'zi o'chadi (ro'yxat o'smaydi)
}
// 2. TEKSHIRISH — imzo + denylist + tokenVersion:
async function verifyAccess(token: string) {
const payload = jwt.verify(token, process.env.JWT_SECRET!, {
algorithms: ["HS256"], // 2.2 — algoritm qat'iy
}) as { sub: string; jti: string; ver: number };
// Denylist tekshir (bitta token bekor qilinganmi):
if (await redis.exists(`denylist:${payload.jti}`)) throw new Error("Token bekor");
// tokenVersion tekshir (BARCHA token bekormi — parol o'zgarsa/"hamma qurilma"):
const user = await db.user.findUnique({ where: { id: payload.sub } });
if (!user || user.tokenVersion !== payload.ver) throw new Error("Qayta kiring");
return payload;
}
// 3. HAMMA QURILMADAN CHIQISH — tokenVersion++ (barcha eski token bir zarbada bekor):
async function revokeAll(userId: string) {
await db.user.update({ where: { id: userId }, data: { tokenVersion: { increment: 1 } } });
}Bu nima qiladi: Bu — stateless JWT'ni amalda bekor qilishning ikki usuli 2.9-bob. JWT muammosi — imzolangan token muddati tugaguncha amal qiladi (DB'ga qaramaydi) — o'g'irlangan token'ni darrov to'xtatib bo'lmaydi. Denylist (revokeToken): token'ning jti'sini (noyob ID — 2.8) Redis'ga qo'yamiz, TTLni token exp'iga tenglashtiramiz (ttl — token yana qancha yashashi) — shunda token muddati tugagach Redis yozuvi o'zi o'chadi (ro'yxat cheksiz o'smaydi — bu muhim, aks holda Redis to'lib ketardi). Tekshirish (verifyAccess): (1) imzo va algoritm (algorithms: ["HS256"] — 2.2); (2) jti denylist'dami (bitta token bekor qilinganmi); (3) tokenVersion — payload'dagi ver foydalanuvchidagi joriy tokenVersionga tengmi (bu bitta DB o'qishni qo'shadi — toza stateless emas, lekin bekor qilish uchun zarur — 2.9). Hamma qurilmadan chiqish (revokeAll): tokenVersionni oshirish — barcha eski token'lardagi ver endi eskiradi, hammasi bir zarbada bekor bo'ladi (parol o'zgarganda yoki "hamma qurilmadan chiqish"da). Demak: denylist — aniq bitta token uchun (arzon, Redis); tokenVersion — foydalanuvchining hamma token'lari uchun (bitta DB maydoni). Bu "toza stateless"dan chekinish (Redis/DB o'qish qo'shiladi), lekin JWT bekor qilish muammosini hal qiladi. Agar tez-tez bekor qilish kerak bo'lsa (bank) — database sessiya (Misol 5) soddaroq bo'lishi mumkin. Amaliy tanlov: qisqa access (15 daqiqa) ko'p holda yetarli; nozik amallar uchun denylist + tokenVersion qo'shing.
Misol 7 — Kriptografik primitivlar: randomBytes, timingSafeEqual, AES-GCM (2.11)
Maqsad: Xom kripto amallarini to'g'ri primitiv bilan yozish — tasodifiy secret, timing-safe solishtirish, authenticated shifr. Bu nozik kripto xatolarini oldini oladi.
import crypto from "node:crypto";
// 1. XAVFSIZ TASODIFIY — token/secret/kod uchun (Math.random EMAS — 2.11):
function generateSecret(bytes = 32): string {
return crypto.randomBytes(bytes).toString("hex"); // CSPRNG — 256 bit entropiya
}
// Math.random().toString(36) — taxmin qilinadi (kriptografik emas!)
// 2. CONSTANT-TIME COMPARE — timing hujumini oldini (=== EMAS — 2.11):
function safeCompare(a: string, b: string): boolean {
const ba = Buffer.from(a), bb = Buffer.from(b);
if (ba.length !== bb.length) return false; // uzunlik oldindan tekshiriladi
return crypto.timingSafeEqual(ba, bb); // DOIM bir xil vaqt
}
// 3. AES-256-GCM — maxfiy ma'lumotni shifrlash (authenticated — 2.11):
function encrypt(plaintext: string, key: Buffer): string {
const iv = crypto.randomBytes(12); // har shifrlashda YANGI IV (takrorlanmasin)
const cipher = crypto.createCipheriv("aes-256-gcm", key, iv);
const enc = Buffer.concat([cipher.update(plaintext, "utf8"), cipher.final()]);
const tag = cipher.getAuthTag(); // butunlik tegi (o'zgartirish aniqlanadi)
return Buffer.concat([iv, tag, enc]).toString("base64"); // iv+tag+shifr
}
function decrypt(payload: string, key: Buffer): string {
const buf = Buffer.from(payload, "base64");
const iv = buf.subarray(0, 12), tag = buf.subarray(12, 28), enc = buf.subarray(28);
const decipher = crypto.createDecipheriv("aes-256-gcm", key, iv);
decipher.setAuthTag(tag); // tegni tekshiradi — mos kelmasa final() XATO beradi
return decipher.update(enc) + decipher.final("utf8");
}Bu nima qiladi: Bu — xavfsizlik kodida to'g'ri kripto primitivlarini ishlatish 2.11-bob. (1) generateSecret: crypto.randomBytes(32) — CSPRNG (kriptografik xavfsiz) — token, secret, parol tiklash kodi uchun; Math.random() hech qachon (u taxmin qilinadigan — hujumchi kelajakdagi qiymatlarni tiklashi mumkin). (2) safeCompare: crypto.timingSafeEqual — token/imzo/secret solishtirishda; === erta to'xtaydi (birinchi farqda) — bu vaqt farqi orqali hujumchi qiymatni bayt-bayt taxmin qiladi (timing hujumi); timingSafeEqual doimo bir xil vaqt sarflaydi (uzunlik tengligi oldin tekshiriladi, chunki timingSafeEqual teng uzunlik talab qiladi). (3) encrypt/decrypt (AES-256-GCM): authenticated encryption — shifrlaydi va butunlikni himoyalaydi; har shifrlashda yangi IV (randomBytes(12) — takrorlanmasligi shart — bir IV ikki marta ishlatilsa GCM buziladi); getAuthTag — butunlik tegi (dekodlashda setAuthTag bilan tekshiriladi — agar shifr matn o'zgartirilgan bo'lsa, final() xato beradi — buzilgan ma'lumot qabul qilinmaydi); natija iv + tag + shifr birga saqlanadi. Muhim — o'z shifr algoritmingizni yozmang (masalan XOR bilan), sinovdan o'tgan AES-GCMni ishlating; AES-ECBni ishlatmang (naqshni oshkor qiladi). Kalit (key) — 32 bayt (256 bit), env'da yoki KMS'da (envelope encryption — 2.11) saqlanadi, kodda emas 2.5-bob. Bu primitivlar JWT imzo 2.1-bob, parol hash 14.5-bob, webhook 2.13-bob, API kalit (Misol 8) — hammasining poydevori.
Misol 8 — API kalit generatsiyasi va webhook imzosini tekshirish (2.13)
Maqsad: O'z API'ngiz uchun xavfsiz kalit yaratish (hash saqlash) va tashqi webhook imzosini tekshirish. Bu token/secret primitivlarining amaliy qo'llanilishi.
import crypto from "node:crypto";
// 1. API KALIT GENERATSIYASI — prefix + tasodifiy; DB'da HASH 2.13-bob:
async function createApiKey(userId: string, scope: string[]) {
const raw = `sk_live_${crypto.randomBytes(24).toString("hex")}`; // prefix + CSPRNG
const keyHash = crypto.createHash("sha256").update(raw).digest("hex");
await db.apiKey.create({
data: { keyHash, userId, scope, prefix: raw.slice(0, 12) }, // HASH saqlanadi, asl EMAS
});
return raw; // asl kalit FAQAT SHU YERDA (bir marta) ko'rsatiladi — keyin faqat hash
}
// Kelgan kalitni tekshirish (hash + timing-safe):
async function verifyApiKey(raw: string) {
const keyHash = crypto.createHash("sha256").update(raw).digest("hex");
const record = await db.apiKey.findUnique({ where: { keyHash } });
return record ?? null; // topilsa — kalit haqiqiy (scope bilan)
}
// 2. WEBHOOK IMZOSINI TEKSHIRISH — Stripe/GitHub uslubi (2.13, 8.20):
function verifyWebhook(rawBody: Buffer, signature: string, secret: string): boolean {
// RAW body ustidan HMAC (JSON.parse'dan OLDIN — bayt-ba-bayt):
const expected = crypto.createHmac("sha256", secret).update(rawBody).digest("hex");
const a = Buffer.from(signature), b = Buffer.from(expected);
// Constant-time solishtirish (2.11 — timing hujumini oldini):
return a.length === b.length && crypto.timingSafeEqual(a, b);
}Bu nima qiladi: Bu — token/secret primitivlarining ikki amaliy qo'llanishi 2.13-bob. (1) API kalit generatsiyasi (createApiKey): sk_live_ prefiksi (tur/muhitni bildiradi, skanerlar tanidi — 2.5) + crypto.randomBytes(24) (CSPRNG — 2.11); kalit DB'da hash holda saqlanadi (sha256 — 2.13), asl kalit foydalanuvchiga faqat bir marta (yaratishda) qaytariladi — keyin faqat hash qoladi, xuddi parol kabi 14.5-bob — shunda DB sizsa ham asl kalitlar himoyalangan (hash'dan tiklab bo'lmaydi); scope — kalit nimaga ruxsat berishi (least privilege — 14.1). Tekshirish (verifyApiKey): kelgan kalitni hash qilib, DB'dan hash bo'yicha topamiz (hash — deterministik, bir xil kalit bir xil hash). (2) Webhook imzosini tekshirish (verifyWebhook): tashqi xizmat (Stripe, GitHub) so'rovi haqiqiyligini tekshirish 8.20-bob; provayder raw body'ni shared secret bilan HMAC qilgan va header'ga qo'ygan; biz o'sha secret bilan raw body ustidan (JSON.parse'dan oldin — bayt-ba-bayt, chunki qayta serializatsiya baytlarni buzishi mumkin) HMAC hisoblab, timingSafeEqual bilan solishtiramiz (2.11 — === emas — timing hujumi); mos kelsa so'rov haqiqiy. Ikkalasi ham bir xil primitivlarga tayanadi: HMAC/hash (bir tomonlama — 2.10), CSPRNG 2.11-bob, timing-safe compare 2.11-bob. Bu bob boshidagi JWT imzosi 2.1-bob va parol hash 14.5-bob bilan bir oila — token/secret xavfsizligi butun ilova bo'ylab shu asosiy kripto primitivlarga quriladi. Diqqat: webhook uchun Next.js'da raw body'ni olish kerak (req.text() yoki maxsus sozlama — framework body'ni avtomatik parse qilmasin).
5. To'g'ri va noto'g'ri holatlar
1) JWT secret
zaif ("secret") yoki kodda (Misol 1, 3)
kuchli (randomBytes 32) + env (2.2, 2.5)2) JWT algoritm
verify(token, secret) (alg=none zaif — 2.2)
algorithms: ["HS256"] (qat'iy — Misol 1)3) Token saqlash
localStorage (XSS o'g'irlaydi — 2.4)
HttpOnly cookie (XSS himoya)4) Secret
kodda/git'da (GitHub sizish — Misol 3)
env/vault (.gitignore)5) API kalit (frontend)
NEXT_PUBLIC_ secret kalit (brauzer ko'radi — Misol 4)
server proxy (kalit server'da)6) Token muddati
muddatsiz (o'g'irlansa cheksiz — 2.3)
qisqa access + refresh (rotation)7) Tasodifiylik (token/secret)
Math.random() (taxmin qilinadi — 2.11)
crypto.randomBytes(32) (CSPRNG)8) Solishtirish (token/imzo)
token === saqlangan (timing hujumi — 2.11)
crypto.timingSafeEqual (constant-time)9) Yashirish usuli
base64 "yashirdim" (kodlash — himoya EMAS — 2.10)
shifr (AES-GCM) yoki hash (bcrypt) — maqsadga qarab10) API kalit saqlash (o'z API)
kalitni ochiq (plaintext) DB'da (2.13)
hash (SHA-256) DB'da, asl bir marta ko'rsat (Misol 8)11) Algoritm tanlash
ko'p tekshiruvchiga HS256 (secret hammada — 2.7)
RS256/ES256 (private imzo, public tekshir — JWKS)6. Keng tarqalgan xatolar va yechimlari
Xato 1 — Zaif JWT secret
Sababi: taxmin qilinadigan secret 2.2-bob. Yechimi: randomBytes(32) + env (Misol 1).
Xato 2 — alg=none / algoritm chalkashligi
Sababi: algoritm belgilanmagan 2.2-bob. Yechimi: algorithms: ["HS256"] (Misol 1).
Xato 3 — Maxfiy ma'lumot JWT payload'da
Sababi: payload ochiq 2.1-bob. Yechimi: faqat ID/rol (Misol 1).
Xato 4 — Token localStorage'da (XSS)
Sababi: JS o'qiydi 2.4-bob. Yechimi: HttpOnly cookie.
Xato 5 — Secret git'ga ketgan
Sababi: kodda secret 2.5-bob. Yechimi: darrov bekor + rotation (git tarixida qoladi — Misol 3).
Xato 6 — API kalit frontend'da
Sababi: NEXT_PUBLIC_ secret 2.6-bob. Yechimi: server proxy (Misol 4).
Xato 7 — Token'ni bekor qilib bo'lmaydi
Sababi: stateless JWT muddati tugaguncha amal 2.9-bob. Yechimi: qisqa exp + denylist/tokenVersion (Misol 6) yoki database sessiya (Misol 5).
Xato 8 — Math.random() bilan token/secret
Sababi: kriptografik bo'lmagan tasodif — taxmin qilinadi 2.11-bob. Yechimi: crypto.randomBytes (Misol 7).
Xato 9 — Timing hujumi (=== bilan solishtirish)
Sababi: erta to'xtaydigan solishtirish sirni oshkor qiladi 2.11-bob. Yechimi: timingSafeEqual (Misol 7, 8).
Xato 10 — base64'ni "shifr" deb o'ylash
Sababi: kodlash bilan shifrlashni aralashtirish 2.10-bob. Yechimi: maxfiylik uchun AES-GCM, format uchun base64.
Xato 11 — Algoritm chalkashligi (RS256HS256)
Sababi: algoritmni token'dan olish + asimmetrik/simmetrik aralashtirish 2.7-bob. Yechimi: algoritmni qat'iy belgila (Misol 1), asimmetrikda public key'ni HMAC secret sifatida ishlatib bo'lmasin.
Xato 12 — Webhook'ni tekshirmaslik
Sababi: kelgan webhook'ni imzosiz qabul qilish (soxta so'rov — 2.13). Yechimi: HMAC imzoni raw body ustidan timingSafeEqual bilan tekshir (Misol 8).
7. Integratsiya — bu mavzu stack'ning qayerida uchraydi
- Auth (13.9, 5.15-16): JWT/sessiya strategiyasi, access/refresh.
- XSS 14.2-bob: token saqlash (HttpOnly — XSS himoya).
- CSRF 14.4-bob: cookie token (SameSite).
- Deploy 13.10-bob: secret env, NEXT_PUBLIC_ (server/public).
- OWASP 14.1-bob: A02 (crypto — secret), A07 (auth).
- Mikroservis (9-QISM): JWT (stateless — har servis tekshir); RS256/ES256 + JWKS (2.7, 2.8).
- DevOps (10-QISM): vault, secret rotation; envelope encryption/KMS 2.11-bob; gitleaks 2.5-bob.
- HTTPS/TLS 14.7-bob: in-transit shifr, Secure cookie, sertifikat 2.12-bob.
- Parol 14.5-bob: hash (bcrypt/argon2) vs shifr farqi 2.10-bob; API kalit hash 2.13-bob.
- Webhook/integratsiya 8.20-bob: HMAC imzo tekshiruvi (2.13, Misol 8).
- OAuth/OIDC 13.9-bob: access/id/refresh token, JWKS, scope 2.12-bob.
- Secrets 10.11-bob: vault/Secrets Manager, env, rotatsiya — bu bob xavfsizlik burchagidan 2.5-bob.
8. Eng yaxshi amaliyotlar (best practices)
- Kuchli JWT secret (randomBytes 32, env — Misol 1).
- Algoritm qat'iy (alg=none oldini — Misol 1).
- Maxfiy ma'lumot payload'da yo'q (ochiq — 2.1).
- Qisqa access + refresh (rotation — Misol 2).
- HttpOnly cookie (XSS himoya — 2.4).
- Secret env/vault (kodda/git'da emas — Misol 3).
- Git secret darrov bekor (tarixda qoladi — Misol 3).
- API kalit server proxy (frontend'da emas — Misol 4).
- Least privilege + rotation (API kalit — 2.6).
- JWT/sessiya — kontekstga (Misol 5).
- Algoritm to'g'ri (monolit — HS256; ko'p tekshiruvchi — RS256/ES256 + JWKS — 2.7, 2.8).
- Claim'larni to'liq tekshir (imzodan tashqari iss/aud/exp/nbf — 2.8).
- Bekor qilishni rejalashtir (qisqa exp + denylist/tokenVersion — Misol 6).
- CSPRNG (token/secret — crypto.randomBytes, Math.random emas — 2.11).
- Constant-time compare (token/imzo — timingSafeEqual — 2.11).
- Shifrlashda AES-GCM (authenticated, yangi IV — 2.11); at-rest + in-transit.
- Hash ≠ shifr ≠ kodlash (maqsadga qarab to'g'ri primitiv — 2.10).
- API kalit — hash saqla (asl bir marta; prefix + scope — Misol 8).
- Webhook imzosini tekshir (HMAC + raw body + timing-safe — Misol 8).
9. Amaliy loyiha: "Xavfsiz Token va Secrets"
Token va secrets xavfsizligini mustahkamlash.
Maqsad
Auth + secrets tizimi — xavfsiz JWT, access/refresh, HttpOnly saqlash, secrets env/proxy.
Talablar (requirements)
- JWT xavfsiz: kuchli secret + algoritm qat'iy + muddat (Misol 1).
- Maxfiy ma'lumot yo'q: payload faqat ID/rol 2.1-bob.
- Access + refresh: qisqa access + refresh rotation (Misol 2).
- HttpOnly saqlash: token cookie (XSS himoya — Misol 2).
- Secret env: kodda/git'da emas (Misol 3).
- .gitignore: .env (Misol 3).
- API kalit proxy: tashqi API server orqali (Misol 4).
- JWT/sessiya: to'g'ri tanlov (Misol 5).
- Test: alg=none, zaif secret, localStorage sinab ko'r.
- Audit: secret kodda/git'da yo'qmi (gitleaks).
- Bekor qilish: denylist yoki tokenVersion bilan token bekor qilish (Misol 6).
- Kripto primitivlar: secret — crypto.randomBytes, solishtirish — timingSafeEqual (Misol 7).
- Shifrlash: nozik maydonni AES-GCM bilan shifrlash (at-rest — Misol 7).
- O'z API kaliti: generatsiya + hash saqlash + scope (Misol 8).
- Webhook: kelgan webhook imzosini HMAC bilan tekshirish (Misol 8).
Maslahatlar (hint)
- Algoritm qat'iy (Xato 2).
- HttpOnly (Xato 4).
- Secret env (Xato 5).
- API proxy (Xato 6).
- crypto.randomBytes / timingSafeEqual (Xato 8, 9).
- API kalit hash saqla (Xato 10 — 2.13).
"Tayyor" mezonlari (acceptance criteria)
- Xavfsiz JWT (secret/algoritm/muddat).
- Access + refresh (rotation).
- HttpOnly saqlash.
- Secret env (git'da yo'q).
- API kalit proxy.
- JWT/sessiya oqlangan.
- Token bekor qilish (denylist/tokenVersion).
- Kripto primitivlar to'g'ri (CSPRNG, timing-safe, AES-GCM).
- O'z API kaliti hash saqlanadi.
- Webhook imzosi tekshiriladi.
Yechim kodi ataylab berilmagan — bu loyihani o'zingiz yozib ko'ring.
10. Xulosa va keyingi bobga ko'prik
Bu bobda token va secrets xavfsizligini chuqur o'rgandik:
- JWT tuzilishi 2.1-bob; JWT xatolari 2.2-bob; access/refresh 2.3-bob; token saqlash 2.4-bob; secrets boshqaruvi 2.5-bob; API kalit/rotation 2.6-bob.
- Imzo algoritmlari (HS256 vs RS256/ES256 — 2.7); standart claim'lar va JWK/kid 2.8-bob; token bekor qilish va JWE 2.9-bob.
- Hash/shifr/kodlash farqi 2.10-bob; kripto primitivlar (CSPRNG, timing-safe, AES-GCM, envelope — 2.11); TLS/OAuth/entropiya 2.12-bob; API kalit generatsiyasi va webhook imzosi 2.13-bob.
Endi siz token'ni (JWT — kuchli secret, to'g'ri algoritm, to'liq claim validatsiyasi, access/refresh, HttpOnly, bekor qilish) va secrets'ni (env/vault, proxy, rotatsiya, to'g'ri kripto primitivlar) xavfsiz boshqarasiz. Bu — zamonaviy auth va maxfiy ma'lumot himoyasi: imzo (soxtalashtirishni to'sadi), shifrlash (maxfiylik — at-rest/in-transit), hash (bir tomonlama — parol/kalit), va to'g'ri primitivlar (CSPRNG, timing-safe) — hammasi bir necha asosiy kripto qurilish bloklariga tayanadi.
Keyingi bob — 14.7-bob: HTTPS, CORS va xavfsizlik header'lari. Token/secrets'ni bildik; endi transport va sozlash xavfsizligini ko'ramiz: HTTPS/TLS (shifrlangan ulanish — nega va qanday), CORS (cross-origin — to'g'ri sozlash), xavfsizlik header'lari (helmet, CSP, HSTS, X-Frame), va xavfsiz sozlash (A05). Bu — ilovaning tashqi himoya qatlami.
Foydalanilgan rasmiy/ishonchli manbalar
- OWASP — "JSON Web Token for Java/Node Cheat Sheet", "Secrets Management Cheat Sheet", "Cryptographic Storage Cheat Sheet"
- OWASP — Top 10: A02 (Cryptographic Failures), A07 (Identification and Authentication Failures)
- RFC 7519 (JWT), RFC 7515 (JWS), RFC 7516 (JWE), RFC 7517 (JWK), RFC 7518 (JWA) — JOSE oilasi
- IETF — RFC 6749 (OAuth 2.0), RFC 8725 (JWT Best Current Practices), OpenID Connect Core (OIDC)
- Node.js —
cryptomoduli hujjatlari (randomBytes,timingSafeEqual,createCipheriv— AES-GCM,createHmac) - NIST — SP 800-57 (Key Management), SP 800-38D (AES-GCM), FIPS 186 (ECDSA)
- HashiCorp Vault, AWS Secrets Manager / AWS KMS (envelope encryption), Doppler — secrets/kalit boshqaruvi hujjatlari
- gitleaks / git-secrets — repo secret skanerlash; pre-commit hook
- Auth.js (authjs.dev) — session strategiyalari (JWT vs database); jose kutubxonasi hujjatlari
Izohlar (0)
Izoh yozish uchun kiring.
- Hozircha izoh yo'q. Birinchi bo'ling!