Apa itu Server-Side Template Injection (SSTI)?
SSTI terjadi ketika input pengguna disisipkan langsung ke dalam template engine di sisi server. Penyerang bisa mengeksekusi kode arbitrary di server melalui sintaks template.
Contoh Vulnerability
# Python Flask dengan Jinja2 — VULNERABLE
@app.route("/greet")
def greet():
name = request.args.get("name")
template = f"Hello {name}!"
return render_template_string(template)
# Serangan:
# GET /greet?name={{7*7}}
# Output: Hello 49!
# Serangan lebih lanjut:
# GET /greet?name={{config.items()}}
# Ini bisa mengekspos konfigurasi server!
Template Engine yang Rentan
- Jinja2 (Python) —
{{ }}dan{% %} - Twig (PHP) —
{{ }}dan{% %} - Freemarker (Java) —
${ }dan<# > - Handlebars (JavaScript) —
{{ }} - ERB (Ruby) —
<%= %>
Dampak SSTI
SSTI bisa berujung pada Remote Code Execution (RCE) — penyerang bisa menjalankan perintah apa pun di server:
# Jinja2 RCE payload
{{ self.__init__.__globals__.__builtins__.__import__("os").popen("id").read() }}
# Twig RCE payload
{{[\"id\"]|filter(\"system\")}}
Cara Mendeteksi SSTI
Coba masukkan ekspresi matematika sederhana di input dan lihat apakah dievaluasi:
{{7*7}}→ jika output49, kemungkinan Jinja2/Twig${7*7}→ jika output49, kemungkinan Freemarker#{7*7}→ jika output49, kemungkinan Ruby ERB
Pencegahan SSTI
- Jangan pernah menyisipkan input pengguna langsung ke template string
- Gunakan template engine dengan sandbox mode
- Gunakan static templates dan pass data sebagai variabel
- Terapkan input validation yang ketat
# Benar: gunakan variabel, bukan string interpolation
@app.route("/greet")
def greet():
name = request.args.get("name")
return render_template("greet.html", name=name)
# greet.html: Hello {{ name }}! — aman karena auto-escaped