2010-08-01 2 views
4

Я пытаюсь защитить форму входа на моей странице из SQL-инъекций. На сервере я использую Zend Framework (Zend_Db, Zend_Db_Table_Abstract), но его встроенные функции предотвращения впрыска: quote, quoteInto, quoteIdentifier не делают их работу хорошо (насколько я знаю, как их использовать). Другие способы, такие как mysql_real_escape_string, addslashes, кажется, не работает вообще ...Предотвращение инъекций SQL с PHP и Zend Framework - как?

Это то, что я пытаюсь выполнить для защиты:

function prevent_from_sql_injection($str) { 
    if(preg_match('/[\'"]/', $str)) 
    {die('attack1'); exit; }// no quotes 
elseif(preg_match('/[\/\\\\]/', $str)) 
    {die('attack2'); exit; }// no slashes 
elseif(preg_match('/(and|or|null|not)/i', $str)) 
    {die('attack3'); exit; }// no sqli boolean keywords 
elseif(preg_match('/(union|select|from|where)/i', $str)) 
    {die('attack4'); exit; }// no sqli select keywords 
elseif(preg_match('/(group|order|having|limit)/i', $str)) 
    {die('attack5'); exit; }// no sqli select keywords 
elseif(preg_match('/(into|file|case|LOAD_FILE|DUMPFILE|char|schema|AES_DECRYPT|AES_ENCRYPT)/i', $str)) 
    {die('attack6'); exit; }// no sqli operators 
elseif(preg_match('/(--|#|\/\*)/', $str)) 
    {die('attack7'); exit; }// no sqli comments 
elseif(preg_match('/(=|&|\|)/', $str)) 
    {die('attack8'); exit; }// no boolean operators 
elseif(preg_match('/(UNI\*\*ON|1 OR 1=1|1 AND 1=1|1 EXEC XP_)/', $str)) 
    {die('attack9'); exit; } 
elseif(preg_match('/(1|'| |O|R|=|&#49&#39&#32&#79&#82&#32&#39&#49&#39&#61&#39&#49|%31%27%20%4F%52%20%27%31%27%3D%27%31)/', $str)) 
    { die('attack10'); exit; } 
elseif(preg_match('/(SELECT\s[\w\*\)\(\,\s]+\sFROM\s[\w]+)| (UPDATE\s[\w]+\sSET\s[\w\,\'\=]+)| (INSERT\sINTO\s[\d\w]+[\s\w\d\)\(\,]*\sVALUES\s\([\d\w\'\,\)]+)| (DELETE\sFROM\s[\d\w\'\=]+)/', $str)) 
    { die('attack11'); exit; } 
elseif(preg_match('/(script)|(<)|(>)|(%3c)|(%3e)|(SELECT) |(UPDATE) |(INSERT) |(DELETE)|(GRANT) |(REVOKE)|(UNION)|(<)|(>)/', $str)) 
    { die('attack12'); exit; } 
elseif(!preg_match('/^["a-zA-Z0-9\040]+$/', $str)) 
    { die('attack13'); exit; } 
else return $str; 

} 

Как проверить мои результаты, я использую расширение Firefox SQL Inject Me и это показывает, еще 14 ошибок (иногда 21 или 17, и я не знаю, почему результаты разные):

Server Status Code: 302 Found 
Tested value: 1' OR '1'='1 
Server Status Code: 302 Found 
Tested value: 1 UNI/**/ON SELECT ALL FROM WHERE 
Server Status Code: 302 Found 
Tested value: &#49&#39&#32&#79&#82&#32&#39&#49&#39&#61&#39&#49 
Server Status Code: 302 Found 
Tested value: 1 OR 1=1 
Server Status Code: 302 Found 
Tested value: 1' OR '1'='1 
Server Status Code: 302 Found 
Tested value: 1 EXEC XP_ 
Server Status Code: 302 Found 
Tested value: 1 UNION ALL SELECT 1,2,3,4,5,6,name FROM sysObjects WHERE xtype = 'U' -- 
Server Status Code: 302 Found 
Tested value: %31%27%20%4F%52%20%27%31%27%3D%27%31 
Server Status Code: 302 Found 
Tested value: 1 AND 1=1 
Server Status Code: 302 Found 
Tested value: 1' OR '1'='1 
Server Status Code: 302 Found 
Tested value: 1 AND ASCII(LOWER(SUBSTRING((SELECT TOP 1 name FROM sysobjects WHERE xtype='U'), 1, 1))) > 116 

Так что это лучший способ, чтобы предотвратить все это SQL-инъекций? Использование заполнителей хорошо, но в некоторых случаях это не нормально. Может быть, это расширение неверно, и у меня паранойя?

+0

Определите, как другие варианты, о которых вы говорили, «не работают». –

+4

Считаете ли вы, что некоторые из них - это только отчеты о фазе? Просто потому, что сервер возвращает код 302, не означает, что инъекция прошла успешно. – Mchl

+0

Возможно, вы правы, и этот ext возвращает неверные результаты. Но как это сделать, я тестирую для SQL-инъекции? – user406136

ответ

7

Настоятельно рекомендую использовать Zend_DB. Он использует prepared statements.
Параметры для подготовленных операторов не обязательно должны быть указаны; драйвер автоматически обрабатывает это.

Если приложение использует исключительно подготовленные заявления, разработчик может быть уверен, что ни одна инъекция SQL не будет произойти (однако, если другие части , то запрос строятся с немаскированным вводом, инъекции SQL является еще возможно

$db = Zend_Db::factory('Pdo_Mysql', array(
    'host'  => '127.0.0.1', 
    'username' => 'webuser', 
    'password' => 'xxxxxxxx', 
    'dbname' => 'test' 
)); 

$stmt = $db->query('SELECT * FROM bugs WHERE reported_by = ? AND bug_status = ?', 
    array('goofy', 'FIXED') 
); 

$rows = $stmt->fetchAll(); 

echo $rows[0]['bug_description']; 
+0

Эти параметры в массиве - они цитируются автоматически или что? – user406136

+1

Да. Вот за что подготовлены заявления. «Параметры для подготовленных операторов не нужно указывать, драйвер автоматически обрабатывает это». Пожалуйста, прочитайте связанный источник для получения дополнительной информации. –

+0

Я согласен с Benjamin, используя Zend_Db, вынимает все заботы о подготовленных заявлениях, и у меня не было никаких проблем с ним. –

7

Используйте подготовленные операторы SQL вместо значения escaping.

$st = $pdo->prepare("SELECT * FROM tbl WHERE x = ?"); 
$st->execute($x); 

Черный список из двух операторов SQL не является разумным подходом. Это расширение Firefox вводит в заблуждение и дает вам неправильное впечатление.

Очевидно, что вы не должны принимать случайные команды SQL в качестве входных данных. В большинстве случаев вы используете некоторые переменные запроса в качестве данных запроса. И подготовленных утверждений достаточно для обеспечения безопасности в этом случае. Объединение команд и переменных SQL является устаревшей практикой (что, по-видимому, предлагает такое сомнительное расширение Firefox).

+0

И это именно то, что предлагает Zend_Db. – Mchl

+0

Что мне делать с Zend_Auth_Adapter_DbTable? – user406136

+1

на самом деле нет проблем с экранированием при правильном использовании –

-1

Поместите этот код на свою страницу заголовка.

function clean_header($string) 
{ 
$string = trim($string); 

// From RFC 822: “The field-body may be composed of any ASCII 
// characters, except CR or LF.” 
if (strpos($string, “\n“) !== false) { 
$string = substr($string, 0, strpos($string, “\n“)); 
} 
if (strpos($string, “\r“) !== false) { 
$string = substr($string, 0, strpos($string, “\r“)); 
} 

return $string; 
} 
Смежные вопросы