rtgx

SQL Injection

Ukážka možného spôsobu útoku:

// $name - vstup klienta
$name = “ilia’; DELETE FROM users;”;
mysql_query(“SELECT * FROM users WHERE name=’{$name}’”);

Okrem výberu zoznamu užívateľov podľa zadaného parametra bude vymazaná tabuľka users.

Toto však neplatí pre MySQL pri volaní PHP funkcie mysql_query, ktorá nevykoná viacero SQL príkazov v jednom volaní (napr. SELECT a DELETE). Problém však nastane ak použijeme nové rozhranie PHP mysqli, kde je zabudované funcia pre vykonanie viacerých SQL príkazov. Taktiež napríklad databázy SQLite alebo PostgreSQL vykonajú obidva príkazy a nastane popísaný problém.

Magic Quotes

Riešením tohto problému je použitie PHP funkcií stripslashes() a mysql_real_escape_string() nasledujúcim spôsobom:

if (get_magic_quotes_gpc()) {
$name = stripslashes($name);
}
$name = mysql_real_escape_string($name);
mysql_query(“SELECT * FROM users WHERE name=’{$name}’”);

Ak escape nepomáha

Prípad, keď SQL príkaz očakáva celočíselnú hodnotu (integer):

// $name - vstup klienta
$id = “0; DELETE FROM users”;

$id = mysql_real_escape_string($id); // 0; DELETE FROM users
mysql_query(“SELECT * FROM users WHERE id={$id}”);

Riešenie je celkom jenoduché – skonvertovať vstup na typ integer operátorom (int) alebo funkciou intval():

$id = “123; DELETE FROM users”;
$id = (int) $id; // výsledok operácie = 123
mysql_query($conn, “SELECT * FROM users WHERE id={$id}”); // bezpečný príkaz

Spracovanie chybových hlásení SQL

Ošetrenie chýb pri vykonávaní príkazov SQL zabríni potencionálnym zvedavcom dozvedieť sa z týchto hlásení niečo o našej databáze. Tu je obvyklý spôsob výpisu chyby pri zlyhaní:

mysql_query($query) or die(“Failed query: {$query}<br />”.mysql_error());

Kedže tieto informácie môžu byť dôležité pre nás, je potrebné ich niekam ukladať, najjednoduchšou cestou je zapisovanie chybových hlásení do súboru Užívateľovi vypíšeme len bežné hlásenie o nedostupnosti údajov.

function sql_failure_handler($query, $error) {
$msg = htmlspecialchars(“Failed Query: {$query}<br>SQL Error: {$error}”);
error_log($msg, 3, “/home/site/logs/sql_error_log”);
if (defined(‘debug’)) {
return $msg;
}
return “Requested page is temporarily unavailable, please try again later.”;
}
mysql_query($query) or die(sql_failure_handler($query, mysql_error()));
 
PDF dokument Guide to PHP security 3, 135.8 (kB)