SQL Injection: From a Broken Login Form to a Full Database Dump
Cerita gue waktu pertama kali nemu celah SQL injection di form login, gimana gue manfaatin kelemahan query database buat ngeluarin data yang seharusnya tertutup rapat, plus pelajaran buat nulis kode yang nggak gampang diretas.
Gue Masuk ke Ruang Server yang Salah
Pertama kali gue kenal yang namanya SQL injection itu bukan dari buku, bukan dari kelas, dan juga bukan dari video motivasi "jadi hacker dalam 30 hari". Gue kenalnya dari sebuah form login yang nyebelin. Waktu itu gue lagi iseng ngetes aplikasi web punya temen sendiri, aplikasi kecil buat nyatet barang di gudang. Gue coba masuk pakai username admin dan password admin, karena ya begitulah orang-orang kalau males bikin akun. Gagal. Terus gue iseng ketik di kolom password: ' OR '1'='1. Tombol masuk gue tekan. Dan boong kalau gue bilang nggak kaget pas halaman langsung pindah ke dashboard admin.
Di situ otak gue berhenti sebentar. Gue nggak ngetik password beneran. Gue cuma nulis satu baris kalimat yang menurut logika seharusnya cuma dianggap sebagai teks biasa. Tapi aplikasinya malah nurut. Ia membuka pintu seolah-olah gue memang adminnya. Itu momen pertama gue sadar: ada bagian dari sistem yang percaya sama apa yang seharusnya cuma diproses sebagai data.
Cerita ini gue tulis bukan buat ajarin kamu ngeretas situs orang. Itu ilegal, dan gue juga nggak mau jadi bagian dari masalah. Tapi gue pengen ceritain gimana cara berpikir di balik SQL injection dari kacamata red team, supaya kalau suatu hari kamu jadi defender, kamu paham persis kenapa kode kamu bisa dibohongi. Karena jujur aja, kebanyakan celah itu lahir bukan dari orang jahat yang jenius, tapi dari kode yang terlalu percaya sama input manusia.
SQL Itu Bahasa, Bukan Sihir
Biar kita sepaham, gue jelasin dulu secara santai. SQL itu singkatan dari Structured Query Language, bahasa yang dipakai buat ngomong sama database. Pas kamu ngetik "tampilinin data user yang namanya si A", aplikasinya nerjemahin itu jadi kalimat SQL, kirim ke database, dan database balikin hasilnya.
Nah, masalahnya muncul pas programmer nulis kode kayak gini:
sqlSELECT * FROM users WHERE username = 'admin' AND password = 'rahasia123';
Itu query normal. Tapi bayangin programmernya males, jadi dia nggabungin input dari form langsung ke dalam teks query tanpa filtrasi. Kira-kira kodenya begini:
pythonquery = "SELECT * FROM users WHERE username = '" + input_user + "' AND password = '" + input_pass + "';"
Lihat? Input user cuma dijeblosin ke dalam string. Nggak dicek, nggak dibersihin. Sekarang gue balik ke kolom password tadi. Pas gue ketik ' OR '1'='1, query yang jadi bukan lagi yang dipikirin programmer. Ia jadi:
sqlSELECT * FROM users WHERE username = 'admin' AND password = '' OR '1'='1';
Bagian '1'='1' itu selalu benar. Jadi seluruh kondisi jadi benar, nggak peduli username dan passwordnya salah. Database pun bilang, "ya udah lewat", dan aplikasinya ngasih akses. Satu tanda kutip aja cukup buat rubah arti kalimat dari "cari user ini" jadi "cari semua user, atau biarin aja lewat".
Itulah inti SQL injection: kita nggak ngeretas database-nya, kita cuma ngakalin cara aplikasi nyusun kalimat perintahnya. Data yang tadinya cuma boleh jadi "isi", kita naikin derajatnya jadi "perintah".
Saat Pertama Kali Gue Ngerasa Jadi Hacker
Setelah kejadian form login itu, gue nggak langsung jago. Gue cuma tahu satu trik. Tapi rasa penasaran itu gatal banget. Gue mulai bikin lab sendiri di laptop. Pasang DVWA, pasang beberapa aplikasi latihan yang emang dibikin buat dibobol, dan mulai main di situ. Kenapa di lab? Karena di lab gue bebas salah, bebas berantakan, dan yang paling penting: izin.
Satu malam, gue nemu form pencarian di aplikasi latihan itu. Box kecil bertuliskan "cari produk". Gue ketik baju, muncul daftar baju. Gue ketik baju', halaman error. Database komplain karena tanda kutipnya nggak ditutup. Bagi orang awam itu cuma tulisan merah jelek. Buat gue, itu sinyal merah yang manis: ada celah.
Cara gue mikirnya simpel. Kalau satu tanda kutip bikin error, berarti input gue masuk ke dalam query SQL secara mentah. Berarti gue bisa lanjut. Gue coba baju' AND '1'='1 — hasilnya normal. Gue coba baju' AND '1'='2 — hasilnya kosong. Nah, pola ini yang disebut blind test: gue nggak lihat datanya langsung, tapi gue lihat reaksi aplikasinya. True bikin muncul, false bikin hilang. Dari situ gue tau query-nya bisa gue kendaliin baris per baris.
Ngobrol sama Database Lewat Union
Sekarang bagian seru. Pas query-nya bisa gue injeksi, gue pengen lihat tabel lain, bukan cuma daftar produk. Di SQL ada kata UNION yang fungsinya gabungin hasil dua query. Asal jumlah kolomnya sama. Jadi tantangan pertamanya: berapa kolom yang dipakai di query aslinya?
Gue siasatin pakai ORDER BY. Gue ketik baju' ORDER BY 1-- hasil normal, ORDER BY 2-- normal, ORDER BY 3-- normal, ORDER BY 4-- error. Artinya query aslinya punya 3 kolom. Garis dua minus-minus di belakang itu penanda komentar di banyak database, buat matiin sisa query asli supaya nggak bentrok sama tambahan gue.
Pas ketemu 3 kolom, gue masukin:
sqlbaju' UNION SELECT username, password, email FROM users--
Dan di layar, di kolom yang tadinya buat nama produk, muncul nama dan password user lain. Bukan hash yang kuat, tapi password mentah. Gue duduk diam. Di situ pertama kali gue ngerasain yang namanya "database mulai ngomong balik". Bukan karena gue pintar, tapi karena si pembuat aplikasi naruh kunci di bawah karpet dan lupa kalau karpetnya transparan.
Gue harus tekenin di sini: dalam dunia nyata, kamu nggak bakal nemu password mentah sejorok itu kecuali aplikasinya sangat berantakan. Kebanyakan sekarang paling nggak di-hash. Tapi poinnya sama: lewat SQL injection, batas antara "yang boleh gue lihat" dan "yang rahasia" bisa ilang sekaligus.
Dua Wajah SQL Injection: yang Kelihatan dan yang Sembunyi
Lama-lama gue paham kalau SQL injection punya banyak wajah. Yang tadi gue lakuin itu yang namanya in-band atau classic: datanya langsung keluar di halaman. Tapi ada yang lebih licik, blind SQL injection. Di sini aplikasinya nggak pernah nampilin error dan nggak pernah nampilin data. Ia cuma berubah sikap: halaman ada, atau halaman kosong.
Gue pernah ngerjain satu endpoint API latihan di mana outputnya cuma "OK" atau "NO". Nggak ada tabel, nggak ada list. Tapi gue curiga. Gue kirim parameter id=5, baliknya "OK". Gue kirim id=5 AND 1=1, baliknya "OK". Gue kirim id=5 AND 1=2, baliknya "NO". Sip, blind injection konfirmasi. Dari situ gue mulai tanya database pakai true-false, satu bit informasi per request.
Mau tahu berapa panjang nama database? Gue tanya: id=5 AND LENGTH(database())=1 -> NO, =2 -> NO, sampai ketemu angka yang bikin "OK". Mau tahu huruf pertamanya? Gue tanya pakai SUBSTRING: huruf pertama kah 'a'? NO. 'b'? NO. Sampai ketemu. Satu huruf butuh belasan request, satu nama database bisa puluhan request. Lambat? Banget. Tapi metodis. Dan itulah yang gue suka dari sisi red team: kadang kemenangan bukan soal cepat, tapi soal sabar dan punya rencana.
Ada juga yang namanya error-based, di mana kita sengaja bikin database melempar pesan error yang kebetulan ikut nyebutin struktur tabelnya. Dan out-of-band, di mana data dibocorin lewat jalur lain kayak DNS request ke server kita. Semua variasi itu sebenarnya satu akar: aplikasi membiarkan input jadi perintah.
Sqlmap itu Kereta, Bukan Kaki
Waktu gue mulai malas, gue kenal sqlmap. Alat otomatis yang bisa ngetes, ngeinjeksi, sampai nge-dump database dalam hitungan menit. Gue jalanin, lihat progress bar jalan, dan dalam waktu singkat punya salinan tabel yang utuh. Enak? Enak. Bahaya buat pemula? Sangat.
Kenapa gue bilang bahaya? Karena kalau kamu cuma tinggal jalanin sqlmap tanpa ngerti kenapa dia berhasil, kamu cuma jadi penyetel tombol. Kamu nggak belajar. Pas suatu hari alat itu gagal di aplikasi yang lebih pintar, kamu bingung karena kamu nggak punya intuisi. Makanya gue selalu saranin: pelajari manual dulu sampai kerasa di tulang, baru pakai alat buat bantu kerjaan berulang. Alat itu kereta api, bukan kaki. Kereta bikin cepat, tapi kalau relnya rusak dan kamu nggak tau jalan kaki, kamu stuck.
Satu lagi soal etika yang gue pegang kuat. Sqlmap dan tools sejenis itu boleh dipakai di lab punyamu sendiri, di program bug bounty yang explicit izinin, atau di kerjaan tempat kamu emang ditugasin ngetes. Di luar itu, jangan. Nggak peduli seberapa penasaran. Ada batas antara belajar dan melanggar hukum, dan batas itu harus kamu respek sebelum kamu nyesel.
Dari Sisi yang Nembak ke Sisi yang Ngebenteng
Ironi yang gue suka: setelah keliling-keliling ngeretas lewat SQL injection, gue jadi programmer yang jauh lebih parno. Gue lihat kodeorang, otomatis mata gue ngejar bagian yang nyambungin input ke query. Dan obatnya sebenarnya simpel banget, cuma kebanyakan orang males atau nggak tau.
Pertama, parameterized query, atau prepared statement. Alih-alih nyusun string SQL pakai tempelan input, kita kasih placeholder. Kira-kira begini:
pythoncursor.execute("SELECT * FROM users WHERE username = %s AND password = %s", (user, pw))
Perhatiin %s-nya. Input user sekarang diperlakukan murni sebagai data, dipisah dari struktur perintah. Mau kamu ketik ' OR '1'='1, database bakal nyari user yang namanya persis itu sebagai teks, bukan ngeksekusi logika. Ini tameng paling dasar dan paling ampun. Sayangnya masih banyak kode lama yang belum pakai ini.
Kedua, jangan percaya input cuma karena datangnya dari dalam. Validasi tipe, panjang, dan format. Kalau kolomnya cuma nerima angka ID, tolak kalau ada huruf atau tanda kutip. Prinsipnya: tolak yang nggak dikenal, bukan izinin yang kelihatan normal.
Ketiga, kalau bisa, jangan simpan password mentah. Hash pakai algoritma yang memang buat password, dan kasih garam. Jadi walau seseorang berhasil nge-dump tabel, yang dia pegang cuma bubur hash, bukan kata sandi asli. Belum tentu aman seratus persen, tapi bikin hidup si penyerang jauh lebih susah.
Keempat, batasi hak akses akun database yang dipakai aplikasi. Banyak aplikasi kecil jalan pakai akun database yang punya hak penuh, padahal dia cuma butuh baca dan tulis di dua tabel. Kalau akunnya cuma punya hak terbatas, dampak SQL injection jadi jauh lebih kecil.
Kelima, jangan tampilkan error mentah ke user. Pesan error database itu peta bagi penyerang. Tampilin "terjadi kesalahan" aja cukup. Detailnya simpan di log server, bukan di layar pengunjung.
Pelajaran yang Gue Bawa Sampai Sekarang
Lebih dari sekadar teknik, SQL injection ngajarin gue cara berpikir yang disebut "bahasa pemrograman itu kontrak". Setiap input itu janji: ini data, bukan perintah. Pas programmer mengabaikan janji itu, sistem jadi rapuh. Dan sebagai orang yang kerja di keamanan, tugas gue bukan cuma nemu celah, tapi ngajarin temen-temen developer buat nulis kode yang nggak gampang dikhianati.
Gue juga belajar kalau banyak celah keamanan itu nggak lahir dari kebodohan luar biasa, tapi dari kebiasaan buruk kecil yang numpuk. Tempel string sekali, lupa validasi sekali, abaikan error sekali. Dalam jangka panjang, kecil-kecil ini jadi lubang lebar. Makanya gue selalu bilang ke tim: perbaiki yang kecil sebelum dia jadi cerita di headline berita.
Terakhir, soal mindset. Red team itu bukan soal jadi jagoan yang bisa jebolin apa aja. Red team itu soal rasa penasaran yang ditaruh di jalur yang benar. Kita menerjang batas di lab, di izin, di aturan, supaya kita tau di mana pertahanan kita bocor sebelum orang lain yang nggak bermoral ngetesnya. SQL injection mungkin sudah tua, sudah sering dibahas, sudah puluhan tahun ada. Tapi dia tetap ada di daftar celah paling laris tiap tahun, karena kode yang lalai tetap ditulis tiap hari.
Penutup buat Kamu yang Baru Mulai
Kalau kamu baru mulai belajar keamanan siber dan pengen nyobain SQL injection, gue punya saran jujur. Jangan cari situs orang buat Latihan. Bangun lab sendiri. Pasang aplikasi latihan, pasang database lokal, dan main di situ sepuasnya. Rasakan momen pas query-nya mulai nurut sama kamu. Rasakan juga momen pas kamu balik jadi programmer dan nambal celah itu dengan parameterized query. Dua sisi itu yang bikin kamu lengkap.
Dan ingat selalu: ilmu ini tajam. Kamu pegang pisau yang bisa buka kotak orang lain. Dipakai di tempat yang salah, kamu bukan lagi pembelajar, kamu pelanggar. Tapi dipakai di tempat yang benar, kamu pelindung. Pilihan ada di tanganmu tiap kali kamu ngetik satu tanda kutip ke dalam kotak yang nggak seharusnya kamu sentuh.
Gue masih ingat malam itu, di depan form login kecil, pas pintu tiba-tiba kebuka cuma karena satu baris teks. Hingga sekarang gue masih senyum sendiri. Bukan karena gue berhasil nembus, tapi karena gue akhirnya paham: keamanan itu bukan soal kunci yang rumit, tapi soal apakah kita benar-benar tahu siapa yang kita ijinin bicara ke sistem kita.