sql >> Database >  >> RDS >> Mysql

Zijn mysql_real_escape_string() en mysql_escape_string() voldoende voor app-beveiliging?

@Charles heeft volkomen gelijk!

U loopt risico op meerdere soorten bekende SQL-aanvallen, waaronder, zoals u al zei

  • SQL-injectie:ja! Mysql_Escape_String houdt u waarschijnlijk NOG STEEDS vatbaar voor SQL-injecties, afhankelijk van waar u PHP-variabelen in uw zoekopdrachten gebruikt.

Overweeg dit:

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

Kan dat op die manier veilig en nauwkeurig worden ontvlucht? NEE! Waarom? omdat een hacker dit heel goed nog zou kunnen doen:

Herhaal na mij:

mysql_real_escape_string() is alleen bedoeld om te ontsnappen aan variabele gegevens, NIET tabelnamen, kolomnamen en vooral geen LIMIT-velden.

  • LIKE exploits:LIKE "$data%" waar $data "%" zou kunnen zijn, wat ALLE records zou retourneren ... wat heel goed kan zijn een beveiligingsexploit... stel je een zoekopdracht voor met de laatste vier cijfers van een creditcard... OOP's! Nu kunnen de hackers mogelijk elk creditcardnummer in uw systeem ontvangen! (BTW:het bewaren van volle creditcards wordt bijna nooit aanbevolen!)

  • Charset-exploits:wat de haters ook zeggen, Internet Explorer is nog steeds , in 2011, kwetsbaar voor karaktersetexploits, en dat is als je hebt je HTML-pagina correct ontworpen, met het equivalent van <meta name="charset" value="UTF-8"/> ! Deze aanvallen zijn ERG gemeen omdat ze de hacker evenveel controle geven als gewone SQL-injecties:b.v. vol.

Hier is een voorbeeldcode om dit alles te demonstreren:

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

Hier zijn de resultaten van deze code wanneer verschillende invoer wordt doorgegeven:

$ 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:Retourneert elke kolom en elk resultaat.

Dan zijn er nog de ECHT vervelende LIMIT-exploits:

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

Het maakt niet uit of u de SQL in de aanvallen begrijpt of niet. Dit heeft aangetoond dat mysql_real_escape_string() gemakkelijk is omzeild door zelfs de meest onvolwassen hackers. Dat komt omdat het een REACTIEF verdedigingsmechanisme is. Het repareert slechts zeer beperkte en BEKENDE exploits in de database.

Alle ontsnappingen zullen NOOIT voldoende zijn om databases te beveiligen. U kunt zelfs expliciet REAGEREN op elke BEKENDE exploit en in de toekomst zal uw code hoogstwaarschijnlijk kwetsbaar worden voor aanvallen die in de toekomst worden ontdekt.

De juiste, en enige (echt) verdediging is een PROACTIEVE:gebruik voorbereide verklaringen. Voorbereide instructies zijn met speciale zorg ontworpen, zodat ALLEEN geldige en GEPROGRAMMEERDE SQL wordt uitgevoerd. Dit betekent dat, als het correct wordt gedaan, de kans dat onverwachte SQL kan worden uitgevoerd drastisch wordt verminderd.

Theoretisch zouden voorbereide instructies die perfect zijn geïmplementeerd, ongevoelig zijn voor ALLE aanvallen, bekende en onbekende, omdat ze een SERVER SIDE-techniek zijn, afgehandeld door de DATABASE SERVERS ZELF en de bibliotheken die communiceren met de programmeertaal. Daarom bent u ALTIJD gegarandeerd beschermd tegen ELKE BEKENDE HACK, op het absolute minimum.

En het is minder code:

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

Dat was toch niet zo moeilijk? En het is zevenenveertig procent minder code (195 tekens (BOB) versus 375 tekens (mysql_). Dat noem ik "vol met winst".

EDIT:Om alle controverse aan te pakken die dit antwoord heeft veroorzaakt, wil ik u graag herhalen wat ik al heb gezegd:

Door voorbereide instructies te gebruiken, kunt u de beschermende maatregelen van de SQL-server zelf benutten, en daarom bent u beschermd tegen dingen waar de mensen van de SQL-server vanaf weten. Door dit extra niveau van bescherming ben je veel veiliger dan door alleen te ontsnappen, hoe grondig ook.



  1. Wat betekent het om een ​​Microsoft Access-database te splitsen?

  2. SQLSTATE [HY000] [2002] Een verbindingspoging is mislukt.. - Bij een poging om verbinding te maken van een lokale naar een externe server

  3. Op proxy gebaseerde dynamische gegevensmaskering in FieldShield

  4. Een berekende kolom maken die gegevens uit een andere tabel in SQL Server gebruikt