Belajar Backend Developer - Security Backend
Episode 17 of 28

Belajar Backend Developer - Security Backend

Mengamankan backend berlapis: memahami OWASP Top 10 yang relevan untuk API, menerapkan input validation dan rate limiting sebagai pertahanan dasar, serta mengelola secrets dengan benar agar kredensial tidak pernah bocor

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

Pendahuluan

Di episode 7 kalian membangun autentikasi, dan di episode 0-16 banyak kredensial melintas — database, registry, cloud, dan email. Sekarang saatnya melihat keamanan sebagai sistem menyeluruh, bukan sekumpulan trik. Attack surface backend sangat luas: input dari user, koneksi ke database, integrasi pihak ketiga, dan konfigurasi cloud.

Mengapa security penting bagi backend developer? Karena backend adalah tempat data berharga dan pintu masuk sistem. 90% serangan yang tercatat menyerang aplikasi web/API, dan sebagian besar bisa dicegah dengan disiplin dasar. Episode ini membangun lapisan pertahanan inti: OWASP Top 10, input validation, rate limiting, dan pengelolaan secrets.

OWASP Top 10 yang Relevan untuk API

OWASP Top 10 adalah daftar risiko keamanan aplikasi web paling kritis yang diperbarui berkala. Yang paling sering menyerang API backend:

PeringkatRisikoKaitannya dengan backend
A01Broken Access ControlOtorisasi lemah (IDOR — episode 18)
A02Cryptographic FailuresSecrets bocor, enkripsi salah (episode 19)
A03InjectionSQL injection (episode 18)
A04Insecure DesignLogika bisnis lemah
A05Security MisconfigurationHeader salah, debug terbuka, CORS longgar
A06Vulnerable ComponentsDependency tidak di-update
A07Auth FailuresSesuai episode 7
A08Software/Data IntegritySupply chain, dependency
A09Logging FailuresSesuai episode 11
A10SSRFServer memanggil URL dari user (episode 18)

Episode 17-18 membahas poin-poin ini secara praktis.

Input Validation: Pertahanan Pertama

Aturan emas backend: jangan pernah percaya input dari client. Setiap field yang masuk harus divalidasi — tipe, format, rentang, dan panjang. Tanpa validasi, input menjadi pintu masuk injection dan logika rusak.

Validasi dengan Zod
import { z } from "zod"
 
const createProductSchema = z.object({
  name: z.string().min(1).max(255),
  price: z.number().positive(),
  stock: z.number().int().nonnegative(),
  category: z.enum(["electronics", "accessories", "books"]),
})
 
const createOrderSchema = z.object({
  items: z.array(z.object({
    productId: z.number().int().positive(),
    qty: z.number().int().min(1).max(100),
  })).min(1),
})
 
router.post("/v1/products", async (req, res, next) => {
  const parsed = createProductSchema.safeParse(req.body)
  if (!parsed.success) {
    return res.status(400).json({
      error: "VALIDATION_FAILED",
      message: "Body tidak valid",
      details: parsed.error.issues,
    })
  }
  const product = await createProduct(parsed.data)
  res.status(201).json({ data: product })
})

Prinsip validasi:

  • Validasi di batas sistem — setiap request masuk wajib melewati schema.
  • Jangan pernah memakai input mentah (req.body langsung) di query.
  • Format error konsisten dengan episode 4.

Note

Validasi bukan hanya soal injection — data yang salah bentuk (harga negatif, qty nol) merusak logika bisnis diam-diam. Schema validation seperti Zod menangkap keduanya sekaligus. Ini juga alasan framework seperti FastAPI menyediakan validasi bawaan (Pydantic) — pakai itu, jangan tulis manual.

SQL Injection dan Parameterized Query

Salah satu serangan tertua yang masih membunuh sampai sekarang: SQL injection — memasukkan kode SQL lewat input. Contoh yang rentan:

RENTAN - jangan pernah begini
const { rows } = await db.query(
  `SELECT * FROM products WHERE name = '${req.query.q}'`,
)

Jika q berisi ' OR '1'='1, query menjadi WHERE name = '' OR '1'='1' — semua produk terbaca. Perbaikan: parameterized query — nilai dikirim terpisah dari query, sehingga tidak pernah dieksekusi sebagai SQL.

Aman - parameterized query
const { rows } = await db.query(
  `SELECT * FROM products WHERE name = $1`,
  [req.query.q],
)

$1 adalah placeholder; driver mengirim nilainya sebagai data, bukan sebagai SQL. Aturan: semua query dengan input user wajib parameterized — tanpa kecuali, termasuk LIKE, IN, dan ORDER BY (yang terakhir divalidasi dengan whitelist kolom, bukan dimasukkan mentah).

Security Headers dan Konfigurasi

Banyak serangan dicegah cukup dengan header HTTP yang benar:

Security headers dasar
res.set("X-Content-Type-Options", "nosniff")
res.set("X-Frame-Options", "DENY")
res.set("Referrer-Policy", "no-referrer")
res.set("Content-Security-Policy", "default-src 'none'")

Di Express, pakai library helmet yang menyetel semua header ini sekaligus:

helmet - header aman otomatis
import helmet from "helmet"
app.use(helmet())

Konfigurasi lain yang wajib:

  • CORS dibatasi ke domain yang dikenal — bukan * untuk API berauth.
  • Debug mode off di produksi (error detail bocor = intel penyerang).
  • Hapus header versi server yang memberi tahu penyerang stack kita.

Rate Limiting

Rate limiting membatasi berapa banyak request dalam satu jendela waktu — pertahanan terhadap brute-force dan DoS. Di episode 20 kita bahas lengkap; intinya di sini:

Rate limit dasar
import { rateLimit } from "express-rate-limit"
 
const limiter = rateLimit({
  windowMs: 60 * 1000,
  limit: 100,
  standardHeaders: "draft-7",
  legacyHeaders: false,
  message: { error: "TOO_MANY_REQUESTS", message: "Terlalu banyak request" },
})
 
app.use(limiter)

Tanpa rate limit, endpoint login bisa dicoba jutaan kali, dan satu script bisa membanjiri server.

Secrets Management

Kredensial — DATABASE_URL, JWT_SECRET, AWS_ACCESS_KEY — adalah target utama penyerang. Aturan pengelolaan:

1. Jangan Pernah di Kode

Secrets tidak boleh di source code, tidak di commit, tidak di Dockerfile (episode 14). Selalu lewat environment variable.

Baca secret dari environment
const jwtSecret = process.env.JWT_SECRET
if (!jwtSecret) {
  throw new Error("JWT_SECRET tidak diatur")
}

2. Gunakan Secret Manager di Produksi

Environment variable di server masih bisa bocor lewat log/config. Untuk produksi, gunakan Secret Manager (AWS Secrets Manager, GCP Secret Manager, Vault):

Simpan dan ambil secret di cloud
aws secretsmanager create-secret --name shop/jwt --secret-string "..." 
aws secretsmanager get-secret-value --secret-id shop/jwt --query SecretString

3. Rotasi dan Least Privilege

  • Rotasi berkala — secret lama dicabut setelah diganti.
  • Least privilege — beri akses seminimal mungkin: user database hanya untuk database itu, IAM role hanya untuk service yang butuh.

Warning

Secret yang sudah pernah bocor (ter-commit lalu dihapus) tetap berbahaya — git history masih menyimpannya. Segera rotasi secret tersebut, bukan sekadar menghapus dari kode. Cek kebocoran dengan tools seperti gitleaks di pipeline CI (episode 15) agar secret tidak pernah masuk history sejak awal.

Praktik: Hardening Checklist API

Terapkan checklist ini pada API toko online:

  • Input divalidasi dengan schema (Zod) di semua endpoint.
  • Semua query pakai parameterized statement.
  • Security headers via helmet.
  • CORS terbatas ke domain yang dikenal.
  • Rate limit global + khusus login.
  • Secrets di environment/Secret Manager, bukan kode.
  • Debug mode off; error detail hanya di log (episode 11).
  • Dependency rutin di-update (episode 19 soal supply chain).

Common Pitfalls

Validasi Hanya di Frontend

Frontend bisa dilewati siapa saja. Validasi harus selalu ada di backend.

Trust Input untuk Query

Input mentah di query = SQL injection. Parameterized selalu.

CORS * untuk API Ber-Auth

Access-Control-Allow-Origin: * berarti situs mana pun bisa memanggil API dari browser user yang sedang login. Batasi ke origin yang dikenal.

Secret di Repository

Sekali bocor, selamanya berisiko. Rotasi dan gitleaks di CI.

Penutup

Episode 17 membangun pertahanan inti: peta OWASP Top 10 untuk API, input validation dengan schema, parameterized query melawan SQL injection, security headers, rate limiting, dan pengelolaan secrets yang disiplin.

Inti yang harus dibawa pulang:

  • OWASP Top 10 adalah peta risiko; akses kontrol, injection, dan misconfig paling sering menyerang API.
  • Jangan pernah percaya input — validasi dengan schema di batas sistem.
  • Semua query dengan input user wajib parameterized.
  • Security headers + CORS terbatas + rate limit = dasar hardening.
  • Secrets: bukan di kode, bukan di git, rotasi jika bocor.

Di episode 18 selanjutnya kita akan mendalami tiga serangan paling berbahaya: web security lanjutan — SQL injection, IDOR, dan SSRF, lengkap dengan cara menemukan dan menambalnya. Sampai jumpa di episode 18!

Belajar Backend Developer - Security Backend | Belajar Backend