Biztonsági kockázatok
Az adatbázisok gyakran tartalmaznak érzékeny adatokat, és veszélyes műveleteket tesznek lehetővé. A Nette Database számos biztonsági funkciót biztosít. Létfontosságú azonban, hogy megértsük a biztonságos és a nem biztonságos API-k közötti különbséget.
SQL injekció
Az SQL injektálás a legsúlyosabb biztonsági kockázat az adatbázisokkal való munka során. Akkor fordul elő, amikor a nem ellenőrzött felhasználói bemenet egy SQL-lekérdezés részévé válik. A támadó saját SQL-parancsokat injektálhat, így adatokat szerezhet vagy módosíthat az adatbázisban.
// ❌ UNSAFE CODE - sebezhető SQL injekcióval szemben
$database->query("SELECT * FROM users WHERE name = '$_GET[name]'");
// A támadó valami ilyesmit adhat be: ' OR '1'='1
// Az eredményül kapott lekérdezés a következő lesz:
// Vagy '1'='1': SELECT * FROM users WHERE name = '' OR '1'='1'
// Ez az összes felhasználót visszaadja!
Ugyanez vonatkozik a Database Explorerre is:
// ❌ UNSAFE CODE
$table->where('name = ' . $_GET['name']);
$table->where("name = '$_GET[name]'");
Biztonságos paraméterezett lekérdezések
Az értékek SQL-lekérdezésekbe történő beszúrásának biztonságos módja a paraméterezett lekérdezések. A Nette Database többféle lehetőséget biztosít ezek használatára.
Helyőrző kérdőjelek
A legegyszerűbb módszer a helyőrző kérdőjelek használata:
// ✅ Biztonságos paraméterezett lekérdezések
$database->query('SELECT * FROM users WHERE name = ?', $_GET['name']);
// ✅ Biztonságos feltétel az Explorerben
$table->where('name = ?', $_GET['name']);
Ugyanez vonatkozik az Adatbázis-kutató összes többi módszerére, amelyek lehetővé teszik a helyőrző kérdőjelekkel és paraméterekkel ellátott kifejezések beillesztését.
Az értékeknek skalár típusúaknak kell lenniük (string
, int
, float
,
bool
) vagy null
. Ha például, $_GET['name']
egy tömb, a Nette Database annak minden
elemét be fogja vonni az SQL-lekérdezésbe, ami nem kívánatos lehet.
Értéktáblák
A INSERT
, UPDATE
vagy WHERE
záradékok esetében használhatunk értéktömböket:
// ✅ Biztonságos BESZÜNTETÉS
$database->query('INSERT INTO users', [
'name' => $_GET['name'],
'email' => $_GET['email'],
]);
// ✅ Biztonságos UPDATE
$database->query('UPDATE users SET', [
'name' => $_GET['name'],
'email' => $_GET['email'],
], 'WHERE id = ?', $_GET['id']);
A Nette Database automatikusan megszünteti a paraméteres lekérdezéseken keresztül átadott értékeket. Biztosítanunk kell azonban a paraméterek helyes adattípusát.
A tömbkulcsok nem biztonságos API
Míg a tömbök értékei biztonságosak, ugyanez nem mondható el a kulcsokról:
// ❌ UNSAFE CODE - a kulcsok SQL injekciót tartalmazhatnak
$database->query('INSERT INTO users', $_GET);
$database->query('SELECT * FROM users WHERE', $_GET);
$table->where($_GET);
A INSERT
és a UPDATE
parancsok esetében ez kritikus biztonsági hiba – egy támadó bármelyik
oszlopot beszúrhatja vagy módosíthatja az adatbázisban. Például beállíthatja a is_admin = 1
címet, vagy
tetszőleges adatokat illeszthet be érzékeny oszlopokba.
A WHERE
feltételek esetén ez még veszélyesebb, mert lehetővé teszi a SQL enumerációt – egy olyan
technikát, amellyel fokozatosan lehet információt szerezni az adatbázisról. Egy támadó megkísérelhetné feltárni a
dolgozói fizetéseket a $_GET
beillesztésével, például így:
$_GET = ['salary >', 100000]; // megkezdi a fizetési sávok meghatározását
A fő probléma azonban az, hogy a WHERE
feltételek támogatják az SQL-kifejezéseket a kulcsokban:
// Az operátorok jogszerű használata a kulcsokban
$table->where([
'age > ?' => 18,
'ROUND(score, ?) > ?' => [2, 75.5],
]);
// ❌ UNSAFE: a támadó saját SQL-t tud beadni
$_GET = ['1) UNION SELECT name, salary FROM users WHERE (is_admin = ?' => 1];
$table->where($_GET); // lehetővé teszi a támadó számára az adminisztrátori fizetések megszerzését
Ez ismét SQL injekció.
Az oszlopok fehér listázása
Ha engedélyezni szeretné, hogy a felhasználók oszlopokat választhassanak, mindig használjon fehérlistát:
// ✅ Biztonságos feldolgozás - csak engedélyezett oszlopok
$allowedColumns = ['name', 'email', 'active'];
$values = array_intersect_key($_GET, array_flip($allowedColumns));
$database->query('INSERT INTO users', $values);
Dinamikus azonosítók
A dinamikus tábla- és oszlopnevekhez használja a ?name
helyőrzőt:
// ✅ Megbízható azonosítók biztonságos használata
$table = 'users';
$column = 'name';
$database->query('SELECT ?name FROM ?name', $column, $table);
// ❌ UNSAFE - soha ne használjon felhasználói bemenetet
$database->query('SELECT ?name FROM users', $_GET['column']);
A ?name
szimbólumot csak az alkalmazáskódban meghatározott megbízható értékek esetén szabad használni.
A felhasználó által megadott értékekhez ismét használjon fehérlistát.