Mundarija (28)
- Bu darsda
- 1. Nega bu kerak?
- 2. Tasodif: Math.random va crypto
- 2.1 Math.random nega xavfli
- 2.2 Kriptografik tasodif
- 2.3 Brauzerda ham bor
- 3. Hash: ma'lumotning barmoq izi
- 3.1 SHA-256
- 3.2 Format: hex, base64, base64url
- 3.3 Brauzerda: crypto.subtle.digest
- 4. HMAC: kalit bilan imzo
- 4.1 Nega oddiy hash yetmaydi
- 4.2 Telegram Mini App: haqiqiy misol
- 4.3 timingSafeEqual: vaqt hujumi
- 5. Hujumchi nigohi
- 6. CLI qadami: kesh kaliti va holat 20 commit'i
- 6.1 kalit.ts
- 6.2 Topilma: yetim kesh fayli
- 6.3 Holat 20 tayyor
- 7. Ko'p uchraydigan xatolar
- 8. Mashqlar
- 1-mashq (oson): to'g'ri tanlov
- 2-mashq (o'rta): fayl butunligi
- 3-mashq (qiyin): imzoli havola
- 4-mashq: CLI qadami
- 9. Real ishda
- Xulosa
- Manbalar
Node.js crypto: xavfsiz tasodif, SHA-256 hash va HMAC
Qisqacha: Token, parol tiklash kodi, sessiya ID — faqat kriptografik tasodif bilan:
crypto.randomBytes,crypto.randomUUID,crypto.randomInt.Math.randomtaxmin qilinadigan ketma-ketlik beradi — xavfsizlik uchun yaramaydi. Hash (SHA-256) — istalgan ma'lumotdan 32 baytlik "barmoq izi": bir xil kirish — bir xil hash, bitta harf farqi — butunlay boshqa hash, orqaga qaytarib bo'lmaydi. HMAC — hash + maxfiy kalit: "bu xabarni kalit egasi yuborgan va u o'zgarmagan" degan imzo. Imzolarni solishtirish — faqattimingSafeEqualbilan.
Bu darsda
Math.randomnega xavfli ekanini tushuntirib, to'g'ri tasodif funksiyasini tanlay olasiz.- SHA-256 hash'ni Node (
createHash) va brauzerda (crypto.subtle) hisoblaysiz; hex, base64, base64url farqini bilasiz. - HMAC bilan xabar imzolaysiz va imzoni vaqt hujumidan himoyalangan holda tekshirasiz.
valyutakeshiga URL hash'idan kalit berasiz va holat 20 ni commit qilasiz.
Oldin bilishingiz kerak: util moduli, Xavfsiz fayl operatsiyalari, Math obyekti, Route Handlers.
1. Nega bu kerak?
valyuta keshida hozir bitta fayl bor — kurslar.json. O'tgan darsda esa --sana bayrog'i qo'shildi. Endi valyuta kurs USD --sana 2026-10-01 va valyuta kurs USD turli javob beradi. Ikkalasi bitta faylga yozilsa, bugungi so'rov 1-oktyabr kursini ko'rsatib yuboradi. Har so'rovga o'z fayli kerak.
Fayl nomini so'rov URL'idan yasash mumkin, lekin URL'da :, /, ? bor — fayl nomida ular taqiqlangan. URL'ni qisqa, xavfsiz, har safar bir xil nomga aylantiradigan narsa kerak. Bu — hash.
Ikkinchi mavzu — tasodif. Atomik yozish vaqtinchalik fayl nomi uchun randomBytes ishlatdi. Math obyekti darsida esa "xavfsiz tasodif uchun crypto bor" degan edik. Bugun nega ekanini ko'ramiz. Ertaga siz server yozasiz va u parol tiklash havolalari, sessiyalar, API kalitlarini yaratadi. Ular taxmin qilinsa — hisob o'g'irlanadi.
O'xshatish: muhr va barmoq izi. Hash — barmoq izi: odamni (ma'lumotni) aniq tanitadi, lekin izdan odamni "qaytarib yasab" bo'lmaydi. HMAC — notarius muhri: faqat muhr egasi bosa oladi, va hujjatning bitta harfi o'zgarsa, muhr mos kelmay qoladi.
2. Tasodif: Math.random va crypto
2.1 Math.random nega xavfli
Math.random — psevdotasodif (pseudo-random) generator. U kichik ichki holatdan matematik formula bilan keyingi sonni hisoblaydi. V8 bunda xorshift128+ algoritmini ishlatadi (V8 blogi, 2015). Ichki holat bor-yo'g'i 128 bit. Tadqiqotchilar bir nechta ketma-ket chiqishdan holatni tiklab, keyingi sonlarni oldindan aytish mumkinligini ko'rsatgan.
Ya'ni Math.random().toString(36).slice(2) bilan parol tiklash kodi yasasangiz, hujumchi o'zi uchun bir nechta kod so'rab, sizning kodingizni hisoblab chiqishi mumkin. Shuning uchun qoida:
| Vazifa | Nima ishlatiladi |
|---|---|
| O'yin, animatsiya, test ma'lumoti, aralashtirish | Math.random — yetarli |
| Token, sessiya ID, parol tiklash kodi, kalit, tuz (salt) | crypto — majburiy |
2.2 Kriptografik tasodif
CSPRNG (cryptographically secure pseudo-random number generator) — OS'ning xavfsiz tasodif manbai ustida ishlaydigan generator. Uning chiqishidan keyingisini taxmin qilib bo'lmaydi. Node'da uchta asosiy funksiya:
import { randomBytes, randomInt, randomUUID } from "node:crypto";
const token = randomBytes(32).toString("base64url");
console.log(token.length);
console.log(randomUUID().length);
const kod = randomInt(100000, 1000000); // 6 xonali SMS kod
console.log(kod >= 100000 && kod < 1000000);
console.log(/^[0-9a-f-]{36}$/.test(randomUUID()));Konsolda:
43
36
true
trueNatija qiymatlari har safar boshqa — shuning uchun faqat ularning shaklini chiqardik.
| Funksiya | Nima qaytaradi | Qachon |
|---|---|---|
randomBytes(n) |
n tasodifiy bayt (Buffer) |
Token, kalit, tuz |
randomUUID() |
"3f2a…-…" — 36 belgilik UUID v4 |
Yozuv ID'si |
randomInt(min, max) |
min ≤ son < max |
SMS/email kod, tasodifiy tanlov |
32 bayt = 256 bit tasodif: sessiya tokeni uchun odatiy hajm. base64url dan keyin 43 belgi chiqadi.
randomInt ni o'zingiz randomBytes dan yasamang. bayt % 1000000 kabi kod noteng taqsimot beradi — ba'zi sonlar boshqalaridan tez-tez chiqadi (modulo bias). randomInt buni to'g'ri hal qiladi.
2.3 Brauzerda ham bor
Web Crypto — brauzer va Node'da umumiy standart. Bu blok saytda ham ishlaydi:
const id = crypto.randomUUID();
const baytlar = crypto.getRandomValues(new Uint8Array(16));
console.log(id.length, id[14]);
console.log(baytlar.length);Konsolda:
36 4
16id[14] — doim 4: UUID'ning shu joyi versiyani bildiradi (v4 — "tasodifiy UUID"). getRandomValues Math obyekti darsida va'da qilingan brauzer usuli; Node 24 da u global crypto da ham bor.
Tekshirib ko'ring: Telegram bot foydalanuvchiga 6 xonali tasdiq kodi yuboradi. Dasturchi
Math.floor(Math.random() * 900000) + 100000yozdi. Bu qayerda xato?
Javob
Kod xavfsizlik uchun ishlatiladi (hisobni tasdiqlash), lekin Math.random taxmin qilinadigan. To'g'risi — crypto.randomInt(100000, 1000000). Qo'shimcha himoya: urinishlar sonini cheklash va kod muddatini qisqa qilish — 6 xonali kodni million marta sinab ko'rish kerak, cheklovsiz esa bu mumkin.
3. Hash: ma'lumotning barmoq izi
3.1 SHA-256
Hash funksiya — istalgan uzunlikdagi ma'lumotni belgilangan uzunlikdagi qisqa qiymatga aylantiradi. Kriptografik hash'ning uch xususiyati bor:
- Deterministik — bir xil kirish, har doim bir xil natija.
- Ko'chki effekti (avalanche) — bitta harf farqi, butunlay boshqa natija.
- Bir tomonlama — hash'dan asl ma'lumotni topib bo'lmaydi; bir xil hash beradigan ikkinchi kirishni topish ham amalda imkonsiz.
Node'da createHash:
import { createHash } from "node:crypto";
const sha256 = (matn) =>
createHash("sha256").update(matn).digest("hex");
console.log(sha256("USD"));
console.log(sha256("USE"));
console.log(sha256("USD") === sha256("USD"));Konsolda:
a26cdf3a6e709124385d4d7eb9bff6b897a58ed5597fbab779b89849dbe81b21
b3c2ed23b44e753d6bfc54b1d48ff7d0e4959624ecf1ceb1d0942bac08548634
trueUSD va USE — bitta harf farq. Hash'lari esa umuman o'xshamaydi. Uchala xususiyat ham ko'rindi.
Zanjir: createHash(algoritm) → update(ma'lumot) (bir necha marta chaqirish mumkin — katta faylni bo'laklab) → digest(format). digest dan keyin obyektni qayta ishlatib bo'lmaydi.
| Algoritm | Hajm | Holat |
|---|---|---|
sha256 |
32 bayt | Standart tanlov |
sha512 |
64 bayt | Kuchliroq, 64-bit protsessorda tez |
sha1 |
20 bayt | Buzilgan (2017, SHAttered) — faqat eski tizimlar bilan moslik uchun |
md5 |
16 bayt | Buzilgan — xavfsizlik uchun emas, faqat checksum |
Diqqat: Parolni SHA-256 bilan saqlamang. SHA-256 juda tez — videokarta sekundiga milliardlab parolni sinab ko'radi. Parol uchun ataylab sekin funksiyalar kerak (scrypt, argon2) — ular keyingi darsda.
3.2 Format: hex, base64, base64url
Hash — 32 bayt. Matnga aylantirishning uch usuli:
import { createHash } from "node:crypto";
const h = createHash("sha256").update("abc").digest();
console.log(h.length);
console.log(h.toString("hex"));
console.log(h.toString("base64"));
console.log(h.toString("base64url"));Konsolda:
32
ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad
ungWv48Bz+pBQUDeXa4iI7ADYaOWF3qctBD/YfIAFa0=
ungWv48Bz-pBQUDeXa4iI7ADYaOWF3qctBD_YfIAFa0| Format | Uzunlik (32 bayt) | Xususiyati |
|---|---|---|
hex |
64 | Faqat 0-9a-f, o'qish va solishtirish oson |
base64 |
44 | Qisqaroq, lekin +, /, = bor |
base64url |
43 | + → -, / → _, = yo'q — URL va fayl nomida xavfsiz |
ba7816bf… — "abc" ning SHA-256 hash'i standartdagi (FIPS 180) rasmiy test qiymati. Har qanday to'g'ri SHA-256 aynan shuni beradi — o'z kodingizni tekshirish uchun qulay. Tokenlar odatda base64url da (JWT ham shunday), fayl nomlari va loglarda — hex.
3.3 Brauzerda: crypto.subtle.digest
Web Crypto'da hash — asinxron va ArrayBuffer qaytaradi. Bu blok saytda ham ishlaydi:
async function sha256Hex(matn) {
const baytlar = new TextEncoder().encode(matn);
const hash = await crypto.subtle.digest("SHA-256", baytlar);
return [...new Uint8Array(hash)]
.map((b) => b.toString(16).padStart(2, "0"))
.join("");
}
console.log(await sha256Hex("abc"));Konsolda:
ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015adNatija createHash bilan bir xil — algoritm bitta. Node'ga xos kodni yozganda createHash qulayroq (sinxron, to'g'ridan hex). Brauzer va Node'da bir xil ishlashi kerak bo'lgan kod uchun — crypto.subtle.
Tekshirib ko'ring: Ikki odamning parol hash'i bir xil chiqdi. Bu nimani anglatadi?
Javob
Deyarli aniq — ikkalasining paroli bir xil. Hash deterministik. Bu ham parolni oddiy hash bilan saqlash xavfining bir sababi: bir xil parollar ko'rinib qoladi. Shuning uchun parolga har foydalanuvchi uchun alohida tasodifiy tuz (salt) qo'shiladi — keyingi darsda.
4. HMAC: kalit bilan imzo
4.1 Nega oddiy hash yetmaydi
Server mijozga "100 USD" degan xabar va uning SHA-256 hash'ini yubordi. Yo'lda hujumchi xabarni "900 USD" ga o'zgartirdi. Hash'ni ham o'zi qayta hisoblab qo'ya oladi — SHA-256 hamma uchun ochiq. Oddiy hash tasodifiy buzilishni ushlaydi, ataylab o'zgartirishni emas.
HMAC (hash-based message authentication code) — hash'ga maxfiy kalit qo'shadi. Kalitni bilmagan odam to'g'ri HMAC yasay olmaydi. Siz HMAC'ni Telegram Mini App va webhook imzosi darslarida ishlatgansiz — bugun uni ichidan ko'ramiz.
import { createHmac } from "node:crypto";
const KALIT = "sir-kalit"; // haqiqatda: env'dan, randomBytes(32)
const imzola = (xabar) =>
createHmac("sha256", KALIT).update(xabar).digest("hex");
const imzo = imzola("100 USD");
console.log(imzo);
console.log(imzola("100 USD") === imzo);
console.log(imzola("900 USD") === imzo);Konsolda:
6ad434ff681b68f111beca0c20aea87d7bfade98544859ffe661d244625971ec
true
falseQabul qiluvchi xabarni o'zi imzolaydi va kelgan imzo bilan solishtiradi. Mos kelsa — xabar kalit egasidan va o'zgarmagan. HMAC shifrlash emas: "100 USD" matni ochiq qoladi, faqat uning haqiqiyligi tasdiqlanadi.
Ikki tomon nima qilishini rasmda ko'ring. Kalit faqat ikkala tomonda, yo'lda faqat xabar va imzo:
sequenceDiagram
participant Y as Yuboruvchi (kalit bor)
participant H as Yo'l (hujumchi ko'radi)
participant Q as Qabul qiluvchi (kalit bor)
Y->>Y: imzo = HMAC(kalit, xabar)
Y->>H: xabar + imzo
H->>Q: xabar + imzo
Q->>Q: HMAC(kalit, xabar) ni qayta hisoblash
Q->>Q: timingSafeEqual: teng — qabul, yo'q — rad4.2 Telegram Mini App: haqiqiy misol
Telegram Mini Apps darsida initData ni serverda tekshirish kerakligini aytgan edik. Telegram hujjatidagi qoida: kalit = HMAC-SHA256("WebAppData", bot tokeni), imzo = HMAC-SHA256(kalit, maydonlar alifbo tartibida, \n bilan). Soxta token bilan:
import { createHmac } from "node:crypto";
const BOT_TOKEN = "123456:SOXTA-TOKEN"; // haqiqiysi — env'da
const maydonlar = { auth_date: "1761195600", user: '{"id":42}' };
const satr = Object.keys(maydonlar)
.sort()
.map((k) => `${k}=${maydonlar[k]}`)
.join("\n");
const kalit = createHmac("sha256", "WebAppData")
.update(BOT_TOKEN)
.digest();
const hash = createHmac("sha256", kalit).update(satr).digest("hex");
console.log(JSON.stringify(satr));
console.log(hash.length);Konsolda:
"auth_date=1761195600\nuser={\"id\":42}"
64Mijoz initData da hash yuboradi, server shu hisobni qilib solishtiradi. Bot tokeni faqat serverda — brauzer uni hech qachon ko'rmaydi, demak imzoni soxtalashtira olmaydi. auth_date ni ham tekshirish kerak (masalan 24 soatdan eski — rad), aks holda eski initData qayta ishlatiladi.
4.3 timingSafeEqual: vaqt hujumi
Imzoni === bilan solishtirish xavfli. === satrlarni chapdan o'ngga solishtiradi va birinchi farqda to'xtaydi. Birinchi belgisi noto'g'ri imzo — bir zumda rad; o'nta belgisi to'g'ri — biroz kechroq. Hujumchi javob vaqtini juda ko'p marta o'lchab, imzoni belgima-belgi topishi mumkin. Bu — vaqt hujumi (timing attack).
timingSafeEqual har doim hamma baytni solishtiradi — vaqt farq qilmaydi:
import { createHmac, timingSafeEqual } from "node:crypto";
const KALIT = "sir-kalit";
function imzoTogrimi(xabar, kelganHex) {
const kutilgan = createHmac("sha256", KALIT).update(xabar).digest();
const kelgan = Buffer.from(kelganHex, "hex");
if (kelgan.length !== kutilgan.length) return false;
return timingSafeEqual(kelgan, kutilgan);
}
const imzo = createHmac("sha256", KALIT)
.update("100 USD")
.digest("hex");
console.log(imzoTogrimi("100 USD", imzo));
console.log(imzoTogrimi("900 USD", imzo));
console.log(imzoTogrimi("100 USD", "abc"));Konsolda:
true
false
falseUzunlik tekshiruvi shart. Usiz timingSafeEqual xato tashlaydi — kanon tajribasi va revalidatsiya darsida ko'rgan xatoingiz:
ERR_CRYPTO_TIMING_SAFE_EQUAL_LENGTH Input buffers must have the same byte length"Kirish buferlari bir xil bayt uzunligida bo'lishi kerak". Uzunlik sir emas (HMAC-SHA256 doim 32 bayt), shuning uchun uni oddiy !== bilan tekshirish xavfsiz.
Tekshirib ko'ring: Nega
imzoTogrimikelgan imzoni hex'dan Buffer'ga aylantiradi,kutilganni esa hex satrga aylantirmaydi?
Javob
timingSafeEqual satr emas, Buffer (yoki TypedArray) qabul qiladi. Ikkalasini bir xil ko'rinishga keltirish kerak edi — baytlarga keltirish tabiiyroq, chunki digest() formatsiz chaqirilsa, Buffer beradi. Noto'g'ri hex ("abc") Buffer.from da 1 baytga aylanadi — uzunlik tekshiruvida rad etiladi.
5. Hujumchi nigohi
| Hujum | Zaif kod | Himoya |
|---|---|---|
| Tokenni taxmin qilish | Math.random() bilan token |
randomBytes(32) |
| SMS kodni sinab chiqish | 6 xona, cheklovsiz urinish | randomInt + urinish chegarasi + qisqa muddat |
| Xabarni o'zgartirish | Oddiy hash bilan "imzo" | HMAC maxfiy kalit bilan |
| Imzoni vaqt bo'yicha topish | imzo === kelgan |
timingSafeEqual + uzunlik tekshiruvi |
| Eski imzoni qayta yuborish (replay) | Faqat imzo tekshiriladi | Vaqt belgisi (auth_date) va muddat |
| Parol bazasi o'g'irlandi | sha256(parol) |
scrypt/argon2 + tuz (crypto 2) |
| Kalit kod ichida | const KALIT = "…" GitHub'da |
env + sirlarni boshqarish |
valyuta da sir yo'q — kesh kaliti xavfsizlik uchun emas, nom uchun. Lekin xuddi shu funksiyalar keyingi qismlardagi serverda auth, webhook va to'lovlarning asosi bo'ladi.
6. CLI qadami: kesh kaliti va holat 20 commit'i
6.1 kalit.ts
Holat 20 ning ikkinchi qismi. Kanon src/kalit.ts — bitta funksiya:
// Kesh kaliti: so'rov URL'ining SHA-256 hash'i (16 belgi).
// API manzili yoki sana o'zgarsa — boshqa fayl, keshlar aralashmaydi
import { createHash } from "node:crypto";
export function keshKaliti(url: string): string {
return createHash("sha256").update(url).digest("hex").slice(0, 16);
}(Izoh qatorini telefon uchun ikkiga bo'ldik va kanondagi "xeshi" so'zini kurs atamasi — "hash'i" — bilan yozdik; kod o'zgarmagan.) Kesh fayli endi kurslar-<kalit>.json. Kalit URL'dan olingani uchun VALYUTA_API boshqa manzilga qaratilsa ham (masalan testdagi soxta server) keshlar aralashmaydi. Kanonning haqiqiy kalitlarini qayta hisobladik:
import { createHash } from "node:crypto";
const keshKaliti = (url) =>
createHash("sha256").update(url).digest("hex").slice(0, 16);
const asos = "https://cbu.uz/uz/arkhiv-kursov-valyut/json/";
console.log(keshKaliti(asos));
console.log(keshKaliti(`${asos}all/2026-10-18/`));
console.log(keshKaliti(`${asos}all/2026-10-01/`));Konsolda:
7d6ac3a5dea5f15a
7d1a2c0f8ef6fbf1
b8c23ce26aa8eef7Kanon jonli chiqishida (holat 20, haqiqiy CBU) xuddi shu nomlar:
$ valyuta kesh
kurslar-7d1a2c0f8ef6fbf1.json 25461 bayt 2026-10-23T05:23:05.463Z
kurslar-7d6ac3a5dea5f15a.json 25533 bayt 2026-10-23T05:23:05.976Z
kurslar-b8c23ce26aa8eef7.json 25497 bayt 2026-10-23T05:23:06.420Z
kurslar.json 25533 bayt 2026-10-23T05:19:17.109ZNega 16 belgi (64 bit), to'liq 64 emas? Fayl nomi qisqa bo'lsin. Bir foydalanuvchining keshida bir necha yuz fayl bo'ladi — 64 bitli hash'da tasodifiy to'qnashuv ehtimoli amalda nol (hash to'qnashuvi). Xavfsizlik kerak emas — hujumchi o'z keshini buzib, o'zidan boshqa hech kimga zarar qilolmaydi.
Ikki muddat: sanali kesh muddatsiz (o'tgan kunning kursi o'zgarmaydi), oxirgi kurs — 1 soat (fs chuqur).
6.2 Topilma: yetim kesh fayli
Oxirgi qatorga qarang: kurslar.json. Bu holat 18 formatidagi fayl — yangi kod uni endi o'qimaydi. Kesh formati o'zgarganda eski fayllar diskda yetim bo'lib qoladi. Kanon buni yashirmadi: valyuta kesh tozala ularni ham o'chiradi (glob * bilan). Saboq: kesh formatini o'zgartirsangiz, eski fayllar haqida o'ylang — avtomatik tozalash yoki versiya raqamli papka (kesh/v2/).
6.3 Holat 20 tayyor
util darsidagi parseArgs, styleText, debuglog va bugungi kalit bilan birga holat 20 ga yana ikki fayl kiradi: src/format.ts (jadval, JSON, CSV — RFC 4180 qochirish) va src/sana.ts (sananiTekshir — CBU'ning jim "oxirgi kurs" xulqiga qarshi). Kanon jonli natijasi:
$ valyuta kurs USD EUR --sana 2026-10-18
Eslatma: 2026-10-18 uchun kurs yo'q (dam olish kuni?) — CBU 2026-10-17 kursini berdi
2026-10-17 holatiga (api)
USD 1 12 055.90 44.25 AQSH dollari
EUR 1 13 572.53 109.87 EVRO$ valyuta kurs USD --sana 2026-10-25
Xato: Kelajak sana: 2026-10-25 (bugun 2026-10-23)
[exit 2]Kelajak sana uchun CBU API jim oxirgi kursni qaytaradi (200 bilan) — kanon buni o'lchab topdi. Shuning uchun valyuta sanani o'zi tekshiradi va javobdagi haqiqiy sanani ko'rsatadi.
Tekshiruv (tekshiruv-20): tip va lint 0, test 27/27 (+9), pack 38 fayl, 18.4 kB, sovuq start --help 76 ms, prod bog'liqlik 0.
git add -A
git commit -m "Bayroqlar parseArgs bilan: --sana, --format, --version" \
-m "Format: jadval/json/csv; rangli farq; kesh kaliti SHA-256"Kanon xabari bitta qator — Bayroqlar parseArgs bilan: --sana, --format (jadval/json/csv), --version; rangli farq, kesh kaliti SHA-256. U 72 belgidan uzun, shuning uchun sarlavha va tanaga bo'ldik (commit xabarlari).
7. Ko'p uchraydigan xatolar
| Belgi | Sabab | Davosi |
|---|---|---|
| Token taxmin qilindi | Math.random |
randomBytes, randomUUID, randomInt |
Digest already called |
digest() dan keyin update |
Har hash uchun yangi createHash |
| Hash har kompyuterda boshqa | Satr encoding'i yoki \r\n farqi |
Kirishni normallashtiring, UTF-8 |
| URL'da token buzildi | base64 dagi +, / |
base64url |
ERR_CRYPTO_TIMING_SAFE_EQUAL_LENGTH |
Uzunliklar teng emas | Avval uzunlikni tekshiring |
Imzo === bilan solishtirilgan |
Vaqt hujumiga ochiq | timingSafeEqual |
Parol sha256 da |
Tez hash — oson buziladi | scrypt/argon2 (crypto 2) |
8. Mashqlar
1-mashq (oson): to'g'ri tanlov
- Sessiya tokeni uchun funksiya:
crypto.random - SHA-256 hash necha bayt?
- URL uchun xavfsiz format:
- Kalitli imzo nomi:
- Imzoni solishtirish funksiyasi:
Yechim
- Bytes —
randomBytes(32). - 32 — 256 bit; hex'da 64 belgi.
- base64url —
+ / =yo'q. - HMAC — hash + maxfiy kalit.
- timingSafeEqual — vaqt bo'yicha teng.
2-mashq (o'rta): fayl butunligi
Fayl yozing, uning SHA-256 hash'ini hisoblang, keyin bitta belgini o'zgartirib qayta hisoblang. Funksiya faylHash(fayl) faylni readFile bilan o'qib, hex hash qaytarsin. Hash'larning birinchi 16 belgisini va tengligini chiqaring.
Yechim
import { createHash } from "node:crypto";
import { readFile, writeFile } from "node:fs/promises";
async function faylHash(fayl) {
const baytlar = await readFile(fayl);
return createHash("sha256").update(baytlar).digest("hex");
}
await writeFile("kurslar.csv", "USD,11903.15\n");
const birinchi = await faylHash("kurslar.csv");
await writeFile("kurslar.csv", "USD,11903.16\n");
const ikkinchi = await faylHash("kurslar.csv");
console.log(birinchi.slice(0, 16));
console.log(ikkinchi.slice(0, 16));
console.log(birinchi === ikkinchi);Konsolda:
ffea5edaba262f84
efbad1cb96c92491
falseBitta raqam — butunlay boshqa hash. npm integrity (npm pack) aynan shunday ishlaydi: yuklangan arxiv hash'i lock-fayldagi bilan solishtiriladi. Katta fayl uchun readFile o'rniga stream bilan bo'laklab update qilinadi (stream'lar).
3-mashq (qiyin): imzoli havola
Parol tiklash havolasi uchun ikki funksiya yozing. havolaYasa(email, muddat, kalit) → email.muddat.imzo (imzo — email.muddat ning HMAC-SHA256, base64url). havolaniTekshir(token, hozir, kalit) → email yoki xato matni: "buzilgan" (imzo mos emas), "muddati o'tgan". timingSafeEqual ishlating. email ichida nuqta bo'lishi mumkin — tokenni oxiridan bo'ling.
Yechim
import { createHmac, timingSafeEqual } from "node:crypto";
const imzoQil = (matn, kalit) =>
createHmac("sha256", kalit).update(matn).digest("base64url");
function havolaYasa(email, muddat, kalit) {
const tana = `${email}.${muddat}`;
return `${tana}.${imzoQil(tana, kalit)}`;
}
function havolaniTekshir(token, hozir, kalit) {
const i = token.lastIndexOf(".");
const tana = token.slice(0, i);
const kelgan = Buffer.from(token.slice(i + 1));
const kutilgan = Buffer.from(imzoQil(tana, kalit));
if (kelgan.length !== kutilgan.length) return "buzilgan";
if (!timingSafeEqual(kelgan, kutilgan)) return "buzilgan";
const j = tana.lastIndexOf(".");
if (Number(tana.slice(j + 1)) < hozir) return "muddati o'tgan";
return tana.slice(0, j);
}
const KALIT = "test-kaliti";
const t = havolaYasa("ali.valiyev@example.com", 1761200000, KALIT);
console.log(havolaniTekshir(t, 1761195600, KALIT));
console.log(havolaniTekshir(t, 1761300000, KALIT));
const soxta = t.replace("ali", "vali");
console.log(havolaniTekshir(soxta, 1761195600, KALIT));Konsolda:
ali.valiyev@example.com
muddati o'tgan
buzilganAvval imzo, keyin muddat tekshiriladi: imzosi noto'g'ri tokendagi muddatga ishonib bo'lmaydi. Email'ni almashtirish imzoni buzdi. Bu — JWT g'oyasining soddalashtirilgan ko'rinishi; haqiqiy auth'ni keyingi qismlarda qurasiz.
4-mashq: CLI qadami
src/kalit.ts ni yozing, kesh.ts ni kurslar-<kalit>.json ga o'tkazing (oxirgi kurs — 1 soat, sanali — muddatsiz). valyuta kurs USD, valyuta kurs USD --sana 2026-10-01, valyuta kesh — ikki xil fayl ko'rinsin. npm run check toza bo'lsa — holat 20 ni commit qiling.
Yechim
Kalitlar «CLI qadami» bo'limidagi qiymatlar bilan bir xil chiqishi kerak (URL bir xil bo'lsa). Holat 18 dan qolgan kurslar.json ni valyuta kesh tozala bilan o'chiring. Testlar soni — 27.
9. Real ishda
- Auth — sessiya tokenlari, parol tiklash havolalari, API kalitlari:
randomBytes. JWT — HMAC (HS256) yoki ochiq kalitli imzo bilan. - Webhook'lar — Stripe, GitHub, Telegram, Click/Payme so'rovlarni HMAC bilan imzolaydi; server
timingSafeEqualbilan tekshiradi. - Kesh va CDN — fayl nomidagi hash (
app.3f2a1c.js, content hash), ETag, Git commit ID — hammasi hash. - Intervyu savollari: "Hash va shifrlash farqi?", "Nega
Math.randomtoken uchun yaramaydi?", "Timing attack nima?".
Xulosa
- Xavfsizlik uchun tasodif — faqat
crypto:randomBytes,randomUUID,randomInt;Math.randomtaxmin qilinadi. - SHA-256 — deterministik, ko'chki effektli, bir tomonlama 32 baytlik barmoq izi;
createHash(Node) vacrypto.subtle.digest(brauzer) bir xil natija beradi. - hex — o'qish uchun,
base64url— URL va token uchun. - HMAC — kalitli imzo: xabar o'zgarmagan va kalit egasidan; solishtirish —
timingSafeEqual+ uzunlik tekshiruvi. valyutakeshi endi URL hash'i bilan nomlanadi; holat 20 commit qilindi (27 test, 38 fayl).
Keyingi dars: crypto 2: parolni hash'lash, shifrlash va imzo — scrypt va argon2 o'lchovlari, AES-256-GCM va Ed25519.
Manbalar
- Node.js 24 hujjati — Crypto (
randomBytes,randomInt,createHash,createHmac,timingSafeEqual) - MDN — Web Crypto API:
SubtleCrypto.digest,Crypto.getRandomValues - V8 blogi — "There's Math.random(), and then there's Math.random()" (2015, xorshift128+)
- Telegram — Validating data received via the Mini App
- NIST FIPS 180-4 — Secure Hash Standard (SHA-256 test qiymatlari)
- RFC 2104 — HMAC; RFC 4648 — base64url
Izohlar (0)
Izoh yozish uchun kiring.
- Hozircha izoh yo'q. Birinchi bo'ling!