Sedang melakukan debugging aplikasi mobile dan tidak mengerti permintaan apa yang dikirim ke server? Perlu menguji perilaku API dalam berbagai kondisi atau intercept respons dan mengganti data secara langsung? mitmproxy menyelesaikan semua tugas ini β ini adalah alat gratis dengan sumber terbuka yang memungkinkan kontrol penuh atas HTTP dan HTTPS traffic antara klien dan server.
Apa itu mitmproxy dan untuk apa pengembang membutuhkannya
mitmproxy adalah MITM proxy interaktif (Man-In-The-Middle Proxy) dengan sumber terbuka yang ditulis dalam Python. Ia berfungsi sebagai perantara antara aplikasi Anda dan server: intercept semua permintaan dan respons, memungkinkan Anda untuk melihat, mengubah, mereproduksi, dan menyimpan.
Perbedaan utama mitmproxy dari proxy server biasa adalah kemampuannya untuk bekerja dengan traffic HTTPS yang terenkripsi. Alat ini secara dinamis menghasilkan sertifikat SSL untuk setiap domain, yang memungkinkan dekripsi traffic secara langsung tanpa mengganggu fungsi aplikasi.
Berikut adalah tugas-tugas khas yang dapat diselesaikan pengembang dengan mitmproxy:
- Debugging API β melihat permintaan dan respons yang tepat, termasuk header, body, dan kode status.
- Rekayasa balik β menganalisis bagaimana aplikasi dan layanan pihak ketiga bekerja.
- Pemrograman β mengganti respons server untuk memeriksa kasus batas.
- Automasi β menulis skrip untuk memodifikasi traffic berdasarkan kondisi.
- Perekaman dan reproduksi β menyimpan sesi dan memutarnya tanpa server nyata.
- Analisis keamanan β memeriksa apakah aplikasi mengirimkan data yang tidak perlu.
Penting untuk dipahami
mitmproxy adalah alat untuk pengujian dan pengembangan yang legal. Gunakan hanya untuk menganalisis traffic aplikasi yang Anda kembangkan atau memiliki hak untuk mengujinya. Mengintercept traffic orang lain tanpa izin melanggar hukum.
Alat ini tersedia dalam tiga varian: antarmuka interaktif konsol mitmproxy, antarmuka web mitmweb, dan utilitas baris perintah mitmdump. Ketiga alat ini menggunakan satu inti dan mendukung skrip Python.
Instalasi mitmproxy di Windows, macOS, dan Linux
mitmproxy dapat diinstal dengan beberapa cara. Kami merekomendasikan menggunakan pip β ini memastikan versi terbaru dan pembaruan yang mudah.
Instalasi melalui pip (cara universal)
Diperlukan Python 3.9 atau lebih baru. Periksa versi Python:
python --version
# atau
python3 --version
Instal mitmproxy:
pip install mitmproxy
Setelah instalasi, periksa:
mitmproxy --version
# Harus menampilkan: mitmproxy 10.x.x
Instalasi melalui manajer paket
macOS (Homebrew):
brew install mitmproxy
Linux (Ubuntu/Debian):
sudo apt install mitmproxy
# atau melalui snap untuk versi terbaru:
sudo snap install mitmproxy
Windows: Unduh installer dari situs resmi mitmproxy.org atau gunakan pip di PowerShell dengan hak administrator.
Menjalankan dan pemeriksaan dasar
Secara default, mitmproxy mendengarkan di port 8080. Jalankan antarmuka web untuk memulai:
# Menjalankan antarmuka web di port 8080
mitmweb
# Menjalankan di port lain
mitmweb --listen-port 9090
# Antarmuka konsol
mitmproxy
Setelah menjalankan mitmweb, buka browser di alamat http://127.0.0.1:8081 β ini adalah antarmuka web untuk melihat traffic. Proxy itu sendiri berjalan di port 8080.
Konfigurasi sertifikat SSL untuk intercept HTTPS
Intercept traffic HTTPS memerlukan instalasi sertifikat root mitmproxy di sistem atau browser. Tanpa langkah ini, browser akan menunjukkan peringatan tentang koneksi yang tidak aman, dan banyak aplikasi akan menolak untuk berfungsi.
Bagaimana cara kerjanya secara teknis
Saat pertama kali menjalankan mitmproxy, ia secara otomatis membuat sertifikat CA root dan menyimpannya di direktori ~/.mitmproxy/. Ketika klien terhubung ke situs HTTPS melalui proxy, mitmproxy secara langsung menghasilkan sertifikat untuk domain ini, menandatanganinya dengan CA-nya. Klien mempercayai sertifikat ini jika CA ditambahkan ke daftar yang dipercaya β dan dekripsi terjadi secara transparan.
Instalasi sertifikat di sistem
Sertifikat berada di ~/.mitmproxy/:
mitmproxy-ca-cert.pemβ untuk Linux/macOSmitmproxy-ca-cert.cerβ untuk Windowsmitmproxy-ca-cert.p12β untuk iOS
macOS:
sudo security add-trusted-cert -d -r trustRoot \
-k /Library/Keychains/System.keychain \
~/.mitmproxy/mitmproxy-ca-cert.pem
Linux (Ubuntu/Debian):
sudo cp ~/.mitmproxy/mitmproxy-ca-cert.pem \
/usr/local/share/ca-certificates/mitmproxy.crt
sudo update-ca-certificates
Windows: Klik dua kali pada file mitmproxy-ca-cert.cer β βInstal Sertifikatβ β βKomputer Lokalβ β βPusat Sertifikasi Root yang Dipercayaβ.
Instalasi di browser Firefox
Firefox menggunakan penyimpanan sertifikatnya sendiri. Pergi ke: Pengaturan β Privasi dan Keamanan β Sertifikat β Lihat Sertifikat β Pusat Sertifikasi β Impor. Pilih file mitmproxy-ca-cert.pem dan centang βPercayakan saat mengidentifikasi situs webβ.
Memeriksa kerja
Atur browser untuk menggunakan proxy 127.0.0.1:8080 dan buka situs HTTPS mana pun. Di antarmuka mitmweb, Anda harus melihat traffic yang terdekripsi. Sebagai alternatif β buka http://mitm.it melalui proxy yang telah diatur: mitmproxy akan menunjukkan instruksi untuk menginstal sertifikat untuk platform Anda.
Tiga antarmuka: mitmproxy, mitmweb, dan mitmdump
Paket mitmproxy mencakup tiga utilitas dengan antarmuka berbeda untuk skenario kerja yang berbeda. Memahami perbedaan ini akan membantu Anda memilih alat yang tepat untuk setiap tugas.
| Utilitas | Antarmuka | Kapan digunakan | Fitur |
|---|---|---|---|
mitmproxy |
TUI Konsol | Debugging interaktif di terminal | Membutuhkan terminal dengan dukungan warna, filter yang kuat |
mitmweb |
Browser web | Analisis visual traffic | UI yang ramah, dukungan filter, ekspor |
mitmdump |
CLI (stdout) | Skrip, CI/CD, automasi | Tanpa interaktivitas, output ke file atau pipe |
Flag berguna untuk menjalankan
# Merekam traffic ke file
mitmdump -w traffic.dump
# Memutar ulang traffic yang direkam
mitmdump -r traffic.dump
# Filter: hanya permintaan ke domain tertentu
mitmproxy --filter "~d api.example.com"
# Menjalankan dalam mode transparent proxy
mitmproxy --mode transparent
# Menjalankan sebagai upstream proxy (rantai proxy)
mitmproxy --mode upstream:http://upstream-proxy:8080
# Menentukan port tertentu
mitmweb --listen-port 9090 --web-port 9091
# Menjalankan dengan skrip
mitmproxy -s my_script.py
Sintaks filter mitmproxy
mitmproxy mendukung bahasa filter yang kuat untuk memilih permintaan yang diinginkan:
# ~d β filter berdasarkan domain
~d api.example.com
# ~u β filter berdasarkan URL (regex)
~u /api/v2/users
# ~m β filter berdasarkan metode HTTP
~m POST
# ~s β hanya respons
~s ~c 404
# ~c β filter berdasarkan kode status
~c 500
# Kombinasi (AND)
~d api.example.com & ~m POST
# Kombinasi (OR)
~c 404 | ~c 500
# NOT
!~d static.example.com
Penulisan skrip Python: intercept dan modifikasi traffic
Skrip adalah kekuatan super utama mitmproxy. Dengan mereka, Anda dapat secara otomatis mengubah permintaan dan respons, mencatat data dalam format yang diinginkan, mensimulasikan kesalahan server, dan banyak lagi. Skrip ditulis dalam Python dan menggunakan model berbasis acara.
Peristiwa utama (hooks)
| Hook | Kapan dipanggil | Objek |
|---|---|---|
request |
Permintaan diterima dari klien | flow.request |
response |
Respons diterima dari server | flow.response |
error |
Kesalahan koneksi | flow.error |
tls_start_client |
Awal handshake TLS dengan klien | tls_start |
Contoh 1: mencatat permintaan ke file
# logger.py
import mitmproxy.http
import json
from datetime import datetime
def request(flow: mitmproxy.http.HTTPFlow) -> None:
"""Mencatat setiap permintaan ke file JSON."""
log_entry = {
"timestamp": datetime.now().isoformat(),
"method": flow.request.method,
"url": flow.request.pretty_url,
"headers": dict(flow.request.headers),
"body": flow.request.text if flow.request.text else None
}
with open("requests.log", "a") as f:
f.write(json.dumps(log_entry, ensure_ascii=False) + "\n")
def response(flow: mitmproxy.http.HTTPFlow) -> None:
"""Mencatat respons dengan kode kesalahan."""
if flow.response.status_code >= 400:
print(f"[ERROR] {flow.request.method} {flow.request.pretty_url} "
f"-> {flow.response.status_code}")
Menjalankan skrip:
mitmproxy -s logger.py
Contoh 2: modifikasi permintaan β mengganti header
# modify_headers.py
from mitmproxy import http
def request(flow: http.HTTPFlow) -> None:
"""Mengganti User-Agent dan menambahkan header kustom."""
if "api.example.com" in flow.request.pretty_host:
# Mengganti User-Agent
flow.request.headers["User-Agent"] = (
"Mozilla/5.0 (iPhone; CPU iPhone OS 17_0 like Mac OS X) "
"AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.0 Mobile/15E148 Safari/604.1"
)
# Menambahkan header otorisasi
flow.request.headers["X-Custom-Token"] = "test-token-12345"
# Menghapus header
if "X-Debug-Info" in flow.request.headers:
del flow.request.headers["X-Debug-Info"]
Contoh 3: mengganti respons server (mock)
# mock_response.py
from mitmproxy import http
import json
def request(flow: http.HTTPFlow) -> None:
"""Mengintercept permintaan dan mengembalikan respons mock, tanpa menghubungi server."""
if flow.request.pretty_url.endswith("/api/v1/user/profile"):
# Membuat respons mock
mock_data = {
"id": 42,
"name": "Test User",
"email": "[email protected]",
"premium": True # Menguji fungsi premium
}
flow.response = http.Response.make(
200, # Kode status
json.dumps(mock_data), # Body respons
{"Content-Type": "application/json"} # Header
)
def response(flow: http.HTTPFlow) -> None:
"""Modifikasi respons nyata dari server."""
if "/api/v1/products" in flow.request.pretty_url:
try:
data = json.loads(flow.response.text)
# Menambahkan field ke setiap produk
for product in data.get("items", []):
product["debug_info"] = "intercepted"
flow.response.text = json.dumps(data)
except (json.JSONDecodeError, KeyError):
pass
Contoh 4: mensimulasikan koneksi lambat dan kesalahan
# chaos_testing.py
from mitmproxy import http
import time
import random
def response(flow: http.HTTPFlow) -> None:
"""Rekayasa chaos: penundaan acak dan kesalahan untuk pengujian."""
# Menambahkan penundaan acak dari 0 hingga 2 detik
if "api.example.com" in flow.request.pretty_host:
delay = random.uniform(0, 2.0)
time.sleep(delay)
# 10% kemungkinan respons 503
if random.random() < 0.1:
flow.response = http.Response.make(
503,
json.dumps({"error": "Service Unavailable"}),
{"Content-Type": "application/json"}
)
Intercept traffic aplikasi mobile
Analisis traffic aplikasi mobile adalah salah satu tugas yang paling umum saat menggunakan mitmproxy. Ini sangat berguna saat melakukan rekayasa balik API aplikasi mobile atau menguji aplikasi Anda sendiri di perangkat nyata.
Pengaturan di Android
Langkah 1. Pastikan ponsel dan komputer berada di jaringan Wi-Fi yang sama.
Langkah 2. Jalankan mitmproxy di komputer:
mitmweb --listen-host 0.0.0.0 --listen-port 8080
Langkah 3. Di Android: Pengaturan β Wi-Fi β tahan jaringan β Ubah jaringan β Tambahan β Proxy β Manual. Masukkan IP komputer dan port 8080.
Langkah 4. Instal sertifikat di Android: buka browser di perangkat, pergi ke http://mitm.it dan unduh sertifikat untuk Android. Kemudian: Pengaturan β Keamanan β Instal sertifikat β Sertifikat CA.
Android 7+ dan Certificate Pinning
Mulai dari Android 7.0, aplikasi secara default tidak mempercayai sertifikat CA pengguna. Untuk intercept traffic aplikasi tersebut, diperlukan akses root atau modifikasi network_security_config.xml dalam APK. Untuk aplikasi dengan SSL Pinning, gunakan Frida atau Xposed Framework untuk melewati pemeriksaan sertifikat.
Pengaturan di iOS
Langkah 1. Atur proxy sama seperti di Android: Pengaturan β Wi-Fi β tekan (i) di samping jaringan β Atur proxy β Manual.
Langkah 2. Buka Safari dan pergi ke http://mitm.it β unduh sertifikat untuk iOS.
Langkah 3. Instal profil: Pengaturan β Profil yang diunduh β Instal.
Langkah 4. Aktifkan kepercayaan pada sertifikat: Pengaturan β Umum β Tentang β Kepercayaan sertifikat β aktifkan saklar untuk mitmproxy.
Intercept traffic aplikasi tertentu melalui Python
# mobile_app_analyzer.py
from mitmproxy import http
import json
import re
# Domain aplikasi yang menarik
TARGET_DOMAINS = ["api.myapp.com", "cdn.myapp.com"]
def response(flow: http.HTTPFlow) -> None:
"""Menganalisis traffic aplikasi mobile."""
host = flow.request.pretty_host
if not any(domain in host for domain in TARGET_DOMAINS):
return
# Mengekstrak respons JSON
content_type = flow.response.headers.get("content-type", "")
if "application/json" in content_type:
try:
data = json.loads(flow.response.text)
print(f"\n{'='*60}")
print(f"URL: {flow.request.pretty_url}")
print(f"Status: {flow.response.status_code}")
print(f"Response: {json.dumps(data, indent=2, ensure_ascii=False)}")
except json.JSONDecodeError:
pass
# Mencari token di header permintaan
auth_header = flow.request.headers.get("authorization", "")
if auth_header:
print(f"[AUTH] Token ditemukan: {auth_header[:50]}...")
Rantai proxy: mitmproxy + upstream-proxy
Salah satu skenario yang kuat adalah menggunakan mitmproxy bersama dengan proxy server eksternal. Ini memungkinkan Anda untuk secara bersamaan intercept dan menganalisis traffic (melalui mitmproxy) dan mengarahkannya melalui alamat IP eksternal (melalui upstream-proxy). Skema ini digunakan saat menguji API yang bergantung pada lokasi geografis atau saat mengembangkan aplikasi yang harus berfungsi melalui proxy.
Mode upstream proxy
# Mengarahkan semua traffic melalui upstream HTTP-proxy
mitmproxy --mode upstream:http://proxy-host:port
# Upstream SOCKS5 proxy
mitmproxy --mode upstream:socks5://proxy-host:port
# Dengan otentikasi
mitmproxy --mode upstream:http://user:password@proxy-host:port
# Melalui mitmweb dengan upstream
mitmweb --mode upstream:http://proxy-host:port
Dalam mode ini, mitmproxy menerima permintaan secara lokal, mendekripsi HTTPS, memberi Anda kesempatan untuk menganalisis dan memodifikasinya, dan kemudian meneruskannya melalui proxy eksternal. Ini sangat berguna saat menguji API yang hanya tersedia dari wilayah tertentu.
Untuk tugas semacam itu, proxy residensial sangat cocok β mereka memiliki alamat IP nyata dari pengguna rumah di negara yang dibutuhkan, yang memungkinkan pengujian respons API yang bergantung pada lokasi dengan benar.
Pemilihan upstream-proxy dinamis dalam skrip
# dynamic_upstream.py
from mitmproxy import http
from mitmproxy.net.server_spec import ServerSpec
# Daftar proxy untuk rotasi
PROXY_LIST = [
"http://proxy1.example.com:8080",
"http://proxy2.example.com:8080",
"http://proxy3.example.com:8080",
]
proxy_index = 0
def request(flow: http.HTTPFlow) -> None:
"""Rotasi upstream-proxy untuk setiap permintaan."""
global proxy_index
# Mengarahkan permintaan ke API melalui proxy yang berbeda
if "api.target.com" in flow.request.pretty_host:
proxy_url = PROXY_LIST[proxy_index % len(PROXY_LIST)]
proxy_index += 1
flow.live.change_upstream_proxy_server(
ServerSpec.from_url(proxy_url)
)
print(f"Menggunakan proxy: {proxy_url} untuk {flow.request.pretty_url}")
Proxy transparan (transparent mode)
Dalam mode transparan, aplikasi tidak tahu bahwa traffic-nya sedang diintercept β tidak perlu mengatur proxy dalam pengaturan. Ini memerlukan pengaturan iptables/pf di tingkat OS:
# Menjalankan dalam mode transparan
mitmproxy --mode transparent --listen-port 8080
# Pengaturan iptables untuk mengalihkan traffic (Linux)
sudo iptables -t nat -A OUTPUT -p tcp --dport 80 -j REDIRECT --to-port 8080
sudo iptables -t nat -A OUTPUT -p tcp --dport 443 -j REDIRECT --to-port 8080
Skenario penggunaan praktis mitmproxy
Mari kita lihat tugas-tugas konkret yang dapat diselesaikan pengembang dengan mitmproxy dalam proyek nyata.
Skenario 1: Pengujian API tanpa mengubah server
Bayangkan: Anda perlu memeriksa bagaimana frontend menangani respons dengan array data kosong atau kesalahan otorisasi 401, tetapi mereproduksinya di server pengujian sulit. mitmproxy memungkinkan Anda mengganti respons secara langsung:
# test_edge_cases.py
from mitmproxy import http
import json
def response(flow: http.HTTPFlow) -> None:
url = flow.request.pretty_url
# Tes: daftar produk kosong
if "/api/products" in url and "test_empty=1" in url:
flow.response.text = json.dumps({"items": [], "total": 0})
# Tes: token kedaluwarsa
if "/api/user" in url and "test_auth=1" in url:
flow.response = http.Response.make(
401,
json.dumps({"error": "Token expired", "code": "AUTH_001"}),
{"Content-Type": "application/json"}
)
# Tes: melebihi batas permintaan
if "/api/" in url and "test_rate=1" in url:
flow.response = http.Response.make(
429,
json.dumps({"error": "Too Many Requests", "retry_after": 60}),
{"Content-Type": "application/json",
"Retry-After": "60"}
)
Skenario 2: Merekam dan memutar ulang sesi
Berguna untuk membuat fixture pengujian atau mendemonstrasikan fungsionalitas tanpa server nyata:
# Merekam sesi ke file
mitmdump -w session.dump --filter "~d api.example.com"
# Memutar ulang sesi yang direkam (offline)
mitmdump -r session.dump
# Mengonversi ke format HAR untuk analisis
mitmdump -r session.dump --flow-detail 3 > session.txt
Skenario 3: Dokumentasi API otomatis
# api_documenter.py
from mitmproxy import http
import json
from collections import defaultdict
# Kamus untuk mengumpulkan informasi tentang endpoint
endpoints = defaultdict(lambda: {"methods": set(), "status_codes": set(),
"request_fields": set(), "response_fields": set()})
def _extract_fields(data, prefix=""):
"""Mengekstrak field dari JSON secara rekursif."""
fields = set()
if isinstance(data, dict):
for key, value in data.items():
full_key = f"{prefix}.{key}" if prefix else key
fields.add(full_key)
fields.update(_extract_fields(value, full_key))
elif isinstance(data, list) and data:
fields.update(_extract_fields(data[0], prefix))
return fields
def response(flow: http.HTTPFlow) -> None:
if "api.example.com" not in flow.request.pretty_host:
return
# Normalisasi URL (menghapus ID)
import re
path = re.sub(r'/\d+', '/{id}', flow.request.path)
endpoint = f"{flow.request.method} {path}"
ep = endpoints[endpoint]
ep["methods"].add(flow.request.method)
ep["status_codes"].add(flow.response.status_code)
# Mengekstrak field permintaan
if flow.request.text:
try:
req_data = json.loads(flow.request.text)
ep["request_fields"].update(_extract_fields(req_data))
except json.JSONDecodeError:
pass
# Mengekstrak field respons
if flow.response.text:
try:
resp_data = json.loads(flow.response.text)
ep["response_fields"].update(_extract_fields(resp_data))
except json.JSONDecodeError:
pass
def done():
"""Mengeluarkan dokumentasi saat selesai."""
print("\n=== DOKUMENTASI API ===\n")
for endpoint, info in sorted(endpoints.items()):
print(f"Endpoint: {endpoint}")
print(f" Kode status: {sorted(info['status_codes'])}")
if info["request_fields"]:
print(f" Field permintaan: {sorted(info['request_fields'])}")
if info["response_fields"]:
print(f" Field respons: {sorted(info['response_fields'])}")
print()
Skenario 4: Pengujian respons yang bergantung pada lokasi geografis
Saat mengembangkan aplikasi dengan konten regional, penting untuk memeriksa bagaimana API merespons permintaan dari negara yang berbeda. Untuk ini, mitmproxy dijalankan dalam mode upstream dengan proxy data center dari wilayah yang dibutuhkan β ini adalah cara cepat dan andal untuk mensimulasikan permintaan dari negara tertentu.
# geo_test.py
from mitmproxy import http
def response(flow: http.HTTPFlow) -> None:
"""Mencatat header dan data yang bergantung pada lokasi geografis."""
# Melihat konten apa yang dikembalikan server
geo_headers = ["cf-ipcountry", "x-country", "x-geo-country"]
for header in geo_headers:
value = flow.response.headers.get(header)
if value:
print(f"[GEO] {header}: {value} | URL: {flow.request.pretty_url}")
# Mencari penyebutan mata uang dan lokal dalam respons
if flow.response.text:
import re
currencies = re.findall(r'"currency":\s*"([A-Z]{3})"', flow.response.text)
locales = re.findall(r'"locale":\s*"([a-z]{2}-[A-Z]{2})"', flow.response.text)
if currencies:
print(f"[CURRENCY] {currencies}")
if locales:
print(f"[LOCALE] {locales}")
Skenario 5: Menggunakan mitmproxy dalam CI/CD
mitmdump sangat cocok untuk pengujian integrasi dalam pipeline CI/CD β ia dijalankan sebagai proses latar belakang, merekam traffic, dan selesai bersamaan dengan pengujian:
#!/bin/bash
# ci_test.sh
# Menjalankan mitmdump di latar belakang
mitmdump -w test_traffic.dump -s ci_assertions.py &
MITM_PID=$!
# Memberi proxy waktu untuk memulai
sleep 1
# Menjalankan pengujian dengan proxy
export HTTP_PROXY=http://127.0.0.1:8080
export HTTPS_PROXY=http://127.0.0.1:8080
pytest tests/integration/ -v
# Menghentikan mitmdump
kill $MITM_PID
# Menganalisis traffic yang direkam
mitmdump -r test_traffic.dump -s analyze_traffic.py
Skrip ci_assertions.py dapat memeriksa bahwa aplikasi tidak melakukan permintaan yang tidak perlu, tidak mengirimkan data sensitif dalam bentuk yang tidak terenkripsi, dan mematuhi kontrak API.
Skenario 6: Analisis traffic parser
Saat mengembangkan parser, mitmproxy membantu memahami permintaan apa yang dibuat browser saat memuat halaman β termasuk permintaan XHR/fetch ke API yang tidak terlihat dalam kode sumber HTML. Ini memungkinkan akses langsung ke API situs alih-alih parsing HTML. Dalam pengembangan solusi semacam itu, sering digunakan proxy residensial untuk rotasi IP, untuk menghindari pemblokiran saat mengumpulkan data.
Kesimpulan
mitmproxy adalah salah satu alat paling kuat dalam arsenal pengembang untuk bekerja dengan traffic HTTP/HTTPS. Ia menggabungkan fungsi debugger, lingkungan pengujian, dokumentator API, dan alat untuk analisis keamanan. Tiga antarmuka β konsol, web, dan CLI β mencakup semua skenario: dari debugging interaktif hingga automasi dalam CI/CD.
```