SQL injection va boshqa himoyalar
Injection (kiritish) hujumlari OWASP ro'yxatida yillar davomida yuqori o'rinda turadi. Ular orasida eng mashhuri โ SQL injection. Ushbu yakuniy darsda biz SQL injection qanday paydo bo'lishini va undan qanday himoyalanishni ko'rib chiqamiz, so'ng backend xavfsizligini mustahkamlaydigan bir qator muhim amaliyotlarni jamlaymiz.
SQL injection qanday yuzaga keladi?
SQL injection zaifligi foydalanuvchi kiritmasi SQL so'rovi matniga to'g'ridan-to'g'ri qo'shilganda paydo bo'ladi. Muammoning ildizi shu: agar kiritma so'rov matniga aralashsa, brauzer/ma'lumotlar bazasi qayerda ma'lumot tugab, qayerda buyruq boshlanishini farqlay olmaydi.
Xavfli naqsh โ bu so'rovni satrlarni ulash (string concatenation) orqali qurish:
// XAVFLI: foydalanuvchi kiritmasi so'rov MATNIGA ulanmoqda
const email = req.body.email; // foydalanuvchi nazoratidagi qiymat
const sorov = "SELECT * FROM users WHERE email = '" + email + "'";
db.query(sorov);
// Agar 'email' oddiy matn bo'lmasa, balki SQL sintaksisini
// o'z ichiga olsa, so'rovning ma'nosi butunlay o'zgarib ketishi mumkin.
// Server buni ODDIY MATN emas, BUYRUQ deb talqin qiladi.
Xuddi XSS singari, bu yerdagi asosiy muammo bir xil: ma'lumot bilan kod aralashib ketmoqda. Himoyaning kaliti โ ma'lumotni doim ma'lumot sifatida, koddan qat'iy ajratib ishlatish.
Himoya 1: Parametrlangan so'rovlar (prepared statements)
Eng ishonchli himoya โ parametrlangan so'rovlar (prepared statements). Bunda siz so'rov tuzilmasini alohida, qiymatlarni alohida beraytasiz. Ma'lumotlar bazasi qiymatlarni doim faqat ma'lumot deb qabul qiladi, hech qachon SQL buyruq deb emas โ ular so'rov matniga aralashmaydi.
// XAVFSIZ: parametrlangan so'rov (?, $1 kabi placeholder'lar)
// mysql2 kutubxonasi bilan misol:
const email = req.body.email;
const [natijalar] = await db.execute(
'SELECT * FROM users WHERE email = ?', // so'rov tuzilmasi
[email] // qiymatlar ALOHIDA beriladi
);
// 'email' ichida nima bo'lishidan qat'i nazar, u faqat
// email QIYMATI sifatida ishlatiladi, buyruq sifatida emas.
// PostgreSQL (node-postgres / pg) bilan: $1, $2 placeholder'lar
const natija = await pool.query(
'SELECT * FROM users WHERE email = $1 AND rol = $2',
[email, rol]
);
? yoki $1) โ bu shunchaki matn almashtirish EMAS. Ma'lumotlar bazasi so'rov rejasini avval qiymatsiz tayyorlaydi, keyin qiymatlarni xavfsiz bog'laydi. Aynan shu ajratish injection'ni imkonsiz qiladi.Himoya 2: ORM va so'rov quruvchilar
Zamonaviy loyihalarda ko'pincha ORM (Object-Relational Mapping) yoki so'rov quruvchi (query builder) ishlatiladi โ masalan, Prisma, Sequelize, Knex, TypeORM. Ular so'rovlarni ichki tarzda parametrlashtiradi, shu sabab injection'dan tabiiy himoya beradi:
// Prisma bilan: qiymatlar avtomatik xavfsiz parametrlanadi
const foydalanuvchi = await prisma.user.findUnique({
where: { email: req.body.email }
});
// Sequelize bilan:
const foydalanuvchi2 = await User.findOne({
where: { email: req.body.email }
});
// Ikkalasida ham 'email' xom SQL matniga aralashmaydi.
sequelize.query yoki raw so'rov), o'sha yerda satr ulashdan qoching โ parametrlangan variantini ishlating. ORM sizni faqat to'g'ri ishlatilgandagina himoya qiladi.Boshqa himoya 1: Kiritishni validatsiya qilish
Injection'dan tashqari ham, har bir kiruvchi ma'lumotni server tomonida tekshiring: kutilgan turdami, formatdami, chegaradami? Bu "foydalanuvchiga ishonma" tamoyilining amaliy ko'rinishi. Validatsiya kutilmagan ma'lumotni erta rad etadi.
// Validatsiya kutubxonasi (masalan, zod) bilan misol
const { z } = require('zod');
const royxatSxemasi = z.object({
email: z.string().email(),
parol: z.string().min(8).max(128),
yosh: z.number().int().min(0).max(150)
});
app.post('/royxat', (req, res) => {
const natija = royxatSxemasi.safeParse(req.body);
if (!natija.success) {
return res.status(400).json({ xato: 'Kiritma noto'g'ri' });
}
const malumot = natija.data; // endi bu ma'lumot tekshirilgan va toza
// ...
});
Boshqa himoya 2: Eng kam imtiyoz tamoyili
Eng kam imtiyoz (least privilege) โ har bir komponent faqat o'z ishini bajarishga yetadigan huquqqa ega bo'lsin, ortiqchasiga emas. Bu zaiflik yuz berganda ham zararni cheklaydi:
- Ilova ulanadigan ma'lumotlar bazasi foydalanuvchisiga faqat kerakli jadval va amallarga ruxsat bering (masalan, faqat
SELECT/INSERT, agarDROPkerak bo'lmasa); - Har bir xizmat faqat o'ziga kerakli sirlar va resurslarga kirsin;
- Admin huquqlarini faqat haqiqatan kerak bo'lganda bering.
Boshqa himoya 3: Sirlarni .env'da saqlash
Maxfiy kalitlar (JWT siri, ma'lumotlar bazasi paroli, API kalitlari) hech qachon kodga yozilmasligi va git tarixiga tushmasligi kerak. Ularni muhit o'zgaruvchilarida saqlang va .env faylini .gitignore'ga qo'shing:
// .env fayli (BU FAYL git'ga QO'SHILMAYDI)
// DATABASE_URL=postgres://user:parol@host:5432/baza
// JWT_SECRET=juda-uzun-tasodifiy-maxfiy-qiymat
// API_KEY=...
// Kodda sirlarni process.env orqali o'qiymiz
require('dotenv').config();
const JWT_SIR = process.env.JWT_SECRET;
if (!JWT_SIR) {
throw new Error('JWT_SECRET o'rnatilmagan!'); // ishga tushishda tekshiramiz
}
# .gitignore faylida albatta bo'lsin:
.env
.env.local
node_modules/
.gitignore'ga qo'shish yetarli emas โ u tarixda qoladi. Bunday holatda sirni darhol yangilang (rotate qiling), chunki uni fosh bo'lgan deb hisoblash kerak.Boshqa himoya 4: Rate limiting
Rate limiting (so'rov chastotasini cheklash) โ bir manbadan kelgan so'rovlar sonini vaqt oralig'ida cheklaydi. Bu parolni takror-takror urinib topishga urinishlar va xizmatni yuklama bilan bostirishga qarshi himoya (mavjudlik va autentifikatsiya himoyasi):
const rateLimit = require('express-rate-limit');
// Login uchun qattiqroq cheklov
const loginCheklovi = rateLimit({
windowMs: 15 * 60 * 1000, // 15 daqiqa
max: 5, // har IP dan 15 daqiqada 5 urinish
message: { xato: 'Juda ko'p urinish. Birozdan keyin qayta urining.' },
standardHeaders: true,
legacyHeaders: false
});
app.post('/login', loginCheklovi, loginHandler);
// Umumiy API uchun yumshoqroq cheklov
const umumiyCheklov = rateLimit({ windowMs: 60 * 1000, max: 100 });
app.use('/api/', umumiyCheklov);
Boshqa himoya 5: Xatoliklarni yashirish
Batafsil xato xabarlari โ ayniqsa stack trace, SQL xatosi matni, fayl yo'llari โ foydalanuvchiga ko'rsatilsa, ular tizim tuzilishi haqida keraksiz ma'lumot beradi. Ishlab chiqarish (production) muhitida foydalanuvchiga umumiy xabar bering, batafsil xatoni esa faqat serverning ichki loglariga yozing:
// Markazlashtirilgan xato ishlovchi (Express)
app.use((err, req, res, next) => {
// Batafsil xatoni faqat SERVER loglariga yozamiz
console.error(err.stack);
// Foydalanuvchiga UMUMIY xabar (ichki tafsilotlarni yashiramiz)
res.status(500).json({ xato: 'Serverda xatolik yuz berdi' });
});
NODE_ENV=production o'rnating. Ba'zi freymvorklar development rejimida batafsil xato sahifalarini ko'rsatadi โ bu sahifalar tizim ichki tuzilishini fosh qilishi mumkin. Foydalanuvchiga hech qachon xom stack trace ko'rsatmang.Yakuniy nazorat ro'yxati
Ushbu bobni yakunlab, backend xavfsizligining amaliy nazorat ro'yxatini jamlaymiz:
- Barcha so'rovlar parametrlangan yoki ishonchli ORM orqali โ satr ulash yo'q;
- Har bir kiruvchi ma'lumot server tomonida validatsiya qilinadi;
- Parollar
bcryptbilan hashlanadi, ochiq saqlanmaydi; - Sirlar
.env'da, git'ga tushmaydi; - Cookie'lar
HttpOnly,Secure,SameSitebilan; - Chiqish eskeyplanadi (XSS), CSP o'rnatiladi;
- Holatni o'zgartiruvchi so'rovlar CSRF'dan himoyalangan;
- Login va boshqa muhim endpointlarda rate limiting;
- Xato xabarlari yashiriladi, faqat loglarga yoziladi;
- HTTPS majburiy,
helmetsarlavhalari o'rnatilgan; - Bog'liqliklar
npm auditbilan muntazam tekshiriladi; - Eng kam imtiyoz tamoyili har qatlamda qo'llaniladi.
Xulosa
- SQL injection foydalanuvchi kiritmasi so'rov matniga aralashganda paydo bo'ladi; birlamchi himoya โ parametrlangan so'rovlar;
- ORM'lar tabiiy himoya beradi, lekin xom SQL yozganda ehtiyot bo'ling;
- Injection, XSS va CSRF'ning umumiy ildizi bitta: ma'lumot bilan kodni aralashtirmaslik va kiritmaga ishonmaslik;
- Qo'shimcha amaliyotlar: validatsiya, eng kam imtiyoz, sirlarni
.env'da, rate limiting, xatolarni yashirish; - Xavfsizlik โ bir emas, ko'p qatlamli himoya (defense in depth); har qatlam boshqasini mustahkamlaydi.