Подтвердить что ты не робот

Являются ли mysql_real_escape_string() и mysql_escape_string() достаточными для безопасности приложения?

Будет ли mysql_real_rescape_string() достаточно, чтобы защитить меня от хакеров и SQL-атак? Спросить, потому что я слышал, что они не помогают против всех атак? Ищите советы экспертов.

EDIT: Кроме того, как насчет LIKE SQL-атак?

4b9b3361

Ответ 1

@Charles чрезвычайно корректен!

Вы подвергаете себя риску за несколько типов известных SQL-атак, в том числе, как вы упомянули

  • SQL-инъекция: да! Mysql_Escape_String, вероятно, STILL позволяет вам подвергать SQL-инъекциям, в зависимости от того, где вы используете PHP-переменные в своих запросах.

Рассмотрим это:

$sql = "SELECT number FROM PhoneNumbers " .
       "WHERE " . mysql_real_escape_string($field) . " = " . mysql_real_escape_string($value);  

Можно ли безопасно и точно избежать этого? НЕТ! Зачем? потому что хакер может очень хорошо это сделать:

Повторите за мной:

mysql_real_escape_string() предназначен только для исключения переменных данных, НЕ имен таблиц, имен столбцов и, особенно, не полей LIMIT.

  • LIKE exploits: LIKE "$ data%", где $data могут быть "%", которые будут возвращать ВСЕ записи..., которые могут быть безопасными эксплойтами... просто представьте себе поиск по последним четырем цифрам кредитной карты... ООП! Теперь хакеры могут получить каждый номер кредитной карты в вашей системе! (BTW: Хранение полных кредитных карт вряд ли когда-либо рекомендуется!)

  • Charset Exploits: Независимо от того, что говорят ненавистники, Internet Explorer еще, в 2011 году уязвим для использования функций набора символов, и если вы правильно разработали свою HTML-страницу, эквивалент <meta name="charset" value="UTF-8"/>! Эти атаки ОЧЕНЬ неприятны, поскольку они дают хакеру такой же контроль, как прямые инъекции SQL: например. полный.

Вот пример кода, чтобы продемонстрировать все это:

// Contains class DBConfig; database information.
require_once('../.dbcreds');                       

$dblink = mysql_connect(DBConfig::$host, DBConfig::$user, DBConfig::$pass);
mysql_select_db(DBConfig::$db);
//print_r($argv);

$sql = sprintf("SELECT url FROM GrabbedURLs WHERE %s LIKE '%s%%' LIMIT %s",
               mysql_real_escape_string($argv[1]),
               mysql_real_escape_string($argv[2]),
               mysql_real_escape_string($argv[3]));
echo "SQL: $sql\n";
$qq = mysql_query($sql);
while (($data = mysql_fetch_array($qq)))
{
        print_r($data);
}

Здесь результаты этого кода, когда передаются различные входы:

$ php sql_exploits.php url http://www.reddit.com id
SQL generated: SELECT url FROM GrabbedURLs 
               WHERE url LIKE 'http://www.reddit.com%'
               ORDER BY id;
Returns: Just URLs beginning w/ "http://www.reddit.com"

$ php sql_exploits.php url % id
SQL generated: SELECT url FROM GrabbedURLs 
               WHERE url LIKE '%%' 
               ORDER BY id;
Results: Returns every result Not what you programmed, ergo an exploit --

$php sql_exploits.php 1 = 1 'http://www.reddit.com' id Результаты: Возвращает каждый столбец и каждый результат.

Затем существуют ДЕЙСТВИТЕЛЬНО неприятные эксплоиты LIMIT:

$ php sql_exploits.php url 
> 'http://www.reddit.com'
> "UNION SELECT name FROM CachedDomains"
Generated SQL: SELECT url FROM GrabbedURLs 
               WHERE url LIKE 'http://reddit.com%' 
               LIMIT 1 
               UNION
               SELECT name FROM CachedDomains;
Returns:  An entirely unexpected, potentially (probably) unauthorized query
          from another, completely different table. 

Если вы понимаете, что SQL в атаках или нет, он неуязвим. Это продемонстрировало, что mysql_real_escape_string() легко обошел даже самые незрелые хакеры. Это потому, что это РЕАКТИВНЫЙ защитный мехизм. Он только фиксирует очень ограниченные и KNOWN эксплойты в базе данных.

Все экранирование никогда не будет достаточным для защиты баз данных. Фактически, вы можете явно РЕАКТАТЬ для каждого эксплойта KNOWN, и в будущем ваш код, скорее всего, станет уязвимым для атак, обнаруженных в будущем.

Собственная и единственная (действительно) защита - это PROACTIVE: используйте подготовленные утверждения. Подготовленные заявления разрабатываются с особой тщательностью, поэтому выполняется ТОЛЬКО действительный и ПРОГРАММИРОВАННЫЙ SQL. Это означает, что при правильном выполнении шансы на неожиданный SQL, который может быть выполнен, резко сокращаются.

Теоретически, готовые операторы, которые реализованы отлично, будут непроницаемы для ВСЕХ атак, известных и неизвестных, поскольку они являются техникой SERVER SIDE, обработанной серверами DATABASE SERVERS THEMSELVES и библиотеками, которые взаимодействуют с языком программирования. Таким образом, вы ВСЕГДА гарантируете, что будете защищены от КАЖДОГО ИЗВЕСТНОГО ХАЗА, на минимальном минимуме.

И это меньше кода:

$pdo = new PDO($dsn);

$column = 'url';
$value = 'http://www.stackoverflow.com/';
$limit = 1;

$validColumns = array('url', 'last_fetched');

// Make sure to validate whether $column is a valid search parameter.
// Default to 'id' if it an invalid column.
if (!in_array($column, $validColumns) { $column = 'id'; }


$statement = $pdo->prepare('SELECT url FROM GrabbedURLs ' .
                           'WHERE ' . $column . '=? ' .
                           'LIMIT ' . intval($limit));
$statement->execute(array($value));
while (($data = $statement->fetch())) { }

Теперь это было не так сложно? И это на сорок семь процентов меньше кода (195 символов (PDO) против 375 символов (mysql_). То, что я называю "полным выигрыша".

РЕДАКТИРОВАТЬ: Чтобы решить все противоречия, этот ответ взволнован, позвольте мне повторить то, что я уже сказал:

Использование подготовленных инструкций позволяет использовать защитные меры сам SQL-сервер и, следовательно, вы защищены от того, что Об этом знают люди SQL-сервера. Потому как этого дополнительного уровня защиты вы гораздо безопаснее, чем просто используя избегая, как бы тщательны.

Ответ 2

Нет!


Важное обновление: После тестирования возможного кода эксплоита, предоставленного Col.Sprapnel, и просмотра версий MySQL 5.0.22, 5.0.45, 5.0.77 и 5.1.48, кажется, что набор символов GBK и, возможно, другие в сочетании с версией MySQL ниже 5.0.77 могут оставить ваш код уязвимым, если вы только используйте SET NAMES вместо использования специальных функций mysql_set_charset/mysqli_set_charset. Поскольку они были добавлены только в PHP 5.2.x, комбинация старого PHP и старого MySQL может дать потенциальную уязвимость SQL-инъекции, даже если вы считаете, что находитесь в безопасности и все сделали правильно, книга.


Без установки набора символов в сочетании с mysql_real_escape_string вы можете оказаться уязвимыми для использования определенного набора символов с более старым MySQL версии. Дополнительная информация о предыдущих исследованиях.

Если возможно, используйте mysql_set_charset. SET NAMES ... недостаточно для защиты от этого конкретного эксплойта, если вы используете исполняемую версию MySQL (до 5.0.22 5.0.77).

Ответ 3

Да. Если вы не забудете:

  • Исключить строковые данные с помощью mysql_real_rescape_string()
  • Ввести числа в числа явно (т.е.: $id = (int)$_GET['id'];)

тогда вы защищены.

Ответ 4

Я лично предпочитаю подготовленные заявления:

<?php
$stmt = $dbh->prepare("SELECT * FROM REGISTRY where name = ?");
if ($stmt->execute(array($_GET['name']))) {
  while ($row = $stmt->fetch()) {
    print_r($row);
  }
}
?>

Было бы довольно легко упустить ту или иную конкретную переменную, которая была пропущена при использовании одной из функций *escape_string(), но если все ваши запросы являются подготовленными операторами, то все они в порядке, а использование интерполированных переменных будет выделяются как больной палец.

Но этого недостаточно для обеспечения того, чтобы вы не были уязвимы для удаленных эксплойтов: если вы проходите вокруг &admin=1 с запросами GET или POST, чтобы указать, что кто-то является администратором, каждый из ваши пользователи могут легко повысить свои привилегии с помощью двух или трех секунд усилий. Обратите внимание, что эта проблема не всегда очевидна:), но это простой способ объяснить последствия чрезмерного ввода запросов пользователя.

Ответ 5

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