Dapatkah saya menggunakan pernyataan yang disiapkan PDO untuk mengikat pengidentifikasi (nama tabel atau bidang) atau kata kunci sintaks?
Sayangnya, pernyataan yang disiapkan hanya dapat mewakili data literal. Jadi, perangkap yang sangat umum adalah kueri seperti ini:
$opt = "id";
$sql = "SELECT :option FROM t WHERE id=?";
$stm = $pdo->prepare($sql);
$stm->execute(array($opt));
$data = $stm->fetchAll();
Bergantung pada pengaturan PDO, kueri ini akan menghasilkan kesalahan (jika menggunakan pernyataan yang disiapkan sebenarnya) atau hanya string literal 'id'
di fieldset (dalam hal persiapan yang ditiru).
Jadi, pengembang harus mengurus sendiri pengidentifikasi - PDO menawarkan tidak ada bantuan untuk masalah ini.
Untuk membuat pengidentifikasi dinamis aman, seseorang harus mengikuti 2 aturan ketat:
- untuk memformat pengenal dengan benar
- untuk memverifikasinya dengan daftar putih berkode keras .
Untuk memformat pengenal, seseorang harus menerapkan 2 aturan berikut:
- Sertakan pengenal di backticks.
- Menghindari backtick di dalam dengan menggandakannya.
Setelah pemformatan seperti itu, aman untuk memasukkan variabel $table ke dalam kueri. Jadi, kodenya adalah:
$field = "`".str_replace("`","``",$field)."`";
$sql = "SELECT * FROM t ORDER BY $field";
Namun, meskipun pemformatan seperti itu akan cukup untuk kasus seperti ORDER BY, untuk sebagian besar kasus lain ada kemungkinan untuk jenis injeksi yang berbeda:membiarkan pengguna memilih tabel atau bidang yang dapat mereka lihat, kami dapat mengungkapkan beberapa informasi sensitif, seperti kata sandi atau data pribadi lainnya. Jadi, selalu lebih baik untuk memeriksa pengidentifikasi dinamis terhadap daftar nilai yang diizinkan. Berikut adalah contoh singkatnya:
$allowed = array("name","price","qty");
$key = array_search($_GET['field'], $allowed);
$field = $allowed[$key];
$query = "SELECT $field FROM t"; //value is safe
Untuk kata kunci aturannya sama, tetapi tentu saja tidak ada format yang tersedia - jadi, hanya daftar putih yang memungkinkan dan harus digunakan:
$dir = $_GET['dir'] == 'DESC' ? 'DESC' : 'ASC';
$sql = "SELECT * FROM t ORDER BY field $dir"; //value is safe
Lihat juga catatan kontribusi pengguna ini dalam dokumentasi PHP:Catatan pengguna di PDO::quote