5.18-bob: OTP va SMS integratsiyasi (Eskiz / Play Mobile)
5-QISM — Node.js Backend · 18-mavzu
1. Kirish va motivatsiya
Autentifikatsiya tizimini (5.15–5.17: parol, JWT, RBAC) qurdik. Endi O'zbekistonda juda keng tarqalgan, deyarli har bir ilovada uchraydigan amaliy mavzuni — telefon raqami orqali tasdiqlash (OTP) va SMS yuborish ni — o'rganamiz. O'zbekistonda ko'p ilova email emas, telefon raqami orqali ishlaydi: ro'yxatdan o'tish, login, parolni tiklash — hammasi SMS kodi bilan tasdiqlanadi.
OTP (One-Time Password — bir martalik parol) — qisqa muddatga amal qiladigan, bir marta ishlatiladigan kod (odatda 4-6 raqam). Foydalanuvchi telefon raqamini kiritadi, serverga SMS orqali kod keladi, uni kiritib o'zini tasdiqlaydi. Bu — telefon raqami haqiqatan o'sha odamniki ekanligini isbotlaydi (raqamga kirish — egalik isboti).
SMS yuborish uchun SMS provayder kerak — telefon operatorlariga ulangan xizmat. O'zbekistonda eng mashhurlari: Eskiz.uz va Play Mobile (playmobile.uz). Ular REST API 5.7-bob beradi — siz so'rov yuborasiz, ular SMS yetkazadi. Bu bobda OTP'ning to'liq oqimini (yaratish, yuborish, tekshirish, muddat, rate limiting) va Eskiz/Play Mobile integratsiyasini quramiz.
O'xshatish: OTP — bankomatdagi tasdiqlash kodi. Karta (telefon raqami) bor, lekin pul yechishdan oldin telefoningizga bir martalik kod keladi — uni kiritasiz. Kod — "bu haqiqatan siz" degan isbot (telefon sizdaligi). Kod qisqa muddatli (2-3 daqiqa) va bir martalik (ishlatilsa, bekor). Hatto kimdir kartani o'g'irlasa ham, telefoningizdagi kodsiz pul yecholmaydi.
Nega muhim?
- O'zbekiston bozori — ilovalar telefon + SMS bilan ishlaydi; deyarli majburiy.
- Xavfsizlik (14) — ikki bosqichli tasdiqlash; telefon egaligini isbotlash.
- Amaliy — Eskiz/Play Mobile integratsiyasi — real ish ko'nikmasi.
- Auth davomi — 5.15-5.17 ga telefon/OTP qo'shadi.
2. Nazariya — chuqur tushuntirish
2.1. OTP nima va qanday ishlaydi
OTP — bir martalik, qisqa muddatli kod. Asosiy g'oya: foydalanuvchi telefon raqamiga kirish imkoni borligini isbotlaydi (kod faqat o'sha telefonga keladi):
OTP turlari:
SMS OTP — telefonga SMS (bu bob; O'zbekistonda asosiy)
Email OTP — emailga kod 5.19-bob
TOTP — Google Authenticator (vaqtga bog'liq, SMS'siz — ilg'or)2.2. OTP oqimi (umumiy rasm)
1. Foydalanuvchi telefon raqamini kiritadi (+998901234567)
2. Server: tasodifiy 6 xonali kod yaratadi (masalan 384726)
3. Server: kodni HASH qilib, telefon + muddat bilan saqlaydi (DB/Redis — 2.6)
4. Server: SMS provayder orqali kodni yuboradi (Eskiz — 2.9)
5. Foydalanuvchi: SMS'dagi kodni kiritadi
6. Server: kiritilgan kodni saqlangan bilan solishtiradi + muddat tekshiradi
7. To'g'ri tasdiqlandi (token beriladi — 5.15); noto'g'ri xato ┌──────┐ telefon ┌────────┐ kod yaratadi+saqlaydi ┌──────────┐
│Client│────────▶│ Server │─────────────────────────▶│SMS provayder│
│ │ │ │ │ (Eskiz) │
└──────┘ └────────┘ └─────┬────┘
▲ │ SMS
└────────────────── kod (SMS) ◀──────────────────────────┘
Client kodni kiritadi Server tekshiradi token (5.15)2.3. OTP kodini yaratish (tasodifiy, xavfsiz)
Kod tasodifiy va bashorat qilib bo'lmaydigan bo'lishi kerak (14):
import crypto from "node:crypto"; // (5.3)
// Math.random — bashorat qilinadi (xavfsiz emas — 14)
const yomon = Math.floor(Math.random() * 900000) + 100000;
// crypto — xavfsiz tasodif (5.3)
const kod = crypto.randomInt(100000, 1000000); // 6 xonali (100000-999999)
crypto.randomIntishlating (Math.randomemas — 5.3):Math.randomkriptografik xavfsiz emas (bashorat qilinishi mumkin — 14). OTP — xavfsizlik elementi, shuning uchuncrypto.
2.4. OTP uzunligi va muddati
Uzunlik: 4-6 raqam (6 — xavfsizroq; 4 — qulayroq, kamroq xavfsiz)
Muddat: 1-5 daqiqa (qisqa — xavfsiz; juda qisqa — foydalanuvchi ulgurmaydi)
O'zbekistonda odatda 2-3 daqiqaBalans: qisqa muddat — xavfsizroq (o'g'irlangan kod tez yaroqsiz), lekin foydalanuvchi SMS kelishini kutib, kiritishga ulgurishi kerak. 2 daqiqa — ko'p holatda yaxshi. Muddat tugagach — qayta so'rash.
2.5. OTP'ni hash qilib saqlash (xavfsizlik — 14)
OTP — vaqtinchalik parol, shuning uchun uni ochiq saqlamang (parol kabi — 5.15):
DB'da ochiq kod: { telefon, kod: "384726" }
DB sizsa yoki ichki xodim ko'rsa — kodni biladi (14)
DB'da hash: { telefon, kodHash: hash("384726"), expiresAt }
solishtirishda kiritilgan kodni hash qilib taqqoslaymizKichik loyihada ba'zan ochiq saqlanadi (kod qisqa muddatli), lekin hash — to'g'ri amaliyot (14). bcrypt 5.15-bob yoki crypto hash 5.3-bob.
2.6. OTP'ni qayerda saqlash (Redis — ideal)
OTP — vaqtinchalik (2-3 daqiqa). Uni saqlash uchun ideal joy — Redis 5.21-bob, chunki Redis avtomatik muddat (TTL) beradi:
Redis: SET otp:+998901234567 <hash> EX 120 (120 sekund = 2 daqiqa)
2 daqiqadan keyin Redis O'ZI o'chiradi (muddat — 2.4)
DB (6): { telefon, kodHash, expiresAt, urinishlar }
muddatni qo'lda tekshirasiz; eski yozuvlarni tozalash kerakRedis afzal 5.21-bob: TTL bilan avtomatik o'chadi (tozalash kerak emas); tez (xotirada). DB ham ishlaydi (muddatni qo'lda tekshirasiz). Redis bo'lmasa — DB; bo'lsa — Redis.
2.7. Rate limiting (eng muhim — suiiste'molni to'xtatish — 14)
OTP — eng ko'p suiiste'mol qilinadigan nuqta (14). Ikki xavf bor:
1. SMS bombing — hacker bir raqamga minglab OTP so'raydi (SMS pul turadi!
sizga katta hisob; foydalanuvchiga spam)
Yechim: bir raqamga SMS so'rovini cheklash (masalan 1 daqiqada 1 marta, kuniga 5)
2. Kod brute-force — hacker 6 xonali kodni minglab marta sinaydi (000000-999999)
Yechim: noto'g'ri urinishlarni cheklash (masalan 3-5 marta, keyin bekor)Rate limiting MAJBURIY (14): OTP'siz rate limiting — pul (SMS xarajati) va xavfsizlik falokati. SMS so'rovini (telefon bo'yicha) va tekshirish urinishini (kod bo'yicha) cheklash shart. Bu — eng ko'p e'tibordan chetda qoladigan, lekin eng muhim qism.
2.8. SMS provayder nima (Eskiz / Play Mobile)
SMS provayder — telefon operatorlariga (Beeline, Ucell, UMS — 0.4) ulangan xizmat; siz API orqali so'rov yuborasiz, ular SMS yetkazadi:
Sizning botingiz SMS provayder API (Eskiz) operator foydalanuvchi telefoni
O'zbekiston provayderlari:
Eskiz.uz — eng mashhur; token-based REST API 2.9-bob
Play Mobile — playmobile.uz; XML/JSON API 2.10-bob
(boshqalar: Twilio — xalqaro, qimmatroq)Muhim: SMS matni provayder/operatorda oldindan tasdiqlangan shablon (template) bo'lishi kerak (O'zbekistonda qoida). Ixtiyoriy matn yubora olmaysiz — avval shablonni provayderdan tasdiqlatasiz ("Tasdiqlash kodi: {code}").
2.9. Eskiz.uz integratsiyasi (token-based)
Eskiz REST API 5.7-bob, token bilan ishlaydi:
1. Login: POST https://notify.eskiz.uz/api/auth/login
body: { email, password } javob: { data: { token } }
token olinadi (muddati bor — yangilanadi)
2. SMS yuborish: POST https://notify.eskiz.uz/api/message/sms/send
header: Authorization: Bearer <token>
body: { mobile_phone: "998901234567", message: "Kod: 384726", from: "4546" }Token boshqaruvi: Eskiz token muddati bor (~30 kun); kodda uni saqlab (kesh — 5.21), muddati tugaganda yangilash kerak. Email/parol —
.envda (5.8, 14).
2.10. Play Mobile integratsiyasi (qisqacha)
Play Mobile (playmobile.uz) — boshqa API (asosan login/parol bilan, JSON):
POST https://send.smsxabar.uz/broker-api/send
Basic Auth (login:parol)
body: { messages: [{ recipient: "998901234567", "message-id": "...",
sms: { originator: "3700", content: { text: "Kod: 384726" } } }] }Ikkala provayder ham printsipial bir xil: autentifikatsiya (token/basic) + SMS yuborish so'rovi. Kodda abstraksiya (interfeys) qiling — provayderni almashtirish oson bo'lsin (2.13, 9: SOLID).
2.11. OTP bilan auth oqimi (login/ro'yxat)
OTP autentifikatsiya bilan birlashadi 5.15-bob:
RO'YXAT/LOGIN (telefon orqali):
1. POST /auth/send-otp { telefon } OTP yuboriladi 2.2-bob
2. POST /auth/verify-otp { telefon, kod }
kod to'g'ri bo'lsa:
- foydalanuvchi bor login (token ber — 5.15, 5.16)
- foydalanuvchi yo'q yangi yarat (ro'yxat) + token
OTP login va ro'yxatni BIRLASHTIRADI (parolsiz auth!)Bu — O'zbekistonda eng keng tarqalgan: parolsiz, faqat telefon + OTP. Parol o'rniga — har safar (yoki birinchi marta) SMS kodi.
2.12. OTP xavfsizlik amaliyotlari (14)
Kod crypto bilan (Math.random emas — 2.3, 14)
Kodni hash qilib saqlang 2.5-bob; muddat qisqa (2-3min — 2.4)
Rate limiting: SMS so'rovi (telefon) + tekshirish urinishi (kod) — 2.7, 14
Urinish tugaganda kodni bekor qiling (yangi so'rasin)
Ishlatilgan kodni darrov bekor (bir martalik — 2.1)
Provayder kalitlari .env'da (14, 5.8)
Kodni javobda/log'da QAYTARMANG/yozmang (14, 5.12)
Telefon raqamini validatsiya (format — 5.9)2.13. Provayder abstraksiyasi (SOLID — 9)
Provayderni to'g'ridan ishlatmang — interfeys orqali (provayderni almashtirish oson bo'lsin — 9: SOLID):
smsService.send(telefon, matn)
│
├─▶ EskizProvider (hozir)
└─▶ PlayMobileProvider (kelajakda — kodni o'zgartirmasdan)
biznes logika "Eskiz"ni bilmaydi, faqat "SMS yubor" deydi (9.2: DIP)3. Sintaksis — tez ma'lumotnoma
import crypto from "node:crypto";
// OTP yaratish (2.3)
const kod = crypto.randomInt(100000, 1000000); // 6 xonali
// Saqlash (Redis — 2.6)
await redis.set(`otp:${tel}`, hash(kod), "EX", 120); // 2 daqiqa TTL
// Eskiz SMS (2.9)
await axios.post("https://notify.eskiz.uz/api/message/sms/send",
{ mobile_phone, message, from: "4546" },
{ headers: { Authorization: `Bearer ${token}` } });
// Oqim 2.11-bob: send-otp verify-otp token (5.15)
// Rate limiting 2.7-bob MAJBURIY4. Batafsil kod namunalari
Misol 1 — OTP yaratish va hash (2.3, 2.5)
import crypto from "node:crypto";
// Xavfsiz 6 xonali kod (2.3)
export const otpYarat = () => crypto.randomInt(100000, 1000000).toString();
// Kodni hash qilish (saqlash uchun — 2.5)
export const otpHash = (kod) =>
crypto.createHash("sha256").update(kod).digest("hex"); // (5.3)
// Solishtirish
export const otpTekshir = (kiritilgan, saqlanganHash) =>
otpHash(kiritilgan) === saqlanganHash;Misol 2 — Eskiz provayder (token + yuborish — 2.9)
import axios from "axios"; // (2.18-JS)
import { config } from "../config/index.js"; // (5.8)
let eskizToken = null; // keshlangan token (2.9)
// Token olish/yangilash
async function tokenOl() {
if (eskizToken) return eskizToken;
const { data } = await axios.post("https://notify.eskiz.uz/api/auth/login", {
email: config.eskiz.email, // .env (14, 5.8)
password: config.eskiz.password,
});
eskizToken = data.data.token;
return eskizToken;
}
// SMS yuborish (2.9)
export async function eskizSms(telefon, matn) {
try {
let token = await tokenOl();
await axios.post("https://notify.eskiz.uz/api/message/sms/send",
{ mobile_phone: telefon.replace("+", ""), message: matn, from: "4546" },
{ headers: { Authorization: `Bearer ${token}` } }
);
} catch (err) {
if (err.response?.status === 401) { // token muddati tugadi (2.9)
eskizToken = null; // qayta olish
return eskizSms(telefon, matn); // bir marta qayta urin
}
throw err; // (5.10)
}
}Misol 3 — Provayder abstraksiyasi (SOLID — 2.13)
// SMS xizmati — provayderni yashiradi (9.2: DIP, 2.13)
class SmsService {
constructor(provider) { this.provider = provider; } // Eskiz/PlayMobile
async send(telefon, matn) {
return this.provider.send(telefon, matn); // biznes logika provayderni bilmaydi
}
}
// Eskiz provayder (Misol 2 ni o'raydi)
const eskizProvider = { send: (tel, matn) => eskizSms(tel, matn) };
export const smsService = new SmsService(eskizProvider);
// Kelajakda: new SmsService(playMobileProvider) — biznes kod o'zgarmaydi (2.13)Misol 4 — OTP yuborish endpoint (rate limiting bilan — 2.7)
import { otpYarat, otpHash } from "../utils/otp.js";
import { smsService } from "../services/sms.js";
import { redis } from "../config/redis.js"; // (5.21)
export const sendOtp = async (req, res, next) => {
try {
const { telefon } = req.body; // (validatsiya — 5.9)
if (!/^\+998\d{9}$/.test(telefon)) {
return res.status(400).json({ error: "Telefon noto'g'ri (+998XXXXXXXXX)" });
}
// RATE LIMITING: 1 daqiqada 1 marta (SMS bombing — 2.7, 14)
const oxirgi = await redis.get(`otp:cooldown:${telefon}`);
if (oxirgi) {
return res.status(429).json({ error: "Iltimos, 1 daqiqa kuting" }); // 429 (5.7)
}
// Kod yarat, hash, Redis'ga saqla (TTL — 2.6)
const kod = otpYarat(); // (2.3)
await redis.set(`otp:${telefon}`, otpHash(kod), "EX", 120); // 2 daqiqa (2.4)
await redis.set(`otp:cooldown:${telefon}`, "1", "EX", 60); // 1 daqiqa cooldown
await redis.set(`otp:attempts:${telefon}`, "0", "EX", 120); // urinishlar (2.7)
// SMS yubor 2.9-bob — kodni LOG QILMANG (14, 2.12)
await smsService.send(telefon, `Tasdiqlash kodi: ${kod}`);
res.json({ message: "Kod yuborildi", expiresIn: 120 });
// kodni JAVOBDA qaytarmang (14)! (faqat dev'da test uchun mumkin)
} catch (err) { next(err); }
};Misol 5 — OTP tekshirish endpoint (2.11, brute-force himoyasi)
import jwt from "jsonwebtoken";
export const verifyOtp = async (req, res, next) => {
try {
const { telefon, kod } = req.body; // (5.9)
const saqlanganHash = await redis.get(`otp:${telefon}`);
if (!saqlanganHash) {
return res.status(400).json({ error: "Kod muddati tugagan yoki yuborilmagan" });
}
// BRUTE-FORCE: urinishlarni cheklash (2.7, 14)
const urinish = Number(await redis.get(`otp:attempts:${telefon}`)) || 0;
if (urinish >= 5) {
await redis.del(`otp:${telefon}`); // kodni bekor (2.7)
return res.status(429).json({ error: "Juda ko'p urinish. Yangi kod so'rang" });
}
// Tekshirish (2.5)
if (otpHash(kod) !== saqlanganHash) {
await redis.incr(`otp:attempts:${telefon}`); // urinishni oshir
return res.status(400).json({ error: "Kod noto'g'ri" });
}
// TO'G'RI — kodni darrov bekor qiling (bir martalik — 2.1)
await redis.del(`otp:${telefon}`);
await redis.del(`otp:attempts:${telefon}`);
// Foydalanuvchini top yoki yarat (login/ro'yxat birga — 2.11)
let user = await User.findOne({ telefon });
if (!user) {
user = await User.create({ telefon, tasdiqlangan: true }); // yangi (ro'yxat)
}
// Token ber (5.15, 5.16)
const accessToken = jwt.sign({ sub: user.id, rol: user.rol }, config.jwt.secret, { expiresIn: "15m" });
res.json({ accessToken, user: { id: user.id, telefon: user.telefon } });
} catch (err) { next(err); }
};Misol 6 — DB bilan OTP (Redis'siz — 2.6)
// Redis bo'lmasa, DB'da (6, 2.6)
const otpSchema = new mongoose.Schema({
telefon: { type: String, required: true, index: true },
kodHash: { type: String, required: true },
expiresAt: { type: Date, required: true },
urinishlar: { type: Number, default: 0 },
});
// TTL index — MongoDB muddati o'tganini avtomatik o'chiradi (2.6)
otpSchema.index({ expiresAt: 1 }, { expireAfterSeconds: 0 });
// Yuborish
const kod = otpYarat();
await Otp.findOneAndUpdate(
{ telefon },
{ kodHash: otpHash(kod), expiresAt: new Date(Date.now() + 120000), urinishlar: 0 },
{ upsert: true } // bor bo'lsa yangila, yo'q bo'lsa yarat
);
await smsService.send(telefon, `Kod: ${kod}`);Misol 7 — Express rate limiter (qo'shimcha himoya — 2.7, 5.20)
import rateLimit from "express-rate-limit";
// OTP endpoint'iga IP bo'yicha ham chegara (2.7, 5.20)
export const otpLimiter = rateLimit({
windowMs: 60 * 60 * 1000, // 1 soat
max: 10, // IP'dan soatiga 10 OTP so'rovi
message: { error: "Juda ko'p so'rov. Keyinroq urinib ko'ring" },
});
app.post("/api/auth/send-otp", otpLimiter, sendOtp); // IP + telefon (Misol 4) — ikki qatlamMisol 8 — Play Mobile provayder (2.10)
import axios from "axios";
// Play Mobile — Basic Auth (2.10)
export async function playMobileSms(telefon, matn) {
const auth = Buffer.from(`${config.playmobile.login}:${config.playmobile.parol}`).toString("base64");
await axios.post("https://send.smsxabar.uz/broker-api/send",
{
messages: [{
recipient: telefon.replace("+", ""),
"message-id": crypto.randomUUID(), // noyob ID (5.3)
sms: { originator: "3700", content: { text: matn } },
}],
},
{ headers: { Authorization: `Basic ${auth}` } }
);
}
// Bir xil interfeys (send) — SmsService'da almashtirish oson (2.13, Misol 3)5. To'g'ri va noto'g'ri holatlar
1) Math.random bilan kod
// bashorat qilinadi (14, 2.3)
const kod = Math.floor(Math.random() * 900000) + 100000;
// crypto
const kod = crypto.randomInt(100000, 1000000);2) Rate limiting'siz OTP
cheklovsiz SMS bombing (pul!) + brute-force (14, 2.7)
SMS so'rovi (telefon/IP) + tekshirish urinishi cheklangan3) Kodni javobda/log'da qaytarish
// kod javobda SMS keraksiz, xavfsiz emas (14, 2.12)
res.json({ message: "Yuborildi", kod });
// faqat "yuborildi"
res.json({ message: "Yuborildi" });4) Ishlatilgan kodni bekor qilmaslik
kod ishlatilgach ham amal qiladi (qayta ishlatiladi — 2.1)
to'g'ri kiritilgach darrov o'chiring (redis.del — Misol 5)5) Provayder kalitlarini kodda saqlash
// email/parol kodda (14, 5.8)
const token = await login("admin@x.uz", "parol");
// .env
const token = await login(config.eskiz.email, config.eskiz.password);6. Keng tarqalgan xatolar va yechimlari
Xato 1 — SMS kelmaydi
Sababi: telefon formati noto'g'ri (+ bilan/'siz), shablon tasdiqlanmagan 2.8-bob, token muddati tugagan 2.9-bob, balans yo'q. Yechimi: format (998XXXXXXXXX); provayderda shablonni tasdiqlat; token yangilash; balans.
Xato 2 — 401 Eskiz'dan
Sababi: token muddati tugagan/noto'g'ri 2.9-bob. Yechimi: tokenni qayta ol (Misol 2 — 401'da yangilash); email/parol to'g'rimi.
Xato 3 — OTP doim "noto'g'ri"
Sababi: hash mos emas (saqlashda/tekshirishda farqli), yoki muddati tugagan. Yechimi: bir xil hash funksiyasi; TTL tekshiring; kodni trim qiling (bo'shliq).
Xato 4 — SMS bombing (katta hisob keldi)
Sababi: rate limiting yo'q (2.7, 14). Yechimi: cooldown (telefon) + IP limit (Misol 4, 7).
Xato 5 — Kod muddatidan keyin ham ishlaydi
Sababi: muddat tekshirilmagan (DB — 2.6). Yechimi: Redis TTL (avtomatik) yoki expiresAt tekshiring (Misol 6).
7. Integratsiya — bu mavzu stack'ning qayerida uchraydi
- crypto 5.3-bob: xavfsiz kod yaratish, hash.
- Axios/HTTP (2.18-JS, 5.5): provayder API so'rovi.
- Auth (5.15, 5.16): OTP tasdiqlangach token.
- Env 5.8-bob: provayder kalitlari.
- Validatsiya 5.9-bob: telefon formati.
- Rate limiting 5.20-bob: SMS bombing/brute-force.
- Redis 5.21-bob: OTP saqlash (TTL).
- DB (6): foydalanuvchi (telefon).
- Telegram bot 5.14-bob: botda OTP/telefon tasdiqlash.
- SOLID 9.2-bob: provayder abstraksiyasi.
8. Eng yaxshi amaliyotlar (best practices)
- Kod
crypto.randomInt(Math.random emas — 2.3, 14); 6 xonali; 2-3 daqiqa muddat 2.4-bob. - Kodni hash qilib saqlang (ochiq emas — 2.5); Redis TTL bilan 2.6-bob.
- Rate limiting MAJBURIY — SMS so'rovi (telefon+IP) + tekshirish urinishi (2.7, 14).
- Ishlatilgan kodni darrov bekor (bir martalik — 2.1); urinish tugaganda bekor 2.7-bob.
- Kodni javobda/log'da qaytarmang (14, 2.12).
- Provayder kalitlari .env'da (14, 5.8).
- Telefon validatsiyasi (format — 5.9).
- Provayder abstraksiyasi (almashtirish oson — 2.13, 9).
- Shablonni provayderda tasdiqlat 2.8-bob; token muddatini boshqar 2.9-bob.
- OTP + auth birga (login/ro'yxat — 2.11).
9. Amaliy loyiha: "Telefon + OTP Autentifikatsiya Tizimi"
OTP va SMS integratsiyasini professional, xavfsiz darajada mustahkamlash.
Maqsad
Eskiz (yoki Play Mobile) bilan telefon raqami orqali OTP autentifikatsiya tizimini qurish: kod yuborish, tekshirish, rate limiting, muddat va token berish.
Talablar (requirements)
- OTP yaratish: crypto bilan 6 xonali; hash qilib saqlash (Redis/DB TTL — Misol 1, 6, 2.3, 2.5).
- SMS provayder: Eskiz integratsiyasi (token + yuborish); abstraksiya (Misol 2, 3, 2.9, 2.13).
- send-otp endpoint: telefon validatsiya; kod yuborish; cooldown rate limit (Misol 4, 2.7).
- verify-otp endpoint: kod tekshirish; brute-force limit; ishlatilgach bekor (Misol 5, 2.7).
- Auth birlashma: kod to'g'ri foydalanuvchi bor/yo'q login/ro'yxat + token (Misol 5, 2.11, 5.15).
- Rate limiting: telefon cooldown + IP limit (Misol 4, 7, 2.7, 14).
- Muddat: 2 daqiqa; muddatdan keyin yaroqsiz (Redis TTL — 2.4, 2.6).
- Xavfsizlik: kod hash; javobda/log'da qaytarmaslik; kalitlar .env (2.12, 14).
- (Bonus) Play Mobile: ikkinchi provayder; abstraksiya orqali almashtirish (Misol 8, 2.13).
- (Bonus) Qayta yuborish: "Kodni qayta yuborish" (cooldown'dan keyin).
Maslahatlar (hint)
- Kod:
crypto.randomInt(100000, 1000000)2.3-bob. - Redis:
set(otp:tel, hash, "EX", 120)(TTL — 2.6). - Cooldown: alohida
otp:cooldown:telkaliti 2.7-bob. - Brute-force:
otp:attempts:telhisoblagich 2.7-bob. - Eskiz: login token (keshla) SMS; 401'da token yangilash (Misol 2).
- Kodni JAVOBDA qaytarmang (14, 3-xato).
- Provayderni interfeys orqali (2.13, SOLID).
"Tayyor" mezonlari (acceptance criteria)
- send-otp kod yuboradi (SMS keladi); telefon validatsiya.
- verify-otp kodni tekshiradi; to'g'ri token.
- Kod crypto bilan, hash qilib saqlanadi.
- Muddat (2 daqiqa) ishlaydi; muddatdan keyin yaroqsiz.
- Rate limiting: SMS so'rovi (cooldown) + brute-force urinishi.
- Ishlatilgan kod darrov bekor qilinadi.
- Login/ro'yxat birlashgan (telefon orqali).
- Kod javobda/log'da yo'q; kalitlar .env'da.
- (Bonus) Provayder abstraksiyasi / Play Mobile.
Yechim kodi ataylab berilmagan — bu loyihani o'zingiz yozib ko'ring.
10. Xulosa va keyingi bobga ko'prik
Bu bobda O'zbekistonda juda keng tarqalgan amaliy mavzuni — OTP va SMS integratsiyasini — chuqur o'rgandik:
- OTP — bir martalik, qisqa muddatli kod (telefon egaligini isbotlaydi — 2.1); oqim (yarat yubor tekshir — 2.2).
- Kod
cryptobilan 2.3-bob; uzunlik/muddat (6 raqam, 2-3min — 2.4); hash qilib saqlang 2.5-bob; Redis TTL 2.6-bob. - Rate limiting MAJBURIY (SMS bombing + brute-force — 2.7, 14) — eng muhim qism.
- SMS provayder 2.8-bob — Eskiz (token-based — 2.9), Play Mobile 2.10-bob; provayder abstraksiyasi 2.13-bob.
- OTP + auth birga (parolsiz login/ro'yxat — 2.11); xavfsizlik (kod hash, javobda qaytarmaslik, kalitlar .env — 2.12, 14).
Keyingi bob — 5.19-bob: Email — Nodemailer. SMS'ni bildik; endi ikkinchi muhim aloqa kanalini — email yuborish (Nodemailer bilan) — o'rganamiz: SMTP, tasdiqlash xati, parolni tiklash, HTML shablon, ilova fayl, va email OTP. Email — ro'yxatdan o'tish tasdiqlash, bildirishnoma, hisobotlar uchun zarur.
Foydalanilgan rasmiy/ishonchli manbalar
- notify.eskiz.uz — Eskiz SMS API (auth/login, message/sms/send); playmobile.uz — Play Mobile API
- nodejs.org — crypto.randomInt; OTP best practices (expiry, rate limiting, hashing)
- DEV/Medium — OTP verification with Node.js (rate limiting, brute-force himoyasi)
Izohlar (0)
Izoh yozish uchun kiring.
- Hozircha izoh yo'q. Birinchi bo'ling!