Asosiy kontentga o‘tish

Maqolalar 10 daqiqa o‘qish 2 soat amaliyot 49 ko‘rish

IDOR: login qilgan — ruxsat berilgan degani emas

Eng ko'p uchraydigan va eng oson tuzatiladigan zaiflik. Sababi bitta: dasturchi kim ekanligini tekshiradi, lekin nimaga tegishini tekshirmaydi. Beshta labda buni o'z qo'limiz bilan ko'ramiz, keyin Django'da bir marta va butunlay yopamiz.

security backend api

Mundarija

Oldingi darsda brauzer yuborgan so'rovni o'zgartirishni o'rgandik. Endi o'sha ko'nikma bilan bitta savol beramiz: so'rovdagi ID'ni boshqasiga almashtirsam nima bo'ladi?

Ko'p hollarda — hech narsa bo'lmaydi, chunki server tekshiradi. Lekin juda ko'p hollarda siz birovning hisobini, buyurtmasini yoki hujjatini ochib o'tirgan bo'lasiz. Bu — IDOR, va u OWASP'ning API uchun tuzgan ro'yxatida birinchi o'rinda turadi.

Bu darsdan keyin siz ruxsat tekshiruvi yo'q joyni topa olasiz va uni Django'da to'g'ri yopa olasiz.

Bu dars kimga

1-dars tugagan bo'lsin: Burp o'rnatilgan, Repeater ishlatib ko'rilgan. PortSwigger hisobi kerak.

Buzilgan taxmin#

Bu darsda ikkita taxminni sinaymiz. Birinchisi — asosiysi:

"Foydalanuvchi login qilgan. Demak, ruxsati bor."

Bu ikkita butunlay boshqa savolni bitta deb o'ylashdan kelib chiqadi:

  • Autentifikatsiya (authentication) — sen kimsan?
  • Avtorizatsiya (authorization) — senga shu narsaga tegishga ruxsat bormi?

@login_required birinchi savolga javob beradi, ikkinchisiga emas. Va dasturchining tasavvurida birinchisi ikkinchisini o'z ichiga oladi — chunki u o'z brauzerida faqat o'z ma'lumotini ko'radi.

Ikkinchi taxmin esa birinchisining yamog'i sifatida tug'iladi:

"ID'ni taxmin qilib bo'lmaydi, demak xavfsiz."

Shuning uchun ketma-ket raqam o'rniga GUID qo'yiladi. Lekin yashirish — himoya emas. Bugun ID'ni taxmin qila olmaysiz; ertaga u boshqa sahifada, logda, share-havolasida yoki API javobida oshkor bo'ladi. Beshta labning uchtasi aynan shu haqida.

Atamalar#

Atama Ma'nosi
authentication kimligini aniqlash (login)
authorization ruxsatini tekshirish (nimaga tegishi mumkin)
IDOR Insecure Direct Object Reference — obyektga to'g'ridan-to'g'ri, tekshiruvsiz murojaat
direct object reference so'rovdagi ID obyektni to'g'ridan-to'g'ri ko'rsatishi
horizontal privilege escalation o'z darajangdagi boshqa odamning narsasiga kirish
vertical privilege escalation yuqori darajaga ko'tarilish (oddiy foydalanuvchi → admin)
object-level authorization har bir obyekt uchun alohida ruxsat tekshiruvi
BOLA Broken Object Level Authorization — OWASP API Top 10 dagi 1-o'rin
security through obscurity yashirish orqali "himoya" — himoya emas
GUID / UUID taxmin qilib bo'lmaydigan uzun identifikator
robots.txt qidiruv botlariga mo'ljallangan fayl; odamga esa yashirin yo'llar ro'yxati

Nazariya: tekshiruv qayerda turishi kerak#

Zaif kodning qolipi doim bir xil:

Python
# Zaif: obyekt so'ralgan ID bo'yicha olinadi, egasi so'ralmaydi
@login_required
def order_detail(request, order_id):
    order = get_object_or_404(Order, pk=order_id)
    return render(request, "order.html", {"order": order})

@login_required bor — ya'ni tasodifiy odam kira olmaydi. Lekin login qilgan har qanday odam istalgan buyurtmani ko'ra oladi. Tekshiruv "kimsan" bosqichida to'xtab qolgan.

Kuzating

zaiflikni izlaganda so'rovda obyektni ko'rsatadigan qiymatni qidiring — id, user, order, file, doc, account. Keyin uni boshqasiga almashtiring va javob kodiga qarang: 200 — zaiflik bor; 403/404 — tekshiruv ishlayapti.

Ikki tekshiruvni zanjir sifatida ko'ring — IDOR ikkinchisi yo'q joyda tug'iladi:

Sxema
So'rov ──► [Autentifikatsiya]  ──► [Avtorizatsiya]  ──► Javob
           kim yubordi?             nimaga ruxsat?
           @login_required          ← BU YERDA TUSHIB QOLADI
           ✓ bor                      ✗ yo'q  ──►  IDOR

@login_required birinchi darvozani qo'yadi, lekin ikkinchisi — "bu obyekt shu foydalanuvchiniki mi?" — ochiq qoladi. Zanjir birinchi halqada to'xtaydi.

Amaliyot#

1-labYashirin, lekin himoyalanmagan#

Lab: Unprotected admin functionality · APPRENTICE

Vazifa: carlos foydalanuvchisini o'chirish.

Savol: admin paneli qayerda? Sayt uni menyuda ko'rsatmaydi — lekin sayt botlar uchun yozib qo'ygan fayl bor.

Eng oddiy tekshiruv: saytning ildizida odam uchun mo'ljallanmagan, lekin hamma o'qiy oladigan qaysi fayl turadi?

Bu lab eng oddiy holat: tekshiruv umuman yo'q. Admin paneli menyuda ko'rinmaydi, lekin /robots.txt uni oshkor qiladi — sayt botlarga "bu yerga kirmang" deb yozadi va shu bilan odamga "bu yerda nimadir bor" deb aytadi. Yashirish himoya emas, birinchi marta shu yerda ko'rinadi.

2-labID'ni almashtirsam nima bo'ladi#

Lab: User ID controlled by request parameter · APPRENTICE

Vazifa: carlos ning API kalitini olish.

Nimani ko'rasiz: o'z hisobingizga kirgach, manzil /my-account?id=wiener bo'ladi.

Savol: server id ni kimdan oladi — sessiyadanmi yoki manzildanmi? Ikkalasi ham bo'lsa, qaysi biriga ishonadi?

Eng oddiy tekshiruv: id=wiener ni id=carlos ga o'zgartiring.

Bu — IDOR'ning eng toza ko'rinishi. Server sizni sessiyadan taniydi (authentication), lekin qaysi hisobni ko'rsatishni manzildan oladi va ular bir xil odamning ekanini tekshirmaydi (authorization yo'q). Kim ekaningiz bilan nimaga tegayotganingiz bog'lanmagan.

3-labTaxmin qilib bo'lmasa ham#

Lab: User ID controlled by request parameter, with unpredictable user IDs · APPRENTICE

Vazifa: yana carlos ning API kalitini olish — lekin bu safar id ketma-ket raqam emas, taxmin qilib bo'lmaydigan GUID.

Savol: ID'ni taxmin qila olmasangiz — uni qayerdan topasiz? Sayt o'zi uni biror joyda ko'rsatib qo'ymaganmi?

Eng oddiy tekshiruv: carlos ning blog postini oching va sahifa manbasiga (yoki havolalarga) qarang — GUID o'sha yerda.

Mana shu lab kursning eng muhim saboqlaridan birini beradi: yashirish himoya emas. GUID qo'yish ID'ni taxmin qilishni qiyinlashtiradi, lekin zaiflikni yo'qotmaydi. ID bugun blog postida, ertaga logda, indamasdan API javobida yoki share-havolasida oshkor bo'ladi. Tekshiruv o'rniga yashirishga tayangan har qanday himoya vaqt masalasi.

4-labID faqat raqam emas#

Lab: Insecure direct object references · APPRENTICE

Vazifa: carlos ning parolini topib, uning hisobiga kirish.

Nimani ko'rasiz: jonli chat sahifasi suhbat yozuvlarini 1.txt, 2.txt kabi fayllardan yuklaydi.

Savol: fayl nomi 2.txt bo'lsa, 1.txt da nima bor?

Eng oddiy tekshiruv: fayl raqamini kamaytiring va boshqa birovning suhbatini o'qing.

IDOR faqat ?id= da emas. Har qanday so'rovdagi qiymat obyektni to'g'ridan-to'g'ri ko'rsatsa — fayl nomi, hujjat raqami, buyurtma kodi — va server egasini tekshirmasa, bu o'sha zaiflik. Nomlanishi boshqa, sababi bir xil.

5-labRuxsat metodga bog'lab qo'yilgan#

Lab: Method-based access control can be circumvented · PRACTITIONER

Vazifa: oddiy foydalanuvchidan admin darajasiga ko'tarilish (vertical privilege escalation).

Nimani ko'rasiz: admin panelidagi amal POST so'rovi bilan bajariladi va tekshiruv aynan POST ga qo'yilgan.

Savol: tekshiruv POST metodini tekshiryapti — GET bilan yuborsam nima bo'ladi?

Eng oddiy tekshiruv: so'rovni Burp'da GET ga o'zgartirib qayta yuboring.

Bu lab avvalgilaridan farq qiladi: bu yerda ruxsat bor, lekin u noto'g'ri narsaga bog'langan — HTTP metodiga. Dasturchi "admin amali POST bilan keladi" deb o'ylagan va tekshiruvni metodga osgan. Ruxsat tekshiruvi kim va nimaga haqida bo'lishi kerak; qanday haqida emas.

Nima ishlamaydi va nega#

"Frontendda tugmani yashirsam yetadi." Admin tugmasini faqat adminlarga ko'rsatish — ko'rinishni o'zgartiradi, ruxsatni emas. Tugma yo'q bo'lsa ham so'rov manzili o'sha joyda turadi va Burp uni to'g'ridan yuboradi. Frontend — qulaylik, himoya emas.

"GUID qo'ysam taxmin qila olmaydi." 3-lab shuni yiqitdi: ID bir joyda yashirin bo'lsa, boshqa joyda oshkor. Yashirish tekshiruvni almashtira olmaydi.

"@login_required qo'ydim-ku." U faqat kimligini tekshiradi. Login qilgan har qanday odam — jumladan hujumchi ham — o'sha tekshiruvdan o'tadi. Yetishmayotgani nimaga tegishi mumkinligi.

Endi yopamiz#

IDOR'ning yechimi bitta jumlaga sig'adi: obyektni ID bo'yicha emas, egasi bo'yicha oling. Ya'ni so'rovni "shu ID'li buyurtmani ber" emas, "shu foydalanuvchining shu ID'li buyurtmasini ber" deb qo'ying.

Python
# Zaif: har qanday login qilgan odam istalgan buyurtmani ko'radi
@login_required
def order_detail(request, order_id):
    order = get_object_or_404(Order, pk=order_id)
    return render(request, "order.html", {"order": order})
Python
# To'g'ri: so'rov o'zi egalikni cheklaydi — begona ID 404 bo'ladi
@login_required
def order_detail(request, order_id):
    order = get_object_or_404(Order, pk=order_id, user=request.user)
    return render(request, "order.html", {"order": order})

Bitta user=request.user — begona buyurtma endi "topilmadi" bo'lib qaytadi. Diqqat qiling: 403 emas, 404. "Bu senga tegishli emas" degan 403 ham obyekt borligini tasdiqlaydi; 404 esa hech narsa oshkor qilmaydi.

DRF'da xuddi shu qoida get_queryset da yashaydi:

Python
class OrderViewSet(viewsets.ModelViewSet):
    serializer_class = OrderSerializer
    permission_classes = [IsAuthenticated]

    def get_queryset(self):
        # Ro'yxat ham, bitta obyekt ham shu queryset'dan olinadi —
        # begona buyurtma umuman ko'rinmaydi
        return Order.objects.filter(user=self.request.user)

Muhim

ruxsatni bitta joyda — so'rov (queryset) darajasida — cheklang. if order.user != request.user tekshiruvini har view'da qo'lda yozsangiz, bittasini unutasiz. Unutilgan bittasi — zaiflik.

5-lab boshqacha yopiladi. U egalik emas, daraja masalasi. Yechim: ruxsatni HTTP metodiga emas, amalning o'ziga bog'lang — DRF'da permission_classes, Django'da @user_passes_test yoki guruh tekshiruvi GET bo'ladimi POST bo'ladimi, baribir ishlasin.

Nazorat savollari#

  1. authentication va authorization orasidagi farqni bir jumlada ayting.
  2. @login_required IDOR'dan himoya qiladimi? Sababini tushuntiring.
  3. Nima uchun begona obyektga 403 emas, 404 qaytarish afzal?
  4. "Yashirish himoya emas" — buni 3-lab misolida tushuntiring.
  5. IDOR faqat ?id= parametrida bo'ladimi? 4-labdan misol keltiring.
  6. horizontal va vertical privilege escalation orasidagi farq nima?
  7. 5-labda ruxsat tekshiruvi nimaga noto'g'ri bog'langan edi?
  8. Nega ruxsatni har view'da qo'lda yozgandan ko'ra get_queryset da cheklash xavfsizroq?
  9. get_object_or_404(Order, pk=order_id, user=request.user) qatoridagi user=request.user nimani kafolatlaydi?
  10. Frontendda admin tugmasini yashirish nega yetarli emas?

Report uchun talablar#

  1. Skrinshot: 2-labda id=carlos bilan olingan javob (API kaliti ko'rinsin).
  2. Gipotezangiz: 3-labda GUID'ni qayerdan topdingiz va bunga qanday fikrladingiz?
  3. Nima ishlamadi: beshta labdan birortasida noto'g'ri yo'ldan ketdingizmi? Nega ishlamadi?
  4. Tuzatuvchi kod: o'z loyihangizdan (yoki tasavvuriy) bitta view oling, unda IDOR bo'lsin, va uni get_queryset/user= bilan yoping. Kodni oldingi va keyingi holatda keltiring.

Faqat ruxsat berilgan joyda

ID almashtirish oson va shu bilan xavfli: bu texnikani faqat PortSwigger laboratoriyasida yoki o'zingizga tegishli tizimda sinang. Birovning hisobiga ID almashtirib kirish — ruxsat "oson" bo'lgani bilan jinoyat bo'lib qolaveradi.


Keyingi dars: XSS — brauzerga begona kod qanday tushadi va nega "foydalanuvchi kiritgan matn — matn emas, ehtimoliy kod".

10 daqiqa 49 marta o‘qildi