@Charles е изключително прав!
Излагате се на риск от различни видове известни SQL атаки, включително, както споменахте
- SQL инжекция:Да! Mysql_Escape_String вероятно ОЩЕ ви държи податливи на SQL инжекции, в зависимост от това къде използвате PHP променливи във вашите заявки.
Помислете за това:
$sql = "SELECT number FROM PhoneNumbers " .
"WHERE " . mysql_real_escape_string($field) . " = " . mysql_real_escape_string($value);
Може ли това сигурно и точно да се избегне по този начин? НЕ! Защо? защото хакер все още може да направи това:
Повторете след мен:
mysql_real_escape_string()
е предназначен само за избягване на променливи данни, НЕ имена на таблици, имена на колони и особено не LIMIT полета.
-
LIKE експлойти:КАТО "$data%", където $data може да бъде "%", което ще върне ВСИЧКИ записи ... което може много да бъде експлоат за сигурност... само си представете търсене по последните четири цифри на кредитна карта... ООП! Сега хакерите потенциално могат да получат всеки номер на кредитна карта във вашата система! (BTW:Съхраняването на пълни кредитни карти почти не се препоръчва!)
-
Експлойти на 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 да може да бъде изпълнен са драстично намалени.
Теоретично подготвените оператори, които се изпълняват перфектно, биха били непроницаеми за ВСИЧКИ атаки, известни и неизвестни, тъй като те са техника от СЪРВЪРНАТА страна, обработвана от САМИ СЪРВЪРИТЕ НА БАЗА ДАННИ и библиотеките, които взаимодействат с езика за програмиране. Следователно, ВИНАГИ гарантирано ще бъдете защитени срещу ВСЕКИ ИЗВЕСТЕН ХАК, най-малкото.
И е по-малко код:
$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 сървъра знаят. Поради това допълнително ниво на защита, вие сте много по-безопасни, отколкото просто да използвате бягство, без значение колко задълбочено е.