Apa itu SQL Injection dan Cara Mencegahnya di Aplikasi PHP?

Jadi menurut Anda database SQL Anda berkinerja baik dan aman dari kehancuran instan? Nah, SQL Injection tidak setuju!

Ya, ini adalah penghancuran instan yang sedang kita bicarakan, karena saya tidak ingin membuka artikel ini dengan terminologi timpang yang biasa tentang “memperketat keamanan” dan “mencegah akses jahat”. SQL Injection adalah trik lama dalam buku sehingga semua orang, setiap pengembang, mengetahuinya dengan sangat baik dan sangat menyadari cara mencegahnya. Kecuali untuk satu waktu yang aneh ketika mereka tergelincir, dan hasilnya bisa sangat buruk.

Jika Anda sudah tahu apa itu SQL Injection, silakan lewati bagian kedua artikel ini. Tetapi bagi mereka yang baru terjun di bidang pengembangan web dan bermimpi untuk mengambil peran yang lebih senior, beberapa perkenalan harus dilakukan.

Apa itu Injeksi SQL?

Kunci untuk memahami SQL Injection ada pada namanya: SQL + Injection. Kata “injeksi” di sini tidak memiliki konotasi medis, melainkan penggunaan kata kerja “injeksi”. Bersama-sama, kedua kata ini menyampaikan gagasan menempatkan SQL ke dalam aplikasi web.

Menempatkan SQL ke dalam aplikasi web . . . hmmm . . . Bukankah itu yang sedang kita lakukan? Ya, tapi kami tidak ingin penyerang menggerakkan basis data kami. Mari kita pahami itu dengan bantuan sebuah contoh.

Katakanlah Anda sedang membangun situs web PHP tipikal untuk toko e-niaga lokal, jadi Anda memutuskan untuk menambahkan formulir kontak seperti ini:

<form action="record_message.php" method="POST">
  <label>Your name</label>
  <input type="text" name="name">
  
  <label>Your message</label>
  <textarea name="message" rows="5"></textarea>
  
  <input type="submit" value="Send">
</form>

Dan anggaplah file send_message.php menyimpan semuanya dalam database sehingga pemilik toko dapat membaca pesan pengguna nanti. Ini mungkin memiliki beberapa kode seperti ini:

<?php

$name = $_POST['name'];
$message = $_POST['message'];

// check if this user already has a message
mysqli_query($conn, "SELECT * from messages where name = $name");

// Other code here

Jadi, pertama-tama Anda mencoba melihat apakah pengguna ini sudah memiliki pesan yang belum dibaca. Kueri SELECT * from messages where name = $name tampaknya cukup sederhana, bukan?

SALAH!

Dalam kepolosan kami, kami telah membuka pintu untuk penghancuran database kami secara instan. Agar hal ini terjadi, penyerang harus memenuhi kondisi berikut:

  • Aplikasi berjalan pada database SQL (hari ini, hampir setiap aplikasi)
  • Koneksi basis data saat ini memiliki izin “edit” dan “hapus” pada basis data
  • Nama-nama tabel penting bisa ditebak
  Biarkan 9 Software Marketing Automation Ini Membantu Bisnis Anda

Poin ketiga berarti bahwa sekarang penyerang tahu Anda menjalankan toko e-niaga, kemungkinan besar Anda menyimpan data pesanan di tabel pesanan. Berbekal semua ini, yang perlu dilakukan penyerang hanyalah memberikan ini sebagai nama mereka:

Joe; potong pesanan;? Ya pak! Mari kita lihat apa jadinya kueri ketika dieksekusi oleh skrip PHP:

PILIH * DARI pesan MANA nama = Joe; potong pesanan;

Oke, bagian pertama kueri memiliki kesalahan sintaksis (tidak ada tanda kutip di sekitar “Joe”), tetapi titik koma memaksa mesin MySQL untuk mulai menginterpretasikan yang baru: perintah potong. Begitu saja, dalam satu gerakan, seluruh riwayat pesanan hilang!

Sekarang setelah Anda mengetahui cara kerja SQL Injection, saatnya untuk melihat cara menghentikannya. Dua syarat yang harus dipenuhi untuk injeksi SQL yang sukses adalah:

  • Skrip PHP harus memodifikasi/menghapus hak istimewa pada database. Saya pikir ini berlaku untuk semua aplikasi dan Anda tidak akan dapat membuat aplikasi Anda hanya-baca. 🙂 Dan coba tebak, bahkan jika kita menghapus semua hak modifikasi, injeksi SQL masih dapat memungkinkan seseorang untuk menjalankan kueri SELECT dan melihat semua database, termasuk data sensitif. Dengan kata lain, mengurangi tingkat akses database tidak berfungsi, dan aplikasi Anda tetap membutuhkannya.
  • Input pengguna sedang diproses. Satu-satunya cara injeksi SQL dapat berfungsi adalah saat Anda menerima data dari pengguna. Sekali lagi, tidak praktis untuk menghentikan semua masukan untuk aplikasi Anda hanya karena Anda khawatir tentang injeksi SQL.
  • Mencegah injeksi SQL di PHP

    Sekarang, mengingat koneksi database, kueri, dan input pengguna adalah bagian dari kehidupan, bagaimana kita mencegah injeksi SQL? Untungnya, ini cukup sederhana, dan ada dua cara untuk melakukannya: 1) membersihkan masukan pengguna, dan 2) menggunakan pernyataan yang telah disiapkan.

    Sanitasi input pengguna

    Jika Anda menggunakan versi PHP yang lebih lama (5.5 atau lebih rendah, dan ini sering terjadi pada shared hosting), sebaiknya jalankan semua input pengguna Anda melalui fungsi yang disebut mysql_real_escape_string(). Pada dasarnya, apa fungsinya menghapus semua karakter khusus dalam sebuah string sehingga kehilangan artinya saat digunakan oleh database.

    Misalnya, jika Anda memiliki string seperti saya adalah string, karakter kutip tunggal (‘) dapat digunakan oleh penyerang untuk memanipulasi kueri basis data yang sedang dibuat dan menyebabkan injeksi SQL. Menjalankannya melalui mysql_real_escape_string() menghasilkan I’m string, yang menambahkan garis miring terbalik ke kutipan tunggal, menghindarinya. Akibatnya, seluruh string sekarang diteruskan sebagai string yang tidak berbahaya ke database, alih-alih dapat berpartisipasi dalam manipulasi kueri.

      12 Ekstensi Chrome Perekaman Layar Terbaik

    Ada satu kelemahan dengan pendekatan ini: ini adalah teknik yang sangat, sangat lama yang sejalan dengan bentuk akses database yang lebih lama di PHP. Pada PHP 7, fungsi ini bahkan tidak ada lagi, yang membawa kita ke solusi berikutnya.

    Gunakan pernyataan yang telah disiapkan

    Pernyataan yang disiapkan adalah cara untuk membuat kueri basis data lebih aman dan andal. Idenya adalah bahwa alih-alih mengirim kueri mentah ke database, pertama-tama kita beri tahu database struktur kueri yang akan kita kirim. Inilah yang kami maksud dengan “mempersiapkan” pernyataan. Setelah pernyataan disiapkan, kami meneruskan informasi sebagai input berparametri sehingga database dapat “mengisi celah” dengan memasukkan input ke struktur kueri yang kami kirim sebelumnya. Ini menghilangkan kekuatan khusus apa pun yang mungkin dimiliki input, menyebabkannya diperlakukan hanya sebagai variabel (atau muatan, jika Anda mau) di seluruh proses. Berikut tampilan pernyataan yang disiapkan:

    <?php
    $servername = "localhost";
    $username = "username";
    $password = "password";
    $dbname = "myDB";
    
    // Create connection
    $conn = new mysqli($servername, $username, $password, $dbname);
    
    // Check connection
    if ($conn->connect_error) {
        die("Connection failed: " . $conn->connect_error);
    }
    
    // prepare and bind
    $stmt = $conn->prepare("INSERT INTO MyGuests (firstname, lastname, email) VALUES (?, ?, ?)");
    $stmt->bind_param("sss", $firstname, $lastname, $email);
    
    // set parameters and execute
    $firstname = "John";
    $lastname = "Doe";
    $email = "[email protected]";
    $stmt->execute();
    
    $firstname = "Mary";
    $lastname = "Moe";
    $email = "[email protected]";
    $stmt->execute();
    
    $firstname = "Julie";
    $lastname = "Dooley";
    $email = "[email protected]";
    $stmt->execute();
    
    echo "New records created successfully";
    
    $stmt->close();
    $conn->close();
    ?>

    Saya tahu prosesnya terdengar tidak perlu rumit jika Anda baru dalam membuat pernyataan, tetapi konsepnya sepadan dengan usaha. Ini pengantar yang bagus untuk itu.

    Bagi mereka yang sudah terbiasa dengan ekstensi PDO PHP dan menggunakannya untuk membuat pernyataan yang sudah disiapkan, saya punya sedikit saran.

    Peringatan: Berhati-hatilah saat mengatur PDO

    Saat menggunakan PDO untuk akses database, kita bisa tersedot ke dalam rasa aman yang salah. “Ah, yah, saya menggunakan PDO. Sekarang saya tidak perlu memikirkan hal lain” — begitulah cara berpikir kita pada umumnya. Benar bahwa PDO (atau pernyataan yang disiapkan MySQLi) cukup untuk mencegah semua jenis serangan injeksi SQL, tetapi Anda harus berhati-hati saat mengaturnya. Adalah umum untuk hanya menyalin-tempel kode dari tutorial atau dari proyek Anda sebelumnya dan melanjutkan, tetapi pengaturan ini dapat membatalkan semuanya:

    $dbConnection->setAttribute(PDO::ATTR_EMULATE_PREPARES, true);

    Apa yang dilakukan pengaturan ini adalah memberi tahu PDO untuk meniru pernyataan yang disiapkan daripada benar-benar menggunakan fitur pernyataan yang disiapkan dari database. Akibatnya, PHP mengirimkan string kueri sederhana ke database meskipun kode Anda terlihat seperti sedang membuat pernyataan yang disiapkan dan mengatur parameter dan semua itu. Dengan kata lain, Anda rentan terhadap injeksi SQL seperti sebelumnya. 🙂

      Cara Menginstal AbanteCart Di Server Ubuntu

    Solusinya sederhana: pastikan emulasi ini disetel ke false.

    $dbConnection->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);

    Sekarang skrip PHP terpaksa menggunakan pernyataan yang disiapkan pada tingkat basis data, mencegah semua jenis injeksi SQL.

    Mencegah menggunakan WAF

    Tahukah Anda bahwa Anda juga dapat melindungi aplikasi web dari injeksi SQL dengan menggunakan WAF (web application firewall)?

    Yah, bukan hanya injeksi SQL tetapi banyak kerentanan lapisan 7 lainnya seperti skrip lintas situs, otentikasi rusak, pemalsuan lintas situs, paparan data, dll. Anda dapat menggunakan hosting sendiri seperti Mod Security atau berbasis cloud sebagai berikut.

    Injeksi SQL dan framework PHP modern

    Injeksi SQL sangat umum, sangat mudah, sangat membuat frustrasi, dan sangat berbahaya sehingga semua kerangka kerja web PHP modern dilengkapi dengan penanggulangan. Di WordPress, misalnya, kami memiliki fungsi $wpdb->prepare() , sedangkan jika Anda menggunakan kerangka kerja MVC, itu melakukan semua pekerjaan kotor untuk Anda dan Anda bahkan tidak perlu berpikir untuk mencegah injeksi SQL. Agak menyebalkan bahwa di WordPress Anda harus menyiapkan pernyataan secara eksplisit, tapi hei, ini WordPress yang sedang kita bicarakan. 🙂

    Ngomong-ngomong, poin saya adalah, pengembang web modern tidak perlu memikirkan injeksi SQL, dan akibatnya, mereka bahkan tidak menyadari kemungkinannya. Dengan demikian, bahkan jika mereka membiarkan satu backdoor terbuka di aplikasi mereka (mungkin itu adalah parameter kueri $_GET dan kebiasaan lama menjalankan kueri kotor), hasilnya bisa menjadi bencana besar. Jadi selalu lebih baik meluangkan waktu untuk menyelam lebih dalam ke fondasi.

    Kesimpulan

    SQL Injection adalah serangan yang sangat jahat pada aplikasi web tetapi mudah dihindari. Seperti yang kita lihat di artikel ini, berhati-hati saat memproses input pengguna (ngomong-ngomong, SQL Injection bukan satu-satunya ancaman yang ditimbulkan oleh penanganan input pengguna) dan hanya menanyakan database. Meskipun demikian, kami tidak selalu bekerja dalam keamanan kerangka kerja web, jadi sebaiknya waspadai jenis serangan ini dan jangan tertipu.