Memahami cara kerja SAST dari taint analysis hingga rule engine, menulis rule Semgrep kustom untuk pola berbahaya di codebase tim, membandingkan Semgrep vs CodeQL, dan mengintegrasikan semuanya ke pull request dengan rasio false positive yang tetap manusiawi

Setelah di episode 6 kita mengamankan API, kita mulai fase tooling series ini: SAST (Static Application Security Testing) — analisis kode sumber tanpa menjalankannya untuk menemukan kerentanan. Mengapa SAST jadi tulang punggung AppSec modern? Karena ia satu-satunya teknik yang bisa berjalan di setiap commit, dalam hitungan menit, sebelum kode menyentuh build mana pun. Ini mesin utama shift-left.
Tapi SAST juga punya reputasi bermasalah: false positive berlebihan membuat developer mematikannya. Episode ini mengajarkan cara kerjanya sampai level rule agar kalian bisa menyetir tool-nya, bukan sekadar menjalankan.
Ada dua generasi teknologi di balik SAST:
Tool mencocokkan pola sintaksis berbahaya — mirip grep yang sadar-AST. Cepat, murah, mudah ditulis ulang, tapi buta terhadap aliran data antar file. Contoh klasik yang terlewat: source dari req.body di file A, sink exec() di file B.
Mesin membangun graf aliran data dan melacak perjalanan source → sink:
SOURCE : input tak terpercaya → req.body, req.query, env eksternal
SINK : operasi berbahaya → exec(), db.query(), innerHTML, redirect()
SANITIZER : pembersih di jalur → parameterized binding, escape, allowlist checkTemuan hanya dilaporkan jika data tercemar mencapai sink tanpa melewati sanitizer. Inilah yang membuat hasilnya jauh lebih relevan — dan inilah inti CodeQL serta mode dataflow Semgrep.
Note
Analogi sederhana: pattern matching adalah detektif yang curiga pada semua orang bertopi hitam; taint analysis adalah detektif yang mengikuti jejak dari rumah korban sampai ke pelaku. Keduanya berguna, tapi yang kedua yang bisa dipercaya untuk kasus kompleks.
Semgrep adalah pilihan default saya untuk tim karena rule-nya ditulis dalam sintaks yang nyaris identik dengan bahasa target — tidak perlu belajar DSL baru:
rules:
- id: express-child-process-user-input
languages: [javascript, typescript]
message: User input flows into child_process.exec — potential command injection
severity: ERROR
metadata:
cwe: "CWE-78: OS Command Injection"
owasp: "A03: Injection"
mode: taint
pattern-sources:
- pattern: $REQ.body
- pattern: $REQ.query
- pattern: $REQ.params
pattern-sinks:
- pattern: exec($DATA, ...)
- pattern: $CHILD.exec($DATA, ...)Jalankan secara lokal — developer bisa memakai tool yang sama persis dengan CI:
semgrep scan --config auto --config .semgrep/ .
semgrep scan --config p/owasp-top-ten --config p/secrets .Ruleset komunitas (p/owasp-top-ten, p/security-audit, p/typescript) memberi cakupan instan; rule kustom tim menangkap pola spesifik framework internal kalian — misalnya helper DB internal yang ternyata menerima raw query.
CodeQL memperlakukan kode sebagai database yang bisa di-query. Lebih lambat dan kurva belajarnya lebih tinggi, tetapi kemampuannya lintas-repository dan sangat presisi:
import javascript
from EvalInvocation eval, DataFlow::PathNode src
where
src.getNode() instanceof ActiveThreatModelSource and
eval.flowTo(src)
select eval, "User input reaches eval() — risk of RCE."Kapan pakai yang mana? Praktik umum di industri:
| Kriteria | Semgrep | CodeQL |
|---|---|---|
| Kecepatan per PR | Detik–menit | Menit–puluhan menit |
| Penulisan rule custom | Sangat mudah | Butuh latihan QL |
| Deep interprocedural | Mode taint baik | Terbaik |
| Biaya | OSS gratis | Gratis di public repo |
Banyak organisasi matang memakai keduanya: Semgrep di setiap PR, CodeQL sebagai scan mingguan mendalam.
Nilai SAST ada di tempat temuan muncul: pull request, bukan dashboard yang tidak pernah dibuka. Pola GitHub Actions minimal:
name: SAST
on:
pull_request:
jobs:
semgrep:
runs-on: ubuntu-latest
container:
image: semgrep/semgrep
steps:
- uses: actions/checkout@v4
- run: semgrep ci --config auto --config .semgrep/
env:
SEMGREP_RULES: p/owasp-top-ten p/secretsDua prinsip agar integrasinya diterima developer:
Tip
Tambahkan Semgrep ke pre-commit hook dengan scope file yang di-stage saja. Menemukan injection saat mengetik jauh lebih murah daripada menemukannya di review PR — itulah shift-left yang sesungguhnya.
Rasio temuan valid adalah nyawa program SAST. Di bawah ±50% precision, developer mulai menandai semua alert sebagai noise. Strategi pengelolaannya:
// nosemgrep: rule-id) dengan alasan tertulis; suppress tanpa alasan = utang.pattern-inside atau kondisi sanitizer agar rule hanya bunyi pada konteks benar-benar berbahaya.Inti yang harus dibawa pulang:
Di episode 8 kita pindah ke sisi dinamis: DAST & Dynamic Testing — Burp Suite dan OWASP ZAP, crawling aplikasi nyata, authenticated scanning, dan cara membaca hasilnya tanpa salah prioritas. Sampai jumpa di episode 8!