Maqolalar 10 daqiqa o‘qish 2 soat amaliyot 38 ko‘rish
SQL injection: kiritilgan matn bazaga buyruq bo'lib tushganda
Foydalanuvchi kiritgan qidiruv so'zi bazaga so'rovning bir qismi bo'lib qo'shilsa, o'sha so'z buyruqni o'zgartira oladi — ma'lumot o'g'irlash, loginni chetlab o'tish, butun jadvalni chiqarish. Beshta labda buni ishga tushiramiz, keyin parametrlangan so'rov bilan butunlay yopamiz.
Mundarija
Bu kursda ko'p marta bitta naqshni ko'rdik: ishonchsiz ma'lumot bajariladigan joyga tozalanmasdan tushadi. XSS'da u brauzerda kodga aylandi. Endi o'sha naqshni ma'lumotlar bazasida ko'ramiz — foydalanuvchi kiritgan matn SQL so'rovining bir qismi bo'lib qo'shilsa, u so'rovni o'zgartira oladi.
SQL injection eng qadimiy zaifliklardan biri, lekin hali ham ishlab turibdi. Uning mag'zini bu saytda allaqachon bir marta ko'rgansiz — SQL injection'ni o'z ko'zingiz bilan ko'ring va yoping maqolasida zaif ilova yozib, uni buzgan edik. Bu dars o'sha bilimni PortSwigger labllarida mustahkamlaydi va uch xil hujum shaklini ko'rsatadi.
Bu darsdan keyin siz SQLi'ni topa olasiz, uni loginni chetlab o'tish, ma'lumot chiqarish va "ko'r" (blind) shakllarida ishga tushira olasiz va nega parametrlangan so'rov yagona to'g'ri yechim ekanini tushunasiz.
Bu dars kimga
1-dars (Burp) tugagan bo'lsin. SQL nima ekani — SELECT ... WHERE ... —
bilan tanish bo'lsangiz osonroq. Yuqoridagi SQLi maqolasini avval o'qib
chiqing.
Buzilgan taxmin#
SQL injection bitta odatiy qulaylikdan tug'iladi:
"So'rovni satrlarni qo'shib yasayman — kiritilgan qiymatni shunchaki orasiga qo'yaman."
Dasturchi so'rovni shunday yozadi:
query = "SELECT * FROM products WHERE category = '" + category + "'"
Uning tasavvurida category — bitta so'z, masalan Gifts. Lekin
category ichida ' belgisi bo'lsa, u satrni yopadi va qolgani SQL
kodiga aylanadi. Ma'lumot bilan kod bir satrga aralashib ketgan — va
brauzer XSS'da HTMLni ajratolmagani kabi, baza ham bu yerda ma'lumotni
koddan ajratolmaydi.
Kiritilgan qiymat — matn emas, so'rovning bir qismi: ma'lumot bo'lib qoladimi yoki buyruqqa aylanadimi, uni yozish usuli hal qiladi.
Atamalar#
| Atama | Ma'nosi |
|---|---|
SQL injection / SQLi |
kiritilgan matn SQL so'rovini o'zgartirishi |
WHERE clause |
so'rovning shart qismi — SQLi ko'pincha shu yerda |
UNION attack |
ikki so'rov natijasini birlashtirib, boshqa jadvaldan ma'lumot olish |
comment (--, #) |
SQL izohi: qatorning qolganini "o'chiradi" |
blind SQLi |
natija ham, xato ham ko'rinmaydi — javob bilvosita o'qiladi |
parametrized query |
qiymat so'rovga alohida beriladi, satrga qo'shilmaydi |
prepared statement |
so'rov qolipi oldindan tayyorlanadi, qiymat keyin |
ORM |
baza bilan obyekt orqali ishlash (Django ORM parametrlaydi) |
stacked queries |
bitta joyda bir necha so'rov ketma-ket |
Nazariya: ma'lumot va kod bir satrda#
Zaif qolip — satr qo'shish orqali so'rov yasash:
# Zaif: category satrga qo'shiladi, ' belgisi so'rovni ochib yuboradi
def products(request):
category = request.GET.get("category", "")
query = f"SELECT * FROM products WHERE category = '{category}' AND released = 1"
rows = run_sql(query)
return render(request, "products.html", {"rows": rows})
category ga Gifts' OR 1=1-- yozilsa, so'rov shunga aylanadi:
SELECT * FROM products WHERE category = 'Gifts' OR 1=1--' AND released = 1
OR 1=1 hamma qatorni chiqaradi, -- esa AND released = 1 ni izohga
aylantirib "o'chiradi". Yashirin mahsulotlar ham ko'rinadi — chunki
sizning matningiz endi so'rovning mantiqini boshqaradi.
Kuzating
SQLi izlaganda kiritilgan qiymatga bitta ' qo'shib
ko'ring. Sahifa xato bersa yoki o'zgarib qolsa — matn so'rovga
tushayapti. Bu birinchi signal; qolgani shu yo'ldan ketadi.
Amaliyot#
1-labYashirin ma'lumotni chiqarish#
Lab: SQL injection in WHERE clause allowing retrieval of hidden data
· APPRENTICE
Vazifa: chiqarilmagan mahsulotlarni ham ko'rsatish.
Nimani ko'rasiz: kategoriya bo'yicha filtr — ?category=Gifts. So'rov
faqat released = 1 bo'lgan mahsulotlarni chiqaradi.
Savol: category qiymati so'rovga qanday qo'shiladi? Unga ' OR 1=1--
qo'shsangiz, released = 1 sharti nima bo'ladi?
Eng oddiy tekshiruv: ?category=Gifts'+OR+1=1--.
Bu SQLi'ning eng toza ko'rinishi: sizning matningiz so'rovning mantiqini
o'zgartiradi. OR 1=1 shartni doim rost qiladi, -- qolgan filtrni
izohga aylantiradi. Server yashirin mahsulotni sizdan yashirdi, lekin
so'rovni sizga ochiq qoldirdi.
2-labLoginni chetlab o'tish#
Lab: SQL injection allowing login bypass
· APPRENTICE
Vazifa: parolsiz administrator bo'lib kirish.
Nimani ko'rasiz: login forma. So'rov ehtimol
WHERE username = '...' AND password = '...' ko'rinishida.
Savol: username ga administrator'-- yozsangiz, parol sharti nima
bo'ladi?
Eng oddiy tekshiruv: username: administrator'--, parol: istalgan.
Bu SQLi'ning eng xavfli oqibatlaridan biri: -- parol tekshiruvini
izohga aylantiradi, ya'ni parol umuman tekshirilmaydi. Autentifikatsiyaning
o'zi chetlab o'tildi. Bir belgi — ' — butun login mantiqini yiqitdi.
3-labUNION: nechta ustun bor#
Lab: UNION attack, determining the number of columns
· PRACTITIONER
Vazifa: so'rov nechta ustun qaytarishini aniqlash.
Nimani ko'rasiz: kategoriya filtri, ma'lumot sahifada ko'rinadi.
Savol: UNION bilan boshqa jadval qo'shmoqchisiz, lekin UNION ikki
so'rovning ustunlari soni bir xil bo'lishini talab qiladi. Nechta
ustun borligini qanday bilasiz?
Eng oddiy tekshiruv: ' UNION SELECT NULL--, keyin NULL,NULL--,
xato yo'qolguncha NULL qo'shib boring.
Bu — UNION hujumining tayyorgarligi. UNION bilan boshqa jadvaldan
ma'lumot olishdan oldin, ustunlar soni mos kelishi kerak. NULL lar
bilan sinab, xato yo'qolgan sonni topasiz. Bu mexanik qadam, lekin usiz
keyingisi ishlamaydi.
4-labUNION: boshqa jadvaldan ma'lumot#
Lab: UNION attack, retrieving data from other tables
· PRACTITIONER
Vazifa: users jadvalidan username va parollarni chiqarib,
administrator bo'lib kirish.
Nimani ko'rasiz: oldingi labda ustunlar sonini aniqladingiz; endi o'sha ustunlarga boshqa jadval ma'lumotini qo'yasiz.
Savol: so'rov mahsulotlarni chiqaradi. UNION bilan uning o'rniga
users jadvalini qo'ysangiz, sahifa nimani ko'rsatadi?
Eng oddiy tekshiruv: ' UNION SELECT username, password FROM users--.
Mana SQLi nega shunchalik xavfli: so'rov bitta jadval uchun yozilgan, lekin
UNION orqali siz butunlay boshqa jadvalni — parollar saqlanadigan
jadvalni — o'sha sahifada chiqarasiz. Mahsulot ro'yxati endi foydalanuvchi
parollari ro'yxati.
5-labKo'r (blind) SQLi#
Lab: Blind SQL injection with conditional responses
· PRACTITIONER
Vazifa: administrator parolini bittalab chiqarib, kirish.
Nimani ko'rasiz: tracking cookie so'rovda ishlatiladi, lekin natija ham, xato ham ko'rinmaydi — faqat "Welcome back" chiqadi yoki chiqmaydi.
Savol: natijani ko'rmasangiz ham, so'rov rost yoki yolg'onligini sahifa bilvosita ko'rsatadimi? Har savolga "ha/yo'q" javob bersangiz, parolni harflab topa olasizmi?
Eng oddiy tekshiruv: shart to'g'ri bo'lsa "Welcome back" chiqadigan so'rov yozing, keyin Burp Intruder bilan harflarni sinang.
Bu eng nozik shakl: natija umuman ko'rinmaydi. Lekin sahifaning bor yoki yo'q bo'lishi ham axborot — har so'rov bitta "ha/yo'q" savol. "Parolning birinchi harfi 'a' dan kattami?" degan minglab savol bilan, ko'rinmaydigan ma'lumotni harflab tiklaysiz. Ko'rinmaslik himoya emas — bilvosita signal ham signal.
Nima ishlamaydi va nega#
"' belgisini bloklasam yetadi." Denylist doim teshik: kodlangan
tirnoq, UNION o'rniga boshqa texnika, raqamli kontekstda tirnoq umuman
kerak emas. Belgilarni sanashga urinsangiz, bittasini o'tkazib yuborasiz.
"Xato xabarlarini yashirsam, blind SQLi ishlamaydi." 5-lab: natija ko'rinmasa ham, sahifaning javob berishi yoki bermasligi — bilvosita signal. Yashirish sekinlashtiradi, to'xtatmaydi.
"Kirishni tozalab, xavfli so'zlarni olib tashlayman." SELECT so'zini
SELSELECTECT qilib yozsangiz, bittasini olib tashlagach SELECT qoladi.
Denylist SQLi'ni hech qachon to'liq yopmaydi.
Endi yopamiz#
SQLi'ning yechimi bitta va u mutlaq: parametrlangan so'rov. Qiymatni so'rov satriga qo'shmang — bazaga alohida bering, u qiymatni hech qachon kod deb o'qimaydi.
# XAVFLI: qiymat satrga qo'shiladi — SQLi shu yerda
query = f"SELECT * FROM products WHERE category = '{category}'"
run_sql(query)
# TO'G'RI: qiymat alohida beriladi, baza uni doim ma'lumot deb oladi
run_sql("SELECT * FROM products WHERE category = %s", [category])
Farq ko'rinmas, lekin tubdan: parametrlangan so'rovda category ichida
nima bo'lishidan qat'i nazar — ' OR 1=1-- bo'lsa ham — u bitta matn
qiymat bo'lib qoladi, hech qachon SQL kodiga aylanmaydi.
Django ORM buni avtomatik qiladi:
# Django ORM har doim parametrlaydi — SQLi bu yerda deyarli imkonsiz
Product.objects.filter(category=category, released=True)
Muhim
yagona xavf — raw() va extra() da satr qo'shsangiz.
Product.objects.raw(f"... {category}") — SQLi qaytadi. raw() kerak
bo'lsa ham parametr bilan: raw("... WHERE category = %s", [category]).
ORM'dan chiqmang; chiqsangiz — parametrlang.
Nega kirishni tozalash emas. Kirishni tozalash (masalan ' ni olib
tashlash) — noto'g'ri qatlam: bir xil qiymat bir kontekstda xavfli,
boshqasida to'g'ri (O'Brien familiyasi). Parametrlash muammoni ildizidan
yechadi — ma'lumot va kodni ajratadi — tozalash esa har doim yamoq bo'lib
qoladi.
Aniq misol: bu saytda grep -rn "\.raw(\|\.extra(\|cursor.execute" apps/
bitta natija beradi — healthz da cursor.execute("SELECT 1"). U qat'iy
matn, foydalanuvchi qiymati umuman yo'q. Ya'ni butun ilovada foydalanuvchi
ma'lumoti bilan xom SQL yozilgan birorta joy yo'q — hamma so'rov ORM
orqali, ORM esa har doim parametrlaydi. SQLi bu yerda dizayn bo'yicha
imkonsiz.
Nazorat savollari#
- SQL injection nega ishlaydi? "Ma'lumot va kod bir satrda" nimani anglatadi?
' OR 1=1--da har uch qism nima qiladi (',OR 1=1,--)?- 2-labda
administrator'--parolni nega tekshirtirmaydi? UNIONhujumida nega avval ustunlar sonini topish kerak (3-lab)?- Blind SQLi'da natija ko'rinmasa, ma'lumotni qanday chiqarasiz (5-lab)?
- Parametrlangan so'rov nega SQLi'ni to'xtatadi? Qiymat qayerda "kod bo'lishdan" to'xtaydi?
- Django ORM SQLi'dan qanday himoya qiladi? Qaysi metodlar bundan mustasno?
raw()ni parametrsiz ishlatsangiz nima bo'ladi?- Nega "
'belgisini bloklash" SQLi'ni yopmaydi? - Nega kirishni tozalash emas, parametrlash to'g'ri yechim? Ildiz va yamoq farqini ayting.
Report uchun talablar#
- Skrinshot: kamida ikkita labda "solved" yoki chiqarilgan ma'lumot (parollar/mahsulotlar) ko'ringan holat.
- UNION: 3 va 4-labda ustunlar sonini qanday topdingiz va
usersjadvalini qanday chiqardingiz? - Blind: 5-labda ko'rinmaydigan ma'lumotni qaysi "ha/yo'q" savollar bilan tikladingiz? Jarayonni tushuntiring.
- Tuzatuvchi kod: o'z loyihangizdan (yoki tasavvuriy) satr qo'shib yasalgan so'rov toping. Uni parametrlangan so'rovga yoki ORM'ga o'tkazing. Oldingi va keyingi holatni keltiring.
Faqat ruxsat berilgan joyda
SQLi butun bazani — parollar, shaxsiy ma'lumotlar — chiqarib olishi mumkin. Uni faqat PortSwigger laboratoriyasida yoki o'zingizga tegishli tizimda sinang. Birovning bazasiga so'rov yuborish — jinoyat.
Keyingi dars: Autentifikatsiya zaifliklari — login sahifasi eng ko'p hujum qilinadigan eshik, va nega "parol to'g'ri bo'lsa kiritamiz" degan mantiq yetarli emas.