cari

Rumah  >  Soal Jawab  >  teks badan

Bagaimana untuk menghalang suntikan SQL dalam PHP?

<p>Jika input pengguna dimasukkan ke dalam pertanyaan SQL tanpa pengubahsuaian, aplikasi terdedah kepada suntikan SQL, seperti dalam contoh berikut: </p> <pre class="lang-php prettyprint-override"><kod>$unsafe_variable = $_POST['user_input']; mysql_query("INSERT INTO `table` (`column`) NILAI ('$unsafe_variable')"); </code></pre> <p>Ini kerana pengguna boleh memasukkan sesuatu seperti <code>value'); <pre class="brush:php;toolbar:false;">INSERT IN TO `table` (`column`) NILAI('value'); <p>Apakah yang boleh dilakukan untuk mengelakkan perkara ini daripada berlaku? </p>
P粉022723606P粉022723606449 hari yang lalu567

membalas semua(2)saya akan balas

  • P粉466643318

    P粉4666433182023-08-24 10:19:21

    Untuk menggunakan pertanyaan berparameter, anda perlu menggunakan Mysqli atau PDO. Untuk menulis semula contoh anda menggunakan mysqli kami memerlukan perkara berikut.

    <?php
    mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
    $mysqli = new mysqli("server", "username", "password", "database_name");
    
    $variable = $_POST["user-input"];
    $stmt = $mysqli->prepare("INSERT INTO table (column) VALUES (?)");
    // "s" means the database expects a string
    $stmt->bind_param("s", $variable);
    $stmt->execute();

    Fungsi utama yang anda perlu baca ialah mysqli::prepare.

    Selain itu, seperti yang dicadangkan oleh orang lain, anda mungkin mendapati menggunakan sesuatu seperti PDO< 之类的东西来提升抽象层很有用/更容易/a>.

    Sila ambil perhatian bahawa kes yang anda tanyakan adalah agak mudah, kes yang lebih kompleks mungkin memerlukan kaedah yang lebih canggih. Terutamanya:

    • Jika anda ingin menukar struktur SQL berdasarkan input pengguna, pertanyaan berparameter tidak akan membantu dan mysql_real_escape_stringmysql_real_escape_string tidak mengandungi pelarian yang diperlukan. Dalam kes ini, lebih baik anda menghantar input pengguna melalui senarai putih untuk memastikan hanya nilai "selamat" dibenarkan.

    balas
    0
  • P粉985686557

    P粉9856865572023-08-24 00:23:23

    Tidak kira pangkalan data yang anda gunakan, cara yang betul untuk mengelakkan serangan suntikan SQL adalah dengan mengasingkan data daripada SQL supaya data masih menjadi data dan >tidak pernah ditafsirkan sebagai arahan oleh penghurai SQL. Anda boleh membuat pernyataan SQL menggunakan bahagian data yang diformat dengan betul, tetapi jika anda sepenuhnya memahami butirannya, anda harus sentiasa menggunakan pernyataan yang disediakan dan pertanyaan berparameter. ialah pernyataan SQL yang dihantar dan dihuraikan oleh pelayan pangkalan data secara berasingan daripada sebarang parameter. Dengan cara ini adalah mustahil bagi penyerang untuk menyuntik SQL berniat jahat.

    Anda pada asasnya mempunyai dua pilihan untuk mencapai ini:

    1. Gunakan PDO (untuk mana-mana pemacu pangkalan data yang disokong):

      $stmt = $pdo->prepare('SELECT * FROM employees WHERE name = :name');
      $stmt->execute([ 'name' => $name ]);
      
      foreach ($stmt as $row) {
          // Do something with $row
      }
      
    2. Gunakan MySQLi (untuk MySQL):
      Bermula dari PHP 8.2+, kita boleh menggunakan < code>execute_query() untuk menyediakan, mengikat parameter dan melaksanakan pernyataan SQL dalam satu kaedah:

      $result = $db->execute_query('SELECT * FROM employees WHERE name = ?', [$name]);
       while ($row = $result->fetch_assoc()) {
           // Do something with $row
       }
      

      Sehingga PHP8.1:

       $stmt = $db->prepare('SELECT * FROM employees WHERE name = ?');
       $stmt->bind_param('s', $name); // 's' specifies the variable type => 'string'
       $stmt->execute();
       $result = $stmt->get_result();
       while ($row = $result->fetch_assoc()) {
           // Do something with $row
       }
      

    Jika anda menyambung ke pangkalan data selain MySQL, anda boleh merujuk kepada pilihan khusus pemacu kedua (cth., pg_prepare()pg_prepare() dan < /code>pg_execute()

    untuk PostgreSQL). PDO ialah pilihan universal.

    Sediakan sambungan dengan betul

    PDO

    Sila ambil perhatian bahawa apabila menggunakan PDO untuk mengakses pangkalan data MySQL, sebenar penyata yang disediakantidak digunakan secara lalai. Untuk menyelesaikan isu ini, anda mesti melumpuhkan simulasi kenyataan yang disediakan. Contoh mencipta sambungan menggunakan PDO

    ialah:

    $dbConnection = new PDO('mysql:dbname=dbtest;host=127.0.0.1;charset=utf8mb4', 'user', 'password');
    
    $dbConnection->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
    $dbConnection->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    
    Dalam contoh di atas, mod ralat tidak begitu diperlukan, tetapi disyorkan untuk menambahnya PDOException. Dengan cara ini, PDO akan memberitahu anda tentang semua ralat MySQL dengan membuang

    PDOException

    . Walau bagaimanapun, setAttribute() memaksa ialah baris setAttribute()

    yang pertama, yang memberitahu PDO untuk melumpuhkan kenyataan simulasi yang disediakan dan menggunakan pernyataan kenyataan yang disediakan

    sebenar 字符集. Ini memastikan pernyataan dan nilai tidak dihuraikan oleh PHP sebelum dihantar ke pelayan MySQL (memberi peluang kepada bakal penyerang untuk menyuntik SQL yang berniat jahat). Walaupun anda boleh menetapkan

    charset

    dalam pilihan pembina, adalah penting untuk ambil perhatian bahawa versi "lama" PHP (sebelum 5.3.6)

    abaikan parameter charset secara senyap

    dalam DSN.

    🎜Mysqli🎜 🎜Untuk mysqli kita kena ikut rutin yang sama: 🎜
    mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT); // error reporting
    $dbConnection = new mysqli('127.0.0.1', 'username', 'password', 'test');
    $dbConnection->set_charset('utf8mb4'); // charset
    

    Arahan

    Apabila anda lulus prepare的SQL语句由数据库服务器解析和编译。通过指定参数(? 或命名参数,如上例中的 :name),您可以告诉数据库引擎您要过滤的位置。然后,当您调用 execute, pernyataan yang disediakan akan digabungkan dengan nilai parameter yang anda tentukan.

    Perkara penting di sini ialah nilai parameter digabungkan dengan pernyataan yang disusun, bukan rentetan SQL. Suntikan SQL berfungsi dengan menipu skrip supaya mengandungi rentetan berniat jahat apabila ia mencipta SQL untuk dihantar ke pangkalan data. Jadi dengan menghantar SQL sebenar secara berasingan daripada parameter, anda mengehadkan risiko berakhir dengan sesuatu yang tidak dijangka.

    Sebarang parameter yang anda hantar apabila menggunakan penyata yang disediakan akan dianggap sebagai rentetan (walaupun enjin pangkalan data mungkin melakukan beberapa pengoptimuman, jadi parameter sudah tentu akan dianggap sebagai nombor juga). Dalam contoh di atas, jika $name 变量包含 'Sarah'; DELETE FROMEmployees 结果只是搜索字符串 "'Sarah'; DELETE FROMEmployees", dan anda tidak akan mendapat meja kosong.

    Faedah lain menggunakan pernyataan yang disediakan ialah jika anda melaksanakan pernyataan yang sama beberapa kali dalam sesi yang sama, ia hanya akan dihuraikan dan disusun sekali, sekali gus meningkatkan kelajuan.

    Oh, kerana anda bertanya bagaimana untuk membuat sisipan, berikut adalah contoh (menggunakan PDO):

    $preparedStatement = $db->prepare('INSERT INTO table (column) VALUES (:column)');
    
    $preparedStatement->execute([ 'column' => $unsafeValue ]);
    

    Bolehkah pernyataan yang disediakan digunakan untuk pertanyaan dinamik?

    Walaupun anda masih boleh menggunakan pernyataan yang disediakan dengan parameter pertanyaan, struktur pertanyaan dinamik itu sendiri tidak boleh diparameterkan dan fungsi pertanyaan tertentu juga tidak boleh diparameterkan.

    Untuk senario khusus ini, perkara terbaik untuk dilakukan ialah menggunakan penapis senarai putih untuk mengehadkan nilai yang mungkin.

    // Value whitelist
    // $dir can only be 'DESC', otherwise it will be 'ASC'
    if (empty($dir) || $dir !== 'DESC') {
       $dir = 'ASC';
    }

    balas
    0
  • Batalbalas