sql >> Databáze >  >> RDS >> Mysql

Jsou mysql_real_escape_string() a mysql_escape_string() dostatečné pro zabezpečení aplikace?

@Charles má naprostou pravdu!

Vystavujete se riziku několika typů známých SQL útoky, včetně, jak jste zmínil

  • Vkládání SQL:Ano! Mysql_Escape_String vás pravděpodobně STÁLE udržuje náchylné k injekcím SQL, v závislosti na tom, kde ve svých dotazech používáte proměnné PHP.

Zvažte toto:

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

Lze z toho bezpečně a přesně uniknout tímto způsobem? NE! Proč? protože hacker může docela dobře udělat toto:

Opakujte po mně:

mysql_real_escape_string() je určen pouze k úniku proměnných dat, NE názvy tabulek, názvy sloupců a zejména ne LIMIT polí.

  • LIKE využívá:LIKE "$data%", kde $data může být "%", což by vrátilo VŠECHNY záznamy ... což může velmi dobře být bezpečnostní exploit... jen si představte vyhledávání podle posledních čtyř číslic kreditní karty... Jejda! Nyní mohou hackeři potenciálně získat každé číslo kreditní karty ve vašem systému! (BTW:Ukládání úplných kreditních karet se stěží doporučuje!)

  • Charset Exploits:Bez ohledu na to, co říkají odpůrci, Internet Explorer je stále , v roce 2011, zranitelný vůči používání Character Set Exploits, a to pokud správně jste svou stránku HTML navrhli s ekvivalentem <meta name="charset" value="UTF-8"/> ! Tyto útoky jsou VELMI ošklivé, protože dávají hackerovi stejnou kontrolu jako přímé SQL injekce:např. úplný.

Zde je několik příkladů kódu, které toto vše demonstrují:

// 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);
}

Zde jsou výsledky tohoto kódu, když jsou předány různé vstupy:

$ 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 Results:Vrátí každý sloupec a každý výsledek.

Pak jsou tu SKUTEČNĚ ošklivé LIMIT exploity:

$ 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. 

Je irelevantní, zda rozumíte SQL v útocích nebo ne. To prokázalo, že mysql_real_escape_string() je snadné obcházejí i ti nejzralejší hackeři. Je to proto, že se jedná o REAKTIVNÍ obranný mechanismus. Opravuje pouze velmi omezené a ZNÁMÉ exploity v databázi.

Všechny úniky NIKDY nebudou stačit k zabezpečení databází. Ve skutečnosti můžete výslovně REAGOVAT na každý ZNÁMÝ exploit a v budoucnu se váš kód s největší pravděpodobností stane zranitelným vůči útokům objeveným v budoucnu.

Správná a jediná (skutečně) obrana je PROAKTIVNÍ:Používejte připravená prohlášení. Připravené příkazy jsou navrženy se zvláštní péčí tak, aby bylo provedeno POUZE platné a PROGRAMOVANÉ SQL. To znamená, že když se to udělá správně, šance na neočekávané provedení SQL se dramaticky sníží.

Teoreticky by připravené příkazy, které jsou dokonale implementovány, byly odolné vůči VŠEM útokům, známým i neznámým, protože se jedná o techniku ​​SERVEROVÉ STRANY, kterou zpracovávají SAMY DATABÁZOVÉ SERVERY a knihovny, které jsou rozhraním s programovacím jazykem. Proto máte VŽDY zaručeno, že budete chráněni před KAŽDÝM ZNÁMÝM HACKEM, a to minimálně.

A je to méně kódu:

$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())) { }

Teď to nebylo tak těžké, že? A je to o čtyřicet sedm procent méně kódu (195 znaků (PDO) vs 375 znaků (mysql_). Tomu říkám "plné vítězství".

EDIT:Abych se vyjádřil ke všem kontroverzím, které tato odpověď vyvolala, dovolte mi zopakovat, co jsem již řekl:

Použití připravených příkazů umožňuje využít ochranná opatření samotného SQL serveru, a proto jste chráněni před věcmi, o kterých lidé na SQL serveru vědí. Díky této mimořádné úrovni ochrany jste mnohem bezpečnější než pouhý únik, bez ohledu na to, jak důkladný.



  1. Nejrychlejší způsob, jak najít vzdálenost mezi dvěma zeměpisnými/délkovými body

  2. Datový model aplikace pro maratonský trénink

  3. Jak vybrat poslední záznam tabulky v SQL?

  4. Jak připojit programy C++ k MariaDB