Varnostna tveganja

Podatkovne zbirke pogosto vsebujejo občutljive podatke in omogočajo nevarne operacije. Podatkovna baza Nette zagotavlja številne varnostne funkcije. Vendar je ključnega pomena, da razumete razliko med varnimi in nevarnimi vmesniki API.

Vsiljevanje SQL

Vbrizgavanje SQL je najresnejše varnostno tveganje pri delu s podatkovnimi zbirkami. Pojavi se, ko nepreverjen uporabniški vnos postane del poizvedbe SQL. Napadalec lahko vnese svoje ukaze SQL in tako pridobi ali spremeni podatke v zbirki podatkov.

// ❌ NEVARNA KODA - ranljiva za vbrizgavanje SQL
$database->query("SELECT * FROM users WHERE name = '$_GET[name]'");

// Napadalec lahko vnese nekaj takega: ' ALI '1'='1
// Rezultat poizvedbe bo:
// SELECT * FROM users WHERE name = '' OR '1'='1'
// To vrne vse uporabnike!

Enako velja za Raziskovalca podatkovnih zbirk:

// ❌ KODEKS NEVARNOSTI
$table->where('name = ' . $_GET['name']);
$table->where("name = '$_GET[name]'");

Varne parametrirane poizvedbe

Varen način za vstavljanje vrednosti v poizvedbe SQL je uporaba parametriziranih poizvedb. Podatkovna baza Nette ponuja več načinov za njihovo uporabo.

Namestni vprašalni znaki

Najpreprostejša metoda je uporaba nadomestnih vprašalnih znakov:

// ✅ Varne parametrizirane poizvedbe
$database->query('SELECT * FROM users WHERE name = ?', $_GET['name']);

// ✅ Varno stanje v Raziskovalcu
$table->where('name = ?', $_GET['name']);

Enako velja za vse druge metode v Raziskovalcu podatkovne baze, ki omogočajo vstavljanje izrazov z nadomestnimi vprašalnimi znaki in parametri.

Vrednosti morajo biti skalarnega tipa (string, int, float, bool) ali null. Če npr, $_GET['name'] je polje, bo podatkovna baza Nette v poizvedbo SQL vključila vse njegove elemente, kar je lahko nezaželeno.

Polja vrednosti

Za stavke INSERT, UPDATE ali WHERE lahko uporabimo polja vrednosti:

// ✅ Safe INSERT
$database->query('INSERT INTO users', [
	'name' => $_GET['name'],
	'email' => $_GET['email'],
]);

// ✅ varen UPDATE
$database->query('UPDATE users SET', [
	'name' => $_GET['name'],
	'email' => $_GET['email'],
], 'WHERE id = ?', $_GET['id']);

Podatkovna zbirka Nette samodejno izloči vse vrednosti, posredovane prek parametriziranih poizvedb. Kljub temu moramo zagotoviti pravilno podatkovno vrsto parametrov.

Ključi matrike niso varen API

Medtem ko so vrednosti v poljih varne, tega ne moremo trditi za ključe:

// ❌ NEVARNA KODA - ključi lahko vsebujejo SQL injekcijo
$database->query('INSERT INTO users', $_GET);
$database->query('SELECT * FROM users WHERE', $_GET);
$table->where($_GET);

Za ukaze INSERT in UPDATE je to kritična varnostna pomanjkljivost – napadalec lahko vstavi ali spremeni kateri koli stolpec v zbirki podatkov. Tako bi lahko na primer nastavil is_admin = 1 ali vstavil poljubne podatke v občutljive stolpce.

Pri pogojih za ukaz WHERE je to še bolj nevarno, saj omogoča izpolnjevanje podatkovne zbirke – tehniko za postopno pridobivanje informacij o podatkovni zbirki. Napadalec bi lahko poskušal raziskati plače zaposlenih tako, da bi vnesel v $_GET takole:

$_GET = ['salary >', 100000];   // začne določati plačne razrede.

Glavna težava pa je, da pogoji WHERE podpirajo izraze SQL v ključih:

// Zakonita uporaba operatorjev v ključih
$table->where([
    'age > ?' => 18,
    'ROUND(score, ?) > ?' => [2, 75.5],
]);

// ❌ NEvarno: napadalec lahko vnese svoj SQL
$_GET = ['1) UNION SELECT name, salary FROM users WHERE (is_admin = ?' => 1];
$table->where($_GET); // omogoča napadalcu, da pridobi administratorske plače

To je ponovno vbrizgavanje SQL.

Dodajanje stolpcev na belo listo

Če želite uporabnikom dovoliti izbiro stolpcev, vedno uporabite beli seznam:

// ✅ Varna obdelava - samo dovoljeni stolpci
$allowedColumns = ['name', 'email', 'active'];
$values = array_intersect_key($_GET, array_flip($allowedColumns));

$database->query('INSERT INTO users', $values);

Dinamični identifikatorji

Za dinamična imena tabel in stolpcev uporabite nosilec ?name:

// ✅ Varna uporaba zaupanja vrednih identifikatorjev
$table = 'users';
$column = 'name';
$database->query('SELECT ?name FROM ?name', $column, $table);

// ❌ UNSAFE - nikoli ne uporabljajte uporabniškega vnosa
$database->query('SELECT ?name FROM users', $_GET['column']);

Simbol ?name se sme uporabljati samo za zaupanja vredne vrednosti, določene v aplikacijski kodi. Za vrednosti, ki jih določi uporabnik, ponovno uporabite beli seznam.

različica: 4.0