Belajar FastAPI - Security Best Practices
Episode 18 of 28

Belajar FastAPI - Security Best Practices

Mengeraskan API FastAPI dengan pertahanan berlapis: pencegahan SQLi dengan parameterized query, mitigasi XSS dan CSRF, security headers lengkap, validasi input sebagai gerbang pertama, serta audit dependency.

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

Pendahuluan

Setelah di episode 17 API kita punya error handling dan logging yang rapi, sekarang kita rangkai semuanya menjadi satu tema: keamanan. Selama 17 episode kita sudah menabur kebiasaan yang benar — validasi Pydantic, parameterized query, bcrypt, JWT — episode ini merangkumnya menjadi peta pertahanan berlapis, plus menutup celah yang belum dibahas.

Mengapa episode ini penting? Karena kebanyakan serangan tidak canggih — mereka mengeksploitasi hal-hal dasar: query yang dirangkai string, input yang tidak divalidasi, header yang hilang. Pertahanan yang benar dimulai dari menghilangkan celah dasar, bukan memasang "alarm super mahal" di atas celah yang masih terbuka.

Prinsip Pertahanan Berlapis

Keamanan bekerja berlapis — jika satu lapis tembus, lapis berikutnya masih menahan:

100%

SQL Injection: Parameterized Query

SQL Injection terjadi saat input user dirangkai langsung ke query SQL. Contoh rentan (jangan ditiru):

PythonVULNERABLE - jangan ditiru
@app.get("/items/")
def search(name: str, db: Session = Depends(get_db)) -> list:
    query = f"SELECT * FROM items WHERE name = '{name}'"
    return db.execute(text(query)).all()

Input ' OR '1'='1 akan membuat query mengembalikan seluruh tabel. Pertahanannya: selalu parameterized. Dengan SQLAlchemy ORM:

PythonAman - parameterized via ORM
from sqlalchemy import select
 
@app.get("/items/")
def search(name: str, db: Session = Depends(get_db)) -> list:
    statement = select(models.Item).where(
        models.Item.name == name
    )
    return db.execute(statement).scalars().all()

ORM where(models.Item.name == name) mengirim name sebagai parameter terikat, bukan string yang di-splice — nilai input tidak pernah ditafsirkan sebagai SQL.

Important

Aturan besi: jangan pernah menyusun query SQL dengan f-string atau +. Kalau kalian terpaksa memakai text() SQL mentah, gunakan placeholder :name + bind parameter. ORM SQLAlchemy yang kita pakai sejak episode 9 sudah aman secara default — pertahankan itu.

XSS: Jangan Percaya Output

XSS (Cross-Site Scripting) terjadi saat input user di-render sebagai HTML/JS. FastAPI sebagai pure API lebih kebal, karena ia mengirim JSON, bukan HTML. Tapi dua jalur tetap perlu dijaga:

  1. Jika kalian mengembalikan HTML (via HTMLResponse), escape semua input yang di-render.
  2. Klien frontend harus menganggap semua field JSON sebagai data, bukan HTML — tanggung jawab bersama.

Untuk input teks yang disimpan lalu ditampilkan, validasi di Pydantic membantu membatasi pola berbahaya:

PythonValidasi input teks
import re
 
from pydantic import BaseModel, field_validator
 
 
class CommentCreate(BaseModel):
    body: str
 
    @field_validator("body")
    @classmethod
    def batasi_script(cls, v: str) -> str:
        if re.search(r"<script", v, re.IGNORECASE):
            raise ValueError("teks mengandung tag terlarang")
        return v

Pola field_validator ini adalah bentuk validasi domain yang kita bangun di episode 5 — sekarang dipakai sebagai gerbang keamanan.

CSRF: Mengenal Sumber Request

CSRF mengeksploitasi cookie session: situs jahat memaksa browser korban mengirim request ke API kita dengan cookie otomatis. Mitigasi utamanya:

  • Jangan andalkan cookie untuk mutasi data; pakai Authorization header (seperti JWT kita di episode 12). Header tidak dikirim otomatis oleh browser pihak ketiga.
  • Jika cookie tetap dipakai, pasang anti-CSRF token dan verifikasi Origin/Referer.

Karena FastAPI auth kita berbasis Bearer token (bukan cookie), serangan CSRF klasik otomatis netral. Ini salah satu alasan pola episode 12 bagus.

Tip

Bonus keamanan token-vs-cookie: cek juga header Origin untuk request yang berbahaya. Middleware sederhana yang memverifikasi Origin terhadap daftar sah adalah lapis pertahanan murah yang jarang dipakai — dan cocok dengan pola middleware episode 11.

Security Headers

Header keamanan memberitahu browser cara memperlakukan response. Gunakan SecureHeadersMiddleware (library secure) atau tulis manual:

Install secure
pip install secure
PythonSecurity headers middleware
from secure import SecureHeaders
from starlette.middleware.base import BaseHTTPMiddleware
from fastapi import FastAPI, Request
 
secure_headers = SecureHeaders()
 
 
class SecurityHeadersMiddleware(BaseHTTPMiddleware):
    async def dispatch(self, request: Request, call_next):
        response = await call_next(request)
        secure_headers.set_headers(response.headers)
        return response
 
 
app = FastAPI()
app.add_middleware(SecurityHeadersMiddleware)

Header yang dihasilkan meliputi:

HeaderFungsi
X-Frame-Options: DENYCegah clickjacking
X-Content-Type-Options: nosniffCegah MIME sniffing
Content-Security-PolicyBatasi sumber script/style
Strict-Transport-SecurityPaksa HTTPS (hanya di produksi)

Semua ini gratis untuk dipasang dan menutup banyak kelas serangan browser — kombinasikan dengan CORS yang sudah benar dari episode 11.

Dependency Security

Aplikasi seaman dependensinya. Library dengan kerentanan adalah backdoor diam-diam. Audit rutin:

Audit dependency
pip install pip-audit
pip-audit

pip-audit membandingkan package terinstall dengan database CVE. Di CI (episode 24), jadikan ini langkah wajib sebelum build:

Audit sebagai gerbang CI
pip-audit -o audit.json --fail-on any

Warning

Jangan asal pip install — pin versi dependensi (atau minimal major) dan audit rutin. FastAPI, Pydantic, dan Starlette punya sejarah CVE sendiri. Kebiasaan pip freeze > requirements.txt dari episode 0 dan audit berkala adalah dua sisi dari disiplin yang sama.

Ringkasan Pertahanan Berlapis FastAPI

LapisanImplementasiEpisode
Gerbang inputPydantic model + validators5, 6
Query amanSQLAlchemy ORM parameterized9
AutentikasiOAuth2 + JWT + bcrypt12
Host & originTrustedHost, CORS, Origin check11, 18
Outputresponse_model filter7
BrowserSecurity headers18
Dependencypip-audit18

Common Pitfalls

PitfallSolusi
f-string SQLParameterized query / ORM
Validasi hanya di frontendValidasi server dengan Pydantic
Mengandalkan cookie tanpa CSRFBearer token + Authorization header
Header keamanan hilangPasang SecurityHeadersMiddleware
Deprecated library dengan CVEpip-audit rutin + pin versi

Penutup

Inti yang harus dibawa pulang:

  • SQLi: parameterized query — tidak pernah menyusun SQL dari string user.
  • XSS: escape output HTML; frontend harus memperlakukan data sebagai data.
  • CSRF: Bearer token di header menetralkan serangan cookie-based.
  • Pasang security headers dan audit dependency (pip-audit) di CI.

Di episode 19 selanjutnya kita akan membahas rate limiting & DoS protection — melindungi API dari banjir request dengan slowapi, throttling per-IP dan per-user, serta konfigurasi reverse proxy untuk mencegah DoS. Pertahanan kalian kini berlapis dari jaringan sampai aplikasi!

Belajar FastAPI - Security Best Practices | Belajar FastAPI