phorror ([info]phorror) wrote,
Тут в комментах я заикнулся про косяк c myql_real_escape_string, и попросили осветить поподробнее.
В общем, насколько я сам понимаю ситуацию.
Эту функцию ввели для того, чтобы она "принимала в расчет текущую кодировку".
Нормально. Но простое выполнение запроса SET NAMES эту самую "текущую кодировку" не меняет.
А меняет ее функция mysql_set_charset()
Пруфкод:

echo mysql_client_encoding();
echo "<br>\n";
mysql_query('SET NAMES cp1251');
echo mysql_client_encoding();
echo "<br>\n";
mysql_set_charset('cp1251');
echo mysql_client_encoding();
echo "<br>\n";

(хотя, конечно, реальным пруфкодом был бы такой, который бы печатал строку, обработанную myql_real_escape_string при разных кодировках и содержащую те самые зависимые от кодировки символы)

Загадочности добавляет невнятная ремарка в мануале по mysql_set_charset, привожу полностью:
Note: This is the preferred way to change the charset. Using mysql_query() to execute SET NAMES .. is not recommended.

Выходит, что пользуясь myql_real_escape_string, никто на самом деле заявленный функционал не использует. А косяков нет потому, что кодировки или однобайтные или утф-8, которым по барабану и хватит даже addslashes (а у многих, опять же, квотинг/искейпинг и вовсе не используется).

Как-то так.
Буду рад поправкам и пинкам.

Упиди
Взял кот из знаменитой статьи Шифлетта

$_POST['password'] = chr(0xbf).chr(0x27).' OR username = username /*';
$pass = addslashes($_POST['password']);
echo mysql_client_encoding();
var_dump($pass);
echo "<br>\n";
$pass = mysql_real_escape_string($_POST['password']);
echo mysql_client_encoding();
var_dump($pass);
echo "<br>\n";
mysql_query('SET NAMES GBK');
$pass = mysql_real_escape_string($_POST['password']);
echo mysql_client_encoding();
var_dump($pass);
echo "<br>\n";
mysql_set_charset('GBK');
$pass = mysql_real_escape_string($_POST['password']);
echo mysql_client_encoding();
var_dump($pass);
echo "<br>\n";

latin1string(29) "ї\' OR username = username /*"
latin1string(29) "ї\' OR username = username /*"
latin1string(29) "ї\' OR username = username /*"
gbkstring(30) "\ї\' OR username = username /*"

похоже, выводы подтверждаются.
Теоретически все работает неправильно, но всем похуй на практике ни одна из используемумых нами кодировок уязвимостью не обладает.

  • Post a new comment

    Error

    Your IP address will be recorded 

  • 6 comments

[info]l_o_n_g

August 26 2010, 03:33:00 UTC 1 year ago

блин, тогда я не понимаю нафига для mysql_real_escape_string() нужен ресурс (установленное соединение) - ведь вполне можно организовать работу без соединения.

[info]phorror

August 26 2010, 04:49:04 UTC 1 year ago

Это только при определенных кодировках. А в GBK и ShiftJIS - фейл.

[info]dkrnl

August 26 2010, 05:14:12 UTC 1 year ago

спасибо, век живи век учись. (:
побежал править DBAL (: вдруг буду работать с GBK или ShiftJIS (((:

[info]_1313

August 26 2010, 08:51:19 UTC 1 year ago

то есть надо выкинуть SET NAMES и заменить их на mysql_set_charset()?

[info]phorror

August 26 2010, 09:01:57 UTC 1 year ago

если используешь искейпинг - то да.
если препареды - то по барабану.
искейпингу с нашими кодировками тоже по барабану, но идеологически правильнее будет выкинуть, да.

[info]a_k_d

September 16 2010, 12:26:29 UTC 1 year ago

пасибо, ща сделаем :-)
Create an Account
Forgot your login or password?
Facebook Twitter More login options
English • Español • Deutsch • Русский…