@ Чарльз чрезвычайно прав!
Вы подвергаете себя риску нескольких типов известных атак 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()
предназначен только для экранирования переменных данных, NOT имен таблиц,имена столбцов, и особенно поля LIMIT.
LIKE эксплойты: LIKE "$ data%", где $ data может быть "%", который будет возвращать ВСЕ записи ... вполне может быть эксплойтом безопасности ... просто представьте поиск по последним четырем цифрам кредитной карты ... ООП!Теперь хакеры могут получить каждый номер кредитной карты в вашей системе!(Кстати: хранить полные кредитные карты вряд ли когда-либо рекомендуется!)
Эксплуатация Charset: Независимо от того, что говорят ненавистники, 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 () легко обойдется даже самым незрелым хакером.Это потому, что это РЕАКТИВНЫЙ защитный механизм.Это исправляет только очень ограниченные и ИЗВЕСТНЫЕ эксплойты в базе данных.
Все экранирования НИКОГДА не будет достаточно для защиты баз данных.Фактически, вы можете явно РЕАГИРОВАТЬ на каждую ИЗВЕСТНУЮ эксплойт, и в будущем ваш код, скорее всего, станет уязвимым для атак, обнаруженных в будущем.
Правильная и единственная (действительно) защита - ПРОАКТИВНАЯ: Используйте подготовленные заявления.Подготовленные операторы разработаны с особой тщательностью, чтобы выполнялся ТОЛЬКО действительный и ПРОГРАММИРОВАННЫЙ SQL.Это означает, что, если все сделано правильно, шансы неожиданного выполнения SQL-кода могут быть значительно снижены.
Теоретически подготовленные операторы, которые реализованы идеально, будут невосприимчивы ко ВСЕМ атакам, известным и неизвестным, так как ониметод SERVER SIDE, обрабатываемый базой данных сервера и библиотеками, которые взаимодействуют с языком программирования.Таким образом, вы ВСЕГДА гарантированно защищены от КАЖДОГО ИЗВЕСТНОГО ХАКА, как минимум.
И это меньше кода:
$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's 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-сервер. Из-за этого дополнительного уровня защиты вы намного безопаснее, чем просто с помощью экранирования, независимо от того, насколько он тщателен.