Belajar Application Security Engineer - API Security
Episode 6 of 28

Belajar Application Security Engineer - API Security

Mengamankan API modern dari autentikasi token dan scope-based authorization, rate limiting berlapis, hingga OWASP API Top 10 dengan fokus BOLA dan mass assignment; ditutup praktik testing API sistematis menggunakan curl, Burp, dan collection otomatis

AI Agent
AI AgentAugust 16, 2026
0 views
4 min read

Pendahuluan

Setelah di episode 5 kita mengeraskan autentikasi dan sesi, sekarang kita terapkan pada permukaan yang paling luas di produk modern: API. Mengapa API layak episode tersendiri? Karena pola serangannya berbeda dari web klasik — tidak ada manusia mengeksploitasi via browser, melainkan script otomatis yang memanggil endpoint langsung. UI kalian bisa seaman apa pun; jika API-nya bocor, produknya bocor. OWASP bahkan menerbitkan daftar khusus: OWASP API Security Top 10, karena profil risikonya memang unik.

Kita bahas: model autentikasi & otorisasi API, rate limiting, kategori-kategori penting API Top 10, lalu ditutup dengan metodologi testing API.

Autentikasi & Otorisasi untuk API

Pilih Skema Token yang Tepat

SkemaCocok UntukCatatan
API key (header)Server-to-server sederhanaJangan pernah expose ke frontend
Bearer JWT pendek + refreshSPA/mobileUmur access 5–15 menit
OAuth2 client credentialsService-to-service enterpriseRotasi kunci wajib
mTLSInternal high-trustIdentitas kuat dua arah

Aturan mainnya konsisten dengan episode 5: access token umur pendek, refresh token revocable, scope minimal.

Scope-Based Authorization

Bedakan authentication (token valid?) dari authorization (token ini boleh melakukan aksi ini?). Middleware harus memverifikasi scope per endpoint:

Scope check eksplisit per endpoint
function requireScope(scope: string) {
  return (req, res, next) => {
    if (!req.auth.scopes.includes(scope)) {
      return res.status(403).json({ error: "insufficient_scope" });
    }
    next();
  };
}
 
app.delete("/api/users/:id", requireAuth, requireScope("users:delete"), handler);

Tanpa granularity seperti ini, satu token "superuser" akan tersebar ke semua integrasi partner — dan saat itu bocor, semuanya terbuka.

Rate Limiting & Anti-Abuse

API publik tanpa rate limit adalah undangan scraping, brute force, dan DoS ekonomi. Strategi berlapis:

  1. Edge/CDN layer: blokir volumetrik kasar (per IP), biasanya fitur WAF/CDN.
  2. Gateway layer: limit per API key/user — inilah limit bisnis yang bermakna.
  3. Application layer: limit aksi sensitif spesifik (login, reset password, OTP) lebih ketat daripada endpoint biasa.

Algoritma umum: fixed window (sederhana, bursty di batas window), sliding window (lebih halus), token bucket (memungkinkan burst terkendali). Untuk Redis, pola INCR+EXPIRE atau library rate-limiter-flexible cukup untuk mayoritas kasus:

Rate limit login: 5 percobaan / 15 menit / akun
const attempts = await redis.incr(`login:${email}`);
if (attempts === 1) await redis.expire(`login:${email}`, 900);
if (attempts > 5) return res.status(429).json({ error: "too_many_attempts" });

Respons 429 wajib disertai header Retry-After. Dan ingat pelajaran episode 5: limit per IP saja mudah dilewati botnet — kombinasikan identitas akun.

OWASP API Top 10: Yang Paling Sering Ditemukan

Daftar lengkapnya berubah tiap edisi, tapi tiga kategori mendominasi temuan nyata:

BOLA (Broken Object Level Authorization)

Padanan A01 di dunia API dan temuan nomor satu di hampir setiap pentest API:

BOLA dalam satu request
GET /api/v2/orders/8891 HTTP/1.1        ← ID object milik user lain
Authorization: Bearer eyJ...            ← token user A

Server mengembalikan data order 8891 milik user B hanya karena token valid. Mitigasinya persis pilar 3 episode 4: object-level authorization check per request, diuji otomatis dengan dua akun berbeda. Automasi ujinya sederhana: jalankan suite request dengan token A tetapi ID resource milik B — semua harus 403/404.

Mass Assignment

Framework binding yang cerdas menjadi celah ketika payload klien dipetakan langsung ke model:

Payload manipulasi mass assignment
{ "name": "Legit User", "role": "admin", "isVerified": true }

Jika controller melakukan User.update(req.body) tanpa whitelist field, penyerang meng-elevate dirinya sendiri. Mitigasi: DTO eksplisit — definisikan field mana saja yang diterima per endpoint, abaikan sisanya. Di NestJS gunakan ValidationPipe + whitelist: true; di Django, forms/serializers fields eksplisit.

Broken Authentication & Property-Level Issues

Varian API-specific: token tanpa expiry, endpoint debug (/api/debug, /actuator) terekspos produksi, dan respons yang membocorkan properti sensitif (password_hash ikut ter-serialize). Untuk kasus terakhir, serializer per-endpoint dengan allowlist properti adalah jawabannya — jangan pernah serialize model ORM mentah.

Warning

Dokumentasi OpenAPI/Swagger yang terekspos publik adalah peta harta karun bagi penyerang: semua endpoint, parameter, dan kadang contoh kredensial. Jika harus publik, pastikan tidak ada environment production di dalamnya; idealnya proteksi dengan auth.

Praktik: Testing API Secara Sistematis

Metodologi lima langkah yang saya pakai saat review API baru:

1. Petakan surface dari dokumentasi/kontrak

Ekstrak daftar endpoint dari OpenAPI
jq -r '.paths | keys[]' openapi.json | sort

Endpoint yang ada di kode tapi tidak ada di kontrak = shadow API — temuan tersendiri.

2. Uji autentikasi: panggil semua endpoint tanpa token, token expired, token scope salah. Semua harus 401/403, bukan 500.

3. Uji otorisasi objek: replay seluruh collection dengan token akun A namun ID resource akun B.

4. Uji input boundary: tipe salah, nilai ekstrem, field tambahan (mass assignment), content-type aneh.

Uji cepat BOLA dengan dua konteks token
curl -s -H "Authorization: Bearer $TOKEN_A" https://api.example.com/v1/orders/$ORDER_ID_B -o /dev/null -w "%{http_code}\n"
# Harapkan: 403 atau 404 — bukan 200

5. Uji abuse logic: rate limit benar-benar bekerja? Refund bisa dipanggil dua kali? Nilai negatif diterima?

Untuk regresi, simpan semua skenario ini sebagai collection Postman/Bruno atau test HTTP file di repo — dan jalankan sebagai integration security test di CI (episode 11).

Tip

Bruno/Postman collection dengan skrip test assertion 401/403 adalah versi murah dari DAST API. Satu sore menyusunnya memberi perlindungan regresi otorisasi permanen untuk tim kalian.

Common Pitfalls

  • "API kami internal kok": internal network bukan zona aman — SSRF, compromised container, dan insider tetap sampai ke sana.
  • Versioning sebagai patch security: membiarkan /v1 rentan hidup karena "masih ada klien" adalah utang berbunga; tetapkan sunset date.
  • Error message developer-friendly: stack trace di JSON response membantu penyerang memetakan stack teknologi kalian.
  • Mengandalkan gateway saja: API gateway menutup autentikasi kasar, tapi object-level authorization hanya bisa dieksekusi di kode yang tahu business logic.

Penutup

Inti yang harus dibawa pulang:

  • API butuh granularitas: scope per endpoint, object-level authorization per request, DTO whitelist anti mass assignment.
  • Rate limiting berlapis: edge untuk volume, gateway untuk identitas, app layer untuk aksi sensitif.
  • BOLA adalah temuan API nomor satu — dan paling mudah diotomasi pengujinya.
  • Testing API sistematis: petakan, uji AuthN, uji AuthZ antar-akun, uji boundary, uji abuse logic — lalu jadikan regresi otomatis.

Di episode 7 kita mulai fase tooling: SAST & Static Analysis — bagaimana mesin membaca kode untuk menemukan kerentanan, cara menulis rule Semgrep sendiri, dan integrasinya ke pull request tanpa membanjiri developer false positive. Sampai jumpa di episode 7!

Belajar Application Security Engineer - API Security | Belajar Application Security Engineer