Nette Documentation Preview

syntax
Biztonsági kockázatok
*********************

.[perex]
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ó .[#toc-sql-injection]
==================================

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.

```php
// ❌ 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:

```php
// ❌ UNSAFE CODE
$table->where('name = ' . $_GET['name']);
$table->where("name = '$_GET[name]'");
```


Biztonságos paraméterezett lekérdezések .[#toc-safe-parameterized-queries]
==========================================================================

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 .[#toc-placeholder-question-marks]
------------------------------------------------------

A legegyszerűbb módszer a helyőrző kérdőjelek használata:

```php
// ✅ 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.

.[warning]
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 .[#toc-value-arrays]
--------------------------------

A `INSERT`, `UPDATE` vagy `WHERE` záradékok esetében használhatunk értéktömböket:

```php
// ✅ 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 .[#toc-array-keys-are-not-a-safe-api]
=======================================================================

Míg a tömbök értékei biztonságosak, ugyanez nem mondható el a kulcsokról:

```php
// ❌ 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:

```php
$_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:

```php
// 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 .[#toc-whitelisting-columns]
--------------------------------------------------------

Ha engedélyezni szeretné, hogy a felhasználók oszlopokat választhassanak, mindig használjon fehérlistát:

```php
// ✅ 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 .[#toc-dynamic-identifiers]
================================================

A dinamikus tábla- és oszlopnevekhez használja a `?name` helyőrzőt:

```php
// ✅ 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.

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.