Cara paling efektif untuk mencegah SQL Injection (SQLi) dalam aplikasi Python adalah dengan tidak pernah menggabungkan string secara langsung ke dalam kueri SQL. Anda wajib menggunakan parameterisasi kueri (parameterized queries) atau menggunakan Object-Relational Mapping (ORM) yang secara otomatis menangani escaping karakter berbahaya.
SQL Injection terjadi ketika input dari pengguna dieksekusi langsung oleh database sebagai bagian dari perintah SQL. Hal ini memungkinkan penyerang memanipulasi logika kueri untuk mengambil, mengubah, atau menghapus data sensitif. Di Python, pustaka database populer seperti sqlite3, psycopg2 (PostgreSQL), dan mysql-connector sudah menyediakan mekanisme parameterisasi bawaan.
Metode Pencegahan SQL Injection di Python
Berikut adalah tabel perbandingan metode penulisan kueri SQL di Python antara yang rentan dan yang aman dari celah keamanan:
| Metode | Status Keamanan | Contoh Kode Python |
|---|---|---|
| String Formatting / F-String | Sangat Rentan (Bahaya) | cursor.execute(f"SELECT * FROM users WHERE name = '{user_input}'") |
| Parameterized Queries | Aman | cursor.execute("SELECT * FROM users WHERE name = %s", (user_input,)) |
| ORM (SQLAlchemy) | Aman | session.query(User).filter(User.name == user_input).all() |
1. Menggunakan Parameterized Queries (Prepared Statements)
Saat menggunakan driver database standar Python, pisahkan antara struktur kueri SQL dan nilai input menggunakan placeholder (tanda tanya ? atau persen %s tergantung driver yang digunakan). Driver akan memperlakukan input pengguna secara ketat sebagai data mentah, bukan sebagai perintah eksekusi.
import sqlite3
# Koneksi ke database SQLite
conn = sqlite3.connect('database.db')
cursor = conn.cursor()
# Input dari pengguna (misalnya dari form web)
username_input = "admin' --"
# AMAN: Menggunakan parameter tuple
cursor.execute("SELECT * FROM users WHERE username = ?", (username_input,))
result = cursor.fetchall()
conn.close()
Perhatikan bahwa pada kode di atas, meskipun username_input berisi karakter injeksi SQL (' --), database akan mencari string harfiah tersebut dan tidak mengeksekusinya sebagai perintah logika SQL.
2. Menggunakan ORM (Object-Relational Mapping)
Sebagian besar kerangka kerja web modern di Python seperti Django dan Flask menggunakan ORM secara default. ORM secara otomatis mengabstraksi pembuatan kueri SQL menggunakan parameterisasi di baliknya, sehingga meminimalkan risiko kesalahan manusia dalam penulisan kueri mentah.
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy()
class User(db.Model):
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(80))
# AMAN: SQLAlchemy otomatis melakukan escaping pada input
user_input = "test_user"
user = User.query.filter_by(username=user_input).first()
3. Validasi dan Sanitasi Tipe Data
Selain menggunakan parameterisasi, lakukan validasi tipe data di sisi aplikasi sebelum data dikirim ke database. Jika sebuah kolom mengharapkan integer (angka), pastikan input divalidasi menggunakan fungsi int() di Python.
# Contoh validasi input numerik
raw_input_id = "1 OR 1=1"
try:
secure_id = int(raw_input_id)
except ValueError:
raise Exception("Input tidak valid, harus berupa angka!")
# Lanjutkan query dengan secure_id yang sudah pasti integer
Tips Keamanan Tambahan di Lapangan
- Prinsip Hak Akses Minimum (Least Privilege): Pastikan akun database yang digunakan oleh aplikasi Python hanya memiliki izin yang diperlukan (misalnya SELECT, INSERT, UPDATE) dan tidak memiliki hak akses administratif seperti DROP TABLE atau GRANT.
- Hindari Penggunaan
cursor.executescript(): Jangan pernah menggunakan fungsi eksekusi skrip massal untuk data yang dikendalikan oleh pengguna, karena fungsi ini memungkinkan eksekusi banyak pernyataan SQL sekaligus yang dipisahkan titik koma. - Gunakan Pemindai Keamanan: Jalankan static code analysis seperti
Banditpada proyek Python Anda untuk mendeteksi potensi penggunaan kueri mentah yang tidak aman secara otomatis sebelum deployment.