Ketika RBAC Salah: Studi Kasus Keamanan untuk Full-Stack Developer

I am an enthusiastic researcher and developer with a passion for using technology to innovate in business and education.
Beberapa waktu lalu muncul sebuah write-up bug bounty berjudul “How a Simple RBAC Mistake Led to a $20K+ Admin Takeover” yang dipublikasikan oleh seorang security researcher. Kasus ini menunjukkan sesuatu yang sangat menarik: kerentanan yang menyebabkan takeover sistem bukan berasal dari eksploitasi kompleks, melainkan dari kesalahan logika sederhana dalam kontrol akses.
Kesalahan tersebut terjadi pada implementasi Role-Based Access Control (RBAC). Backend hanya memvalidasi bahwa token pengguna valid, tetapi tidak memverifikasi apakah pengguna tersebut memiliki hak akses yang sesuai.
Akibatnya, pengguna biasa dapat memanggil endpoint admin secara langsung dan bahkan mengubah rolenya menjadi Super Admin.
Kasus ini memberikan pelajaran penting bagi para full-stack developer:
Authentication bukanlah Authorization.
Login yang berhasil tidak berarti pengguna boleh melakukan semua aksi dalam sistem.
Dalam artikel ini kita akan membahas:
studi kasus kerentanan RBAC
contoh implementasi yang buruk
contoh implementasi yang aman
contoh mini project API menggunakan Hono
Studi Kasus: Bagaimana Sistem Bisa Diambil Alih
Dalam kasus tersebut, sistem memiliki arsitektur seperti ini:
Mobile App
│
│
Shared API Backend
│
┌───────────────┐
│ Admin Portal │
│ Invoice Portal│
└───────────────┘
Mobile app menyediakan fitur registrasi user.
Setelah user mendaftar, sistem memberikan token autentikasi.
Masalah muncul karena backend hanya melakukan pemeriksaan:
token valid → allow request
tanpa memverifikasi role.
Peneliti keamanan kemudian mencoba mengakses endpoint admin menggunakan token user biasa:
GET /user/v2/users
GET /user/v2/acl
POST /user/v2/acl
Karena tidak ada validasi role, request tersebut berhasil.
Lebih buruk lagi, terdapat endpoint yang memungkinkan perubahan role:
POST /user/v2/acl
Dengan payload sederhana:
{
"role": "super_admin"
}
Pengguna biasa berhasil menaikkan hak aksesnya menjadi Super Admin.
Dari titik ini, ia dapat:
membaca seluruh data pengguna
mengubah role pengguna lain
mengontrol konfigurasi sistem
mengakses beberapa portal admin sekaligus
Kerentanan ini menghasilkan bug bounty lebih dari $20.000.
Kesalahan Arsitektur yang Sering Terjadi
Beberapa pola kesalahan yang sering muncul pada aplikasi modern:
1. Backend hanya memvalidasi token
Developer sering membuat middleware seperti:
if token valid:
allow request
Padahal seharusnya:
if token valid AND role authorized:
allow request
2. Menganggap UI sebagai layer keamanan
Contoh kesalahan:
menu admin disembunyikan
tombol admin tidak muncul
route admin tidak ditampilkan
Namun endpoint API masih dapat dipanggil langsung menggunakan tools seperti:
Postman
Burp Suite
curl
3. API dipakai oleh banyak aplikasi
Backend sering dipakai oleh:
mobile app
admin dashboard
internal tools
Jika RBAC tidak dirancang dengan baik, maka token dari satu aplikasi bisa digunakan untuk mengakses sistem lain.
Contoh Project Buruk (Broken RBAC)
Berikut contoh mini API menggunakan Hono yang memiliki masalah yang sama seperti studi kasus tadi.
Struktur sederhana project:
src
├─ server.ts
├─ auth.ts
└─ db.ts
Middleware Authentication
import { verify } from "jsonwebtoken"
export const auth = async (c, next) => {
const token = c.req.header("Authorization")
if (!token) {
return c.json({ error: "Unauthorized" }, 401)
}
try {
const payload = verify(token, process.env.JWT_SECRET)
c.set("user", payload)
await next()
} catch {
return c.json({ error: "Invalid token" }, 401)
}
}
Middleware ini hanya memastikan user login.
Endpoint Admin (Tidak Aman)
GET /admin/users
Implementasi:
app.get("/admin/users", auth, async (c) => {
return c.json(await db.users.findMany())
})
Masalahnya:
tidak ada validasi role.
Jika user biasa memiliki token valid, ia tetap bisa mengakses endpoint ini.
Endpoint Role Update (Sangat Berbahaya)
POST /admin/role
Implementasi buruk:
app.post("/admin/role", auth, async (c) => {
const body = await c.req.json()
await db.users.update({
where: { id: body.userId },
data: { role: body.role }
})
return c.json({ success: true })
})
Attacker bisa mengirim request:
{
"userId": 15,
"role": "super_admin"
}
Jika backend tidak memverifikasi role:
user → super_admin
Inilah privilege escalation.
Versi Project yang Aman
Sekarang kita perbaiki implementasinya.
Kita pisahkan antara:
authentication
authorization
Middleware Role Check
export const requireRole = (role) => {
return async (c, next) => {
const user = c.get("user")
if (!user || user.role !== role) {
return c.json({ error: "Forbidden" }, 403)
}
await next()
}
}
Middleware ini memastikan hanya role tertentu yang boleh mengakses endpoint.
Endpoint Admin Aman
GET /admin/users
Implementasi:
app.get(
"/admin/users",
auth,
requireRole("admin"),
async (c) => {
return c.json(await db.users.findMany())
}
)
Sekarang alurnya:
request
↓
auth middleware
↓
role validation
↓
endpoint handler
User biasa akan mendapatkan:
403 Forbidden
Endpoint Role Update Aman
Endpoint ini sangat sensitif sehingga hanya boleh diakses oleh super admin.
app.post(
"/admin/role",
auth,
requireRole("super_admin"),
async (c) => {
const body = await c.req.json()
await db.users.update({
where: { id: body.userId },
data: { role: body.role }
})
return c.json({ success: true })
}
)
Sekarang user biasa tidak dapat mengubah role.
Praktik Terbaik untuk Developer
Beberapa prinsip penting ketika membangun API:
1. Backend adalah sumber keamanan
Frontend tidak boleh dipercaya.
Semua kontrol akses harus dilakukan di backend.
2. Setiap endpoint harus memiliki aturan akses
Contoh:
| Endpoint | Role |
|---|---|
| /users/me | user |
| /admin/users | admin |
| /admin/role | super_admin |
3. Gunakan prinsip Least Privilege
User hanya boleh melakukan hal yang benar-benar dibutuhkan.
4. Uji API seperti hacker
Cobalah:
akses endpoint admin dengan user biasa
ubah parameter request
gunakan Postman untuk bypass UI
Tes sederhana ini sering menemukan bug besar.
Kesimpulan
Kasus bug bounty tersebut menunjukkan satu hal yang sangat penting dalam pengembangan aplikasi modern.
Kerentanan terbesar sering kali bukan berasal dari eksploitasi kompleks, tetapi dari kesalahan logika sederhana dalam kontrol akses.
Kesalahan kecil seperti ini:
if token valid → allow
seharusnya ditulis:
if token valid AND role authorized → allow
Perbedaan kecil tersebut dapat menentukan apakah sistem Anda aman atau justru dapat diambil alih oleh attacker.
Sebagai full-stack developer, kita tidak hanya bertanggung jawab membuat aplikasi berjalan dengan baik, tetapi juga memastikan aplikasi tersebut tidak mudah disalahgunakan.
Karena dalam keamanan aplikasi, sering kali:
Bug paling berbahaya adalah bug yang terlihat paling sederhana.
Sumber Inspirasi: https://medium.com/@Seek404/how-a-simple-rbac-mistake-led-to-a-20k-admin-takeover-d196694791dd





