Alternatif untuk mysql_real_escape_string tanpa terhubung ke DB

91

Saya ingin memiliki fungsi yang berperilaku sebagai mysql_real_escape_string tanpa terhubung ke database karena terkadang saya perlu melakukan pengujian kering tanpa koneksi DB. mysql_escape_string tidak digunakan lagi dan karena itu tidak diinginkan. Beberapa temuan saya:

http://www.gamedev.net/community/forums/topic.asp?topic_id=448909

http://w3schools.invisionzone.com/index.php?showtopic=20064

Viet
sumber
1
+1 Saya menulis kelas MySQL sendiri dan menggunakan mysql_real_escape_string () untuk tujuan pengikatan parameter. Saya menghindari penggunaan mysqli karena tidak semua hosting mendukungnya. Saya juga menghindari perpustakaan multi-file & multi-kelas. Yang saya butuhkan hanyalah satu Kelas yang rapi & bersih. Terima kasih!
Viet
1 untuk saya juga. Kasus penggunaan saya adalah SugarCRM APi di mana saya perlu mendorong fragmen SQL ke instance SugarCRM jarak jauh melalui API. Meskipun itu buruk, saya harus bekerja dengan itu (temui beberapa pengembang SugarCRM bersama-sama). Saya perlu melepaskan string dalam SQL dalam aplikasi yang menggunakan API dan itu benar-benar terpisah dari database di belakang instance SugarCRM.
Jason

Jawaban:

76

Tidak mungkin untuk melepaskan string dengan aman tanpa koneksi DB. mysql_real_escape_string()dan pernyataan yang disiapkan membutuhkan koneksi ke database sehingga mereka dapat melarikan diri dari string menggunakan set karakter yang sesuai - jika tidak, serangan injeksi SQL masih dimungkinkan menggunakan karakter multi-byte.

Jika Anda hanya menguji , Anda juga dapat menggunakan mysql_escape_string(), itu tidak dijamin 100% terhadap serangan injeksi SQL, tetapi tidak mungkin untuk membangun sesuatu yang lebih aman tanpa koneksi DB.

terlalu banyak php
sumber
1
+1 Terima kasih atas catatannya. Saya tidak begitu yakin bagaimana cara menguji serangan injeksi SQL menggunakan karakter multi-byte.
Viet
2
Saya telah diberi beberapa kode lama untuk diperbarui. Ini menggunakan mysql_escape_stringtanpa koneksi (masih mencoba mencari tahu mengapa). Karena fungsi itu sudah usang, saya hanya ingin tahu bagaimana saya bisa menggantinya. Tampaknya masuk akal bahwa seseorang dapat menentukan "rangkaian karakter yang sesuai" dalam fungsi apa pun yang menggantikannya tanpa membuka koneksi.
JohnK
3
Mustahil? Apa yang diperoleh mysql_real_escape_string dari koneksi database yang bukan merupakan data konfigurasi yang dapat diteruskan dengan tangan ke fungsi yang setara? Edit: baca saja di bawah ini, ini memanggil fungsi perpustakaan di dalam MySQL, jadi ada beberapa pemrosesan yang terjadi di luar PHP. Ini mungkin masih portabel, tetapi menjaganya tetap mutakhir akan menjadi proyek tersendiri.
Jason
2
Bagaimana jika kumpulan karakter DB diketahui sebelumnya?
jchook
7
Ya jika Anda tahu set karakter, apa yang mencegah melakukan pelarian tanpa koneksi?
Johan
67

Nah, menurut halaman referensi fungsi mysql_real_escape_string : "mysql_real_escape_string () memanggil fungsi pustaka MySQL mysql_real_escape_string, yang lolos dari karakter berikut: \ x00, \ n, \ r, \, '," dan \ x1a. "

Dengan mengingat hal itu, maka fungsi yang diberikan di tautan kedua yang Anda posting harus melakukan apa yang Anda butuhkan:

function mres($value)
{
    $search = array("\\",  "\x00", "\n",  "\r",  "'",  '"', "\x1a");
    $replace = array("\\\\","\\0","\\n", "\\r", "\'", '\"', "\\Z");

    return str_replace($search, $replace, $value);
}
zombat
sumber
6
Terima kasih. Saya akan menyarankan sesuatu yang lain: function escape ($ aQuery) {return strtr ($ aQuery, array ("\ x00" => '\ x00', "\ n" => '\ n', "\ r" => '\ r', '\\' => '\\\\', "'" => "\'", '"' => '\"', "\ x1a" => '\ x1a')) ; }
Viet
1
mengapa \ x1a diganti dengan \\\ x1a daripada \\ x1a? Apakah ini salah ketik?
Michael Z
16
-1 Ini sangat berbahaya. Jika koneksi database menggunakan kumpulan karakter multibyte, penggantian bytewise sederhana seperti ini dapat menyebabkan kerusakan data (termasuk karakter pelolosan / kutipan) - ini dapat dengan sengaja dieksploitasi oleh penyerang jahat untuk memasukkan SQL sewenang-wenang.
eggyal
Jika Anda salah menetapkan karakter dalam hal ini, ini bisa berbahaya. Untuk himpunan karakter multibyte, jika mysql digunakan, seseorang dapat memasukkan satu byte saja untuk membatalkan \\. Kumpulan karakter multiebyte seringkali dapat mengambil apa saja sebagai byte kedua termasuk \\ karena mysql tidak akan melihatnya sebagai standalone \\ tetapi bagian dari karakter multibyte. Saya tidak tahu apa yang terjadi dengan UTF8. Saya berharap bahwa dengan [0xB0, '\\'] bahwa saat mencapai byte yang tidak valid \\ itu hanya berhenti dan mulai lagi dengan byte itu daripada menelannya.
jgmjgm
1
Jika saya tahu bahwa charset adalah utf8, apakah aman digunakan mb_strpos()(dan mb_substr()membuat perilaku serupa substr_replace()) untuk melakukan ini?
SOFe
28

Bertentangan langsung dengan jawaban saya yang lain, fungsi berikut ini mungkin aman, bahkan dengan karakter multi-byte.

// replace any non-ascii character with its hex code.
function escape($value) {
    $return = '';
    for($i = 0; $i < strlen($value); ++$i) {
        $char = $value[$i];
        $ord = ord($char);
        if($char !== "'" && $char !== "\"" && $char !== '\\' && $ord >= 32 && $ord <= 126)
            $return .= $char;
        else
            $return .= '\\x' . dechex($ord);
    }
    return $return;
}

Saya berharap seseorang yang lebih berpengetahuan dari saya dapat memberi tahu saya mengapa kode di atas tidak berfungsi ...

terlalu banyak php
sumber
+1 Terima kasih atas usaha ekstra. Saya akan berkeliling untuk mencari tahu lebih banyak tentang injeksi SQL terkait multi-byte.
Viet
Saya kira itu harus $ return. = '\ X'. dechex ($ ord); sebagai gantinya
Viet
1
Sebagai aturan umum, saya lebih suka menggunakan '\\' bahkan dalam string yang dikutip tunggal, hanya karena satu '\' dapat memengaruhi karakter berikutnya jika Anda tidak berhati-hati. Saya mungkin hanya menjadi OCD lagi.
terlalu banyak php
1
Fungsi ini tidak mengikuti aturan pelolosan mysql dan akan mengakibatkan hilangnya integritas data. "MySQL mengenali urutan escape yang ditunjukkan pada Tabel 9.1," Urutan Escape Karakter Khusus ". Untuk semua urutan escape lainnya, garis miring terbalik diabaikan. Artinya, karakter yang lolos diinterpretasikan seolah-olah tidak melarikan diri. Misalnya," \ x " hanya “x”. " - dev.mysql.com/doc/refman/5.6/en/…
velcrow
2
Apakah \ xAA sebenarnya memiliki arti selain teks "xAA" dalam literal string MySQL? Dokumentasi sepertinya mengatakan bahwa \ x tidak memiliki arti khusus, jadi \ akan diabaikan. dev.mysql.com/doc/refman/5.0/en/string-literals.html
Jason
6

Dari penelitian lebih lanjut, saya telah menemukan:

http://dev.mysql.com/doc/refman/5.1/en/news-5-1-11.html

Perbaikan Keamanan:

Lubang keamanan injeksi SQL telah ditemukan dalam pemrosesan pengkodean multi-byte. Bug ada di server, salah mengurai string yang lolos dengan fungsi API C mysql_real_escape_string ().

Kerentanan ini ditemukan dan dilaporkan oleh Josh Berkus dan Tom Lane sebagai bagian dari kolaborasi keamanan antar proyek dari konsorsium OSDB. Untuk informasi lebih lanjut tentang injeksi SQL, silakan lihat teks berikut.

Diskusi. Lubang keamanan injeksi SQL telah ditemukan dalam pemrosesan pengkodean multi-byte. Lubang keamanan injeksi SQL dapat mencakup situasi di mana ketika pengguna memberikan data untuk dimasukkan ke dalam database, pengguna dapat memasukkan pernyataan SQL ke dalam data yang akan dieksekusi oleh server. Berkenaan dengan kerentanan ini, ketika karakter set-unaware escaping digunakan (misalnya, addlashes () di PHP), adalah mungkin untuk melewati escaping di beberapa set karakter multi-byte (misalnya, SJIS, BIG5 dan GBK). Akibatnya, fungsi seperti addlashes () tidak dapat mencegah serangan injeksi SQL. Tidak mungkin untuk memperbaikinya di sisi server. Solusi terbaik adalah untuk aplikasi menggunakan pelarian karakter set-aware yang ditawarkan oleh fungsi seperti mysql_real_escape_string ().

Namun, bug terdeteksi dalam cara server MySQL mengurai output mysql_real_escape_string (). Akibatnya, bahkan ketika karakter set-aware function mysql_real_escape_string () digunakan, injeksi SQL dimungkinkan. bug ini telah diperbaiki.

Solusi. Jika Anda tidak dapat memutakhirkan MySQL ke versi yang menyertakan perbaikan bug dalam parsing mysql_real_escape_string (), tetapi menjalankan MySQL 5.0.1 atau lebih tinggi, Anda dapat menggunakan mode SQL NO_BACKSLASH_ESCAPES sebagai solusinya. (Mode ini diperkenalkan di MySQL 5.0.1.) NO_BACKSLASH_ESCAPES mengaktifkan mode kompatibilitas standar SQL, di mana garis miring terbalik tidak dianggap sebagai karakter khusus. Hasilnya adalah kueri akan gagal.

Untuk mengatur mode ini untuk koneksi saat ini, masukkan pernyataan SQL berikut:

SET sql_mode='NO_BACKSLASH_ESCAPES';

Anda juga dapat menyetel mode secara global untuk semua klien:

SET GLOBAL sql_mode='NO_BACKSLASH_ESCAPES';

Mode SQL ini juga dapat diaktifkan secara otomatis ketika server dimulai dengan menggunakan opsi baris perintah --sql-mode = NO_BACKSLASH_ESCAPES atau dengan mengatur sql-mode = NO_BACKSLASH_ESCAPES di file opsi server (misalnya, my.cnf atau my.ini , tergantung pada sistem Anda). (Bug # 8378, CVE-2006-2753)

Lihat juga Bug # 8303.

Viet
sumber
1
Ini telah diperbaiki sejak lama.
Akal Sehat Anda
2
Juga berhati-hatilah karena menyebabkan NO_BACKSLASH_ESCAPES kerentanan lainnya .
eggyal
2
Diperbaiki di 5.1.11 - Tautan rusak, ini arsipnya: web.archive.org/web/20120501203047/http://dev.mysql.com:80/doc/…
Bastion