Nette Documentation Preview

syntax
Rischi per la sicurezza
***********************

.[perex]
I database contengono spesso dati sensibili e consentono operazioni pericolose. Nette Database offre una serie di funzioni di sicurezza. Tuttavia, è fondamentale capire la differenza tra API sicure e non sicure.


Iniezione SQL .[#toc-sql-injection]
===================================

L'iniezione SQL è il rischio di sicurezza più grave quando si lavora con i database. Si verifica quando un input dell'utente non controllato diventa parte di una query SQL. Un aggressore può iniettare i propri comandi SQL, ottenendo o modificando i dati nel database.

```php
// Codice non sicuro - vulnerabile all'iniezione SQL
$database->query("SELECT * FROM users WHERE name = '$_GET[name]'");

// L'attaccante può inserire qualcosa come: ' OR '1'='1
// La query risultante sarà:
// SELECT * FROM users WHERE name = '' OR '1'='1'
// Questo restituisce tutti gli utenti!
```

Lo stesso vale per Database Explorer:

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


Query parametriche sicure .[#toc-safe-parameterized-queries]
============================================================

Il modo sicuro per inserire valori nelle query SQL è quello delle query parametrizzate. Nette Database offre diversi modi per utilizzarle.


Punti interrogativi segnaposto .[#toc-placeholder-question-marks]
-----------------------------------------------------------------

Il metodo più semplice è quello di utilizzare dei punti interrogativi segnaposto:

```php
// Query parametriche sicure
$database->query('SELECT * FROM users WHERE name = ?', $_GET['name']);

// ✅ Condizione sicura in Explorer
$table->where('name = ?', $_GET['name']);
```

Lo stesso vale per tutti gli altri metodi di Database Explorer che consentono di inserire espressioni con punti interrogativi e parametri segnaposto.

.[warning]
I valori devono essere di tipo scalare (`string`, `int`, `float`, `bool`) o `null`. Se, ad esempio, è un array, Nette Database includerà tutti i suoi elementi nella query SQL, il che può essere indesiderato, `$_GET['name']` è un array, Nette Database includerà tutti i suoi elementi nella query SQL, il che può essere indesiderato.


Array di valori .[#toc-value-arrays]
------------------------------------

Per le clausole `INSERT`, `UPDATE` o `WHERE` si possono utilizzare array di valori:

```php
// INSERIMENTO sicuro
$database->query('INSERT INTO users', [
	'name' => $_GET['name'],
	'email' => $_GET['email'],
]);

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

Nette Database esegue automaticamente l'escape di tutti i valori passati attraverso le query parametrizzate. Tuttavia, è necessario garantire il corretto tipo di dati dei parametri.


Le chiavi di array non sono un'API sicura .[#toc-array-keys-are-not-a-safe-api]
===============================================================================

Mentre i valori negli array sono sicuri, lo stesso non si può dire per le chiavi:

```php
// Codice non sicuro: le chiavi possono contenere un'iniezione SQL.
$database->query('INSERT INTO users', $_GET);
$database->query('SELECT * FROM users WHERE', $_GET);
$table->where($_GET);
```

Per i comandi `INSERT` e `UPDATE` si tratta di una falla di sicurezza critica: un utente malintenzionato potrebbe inserire o modificare qualsiasi colonna del database. Ad esempio, potrebbe impostare `is_admin = 1` o inserire dati arbitrari in colonne sensibili.

Nelle condizioni di `WHERE`, questo è ancora più pericoloso perché permette la **Enumerazione SQL**, una tecnica per recuperare gradualmente informazioni sul database. Un utente malintenzionato potrebbe tentare di esplorare gli stipendi dei dipendenti iniettando in `$_GET` questo tipo di dati:

```php
$_GET = ['salary >', 100000];   // inizia a determinare le fasce salariali
```

Il problema principale, tuttavia, è che le condizioni di `WHERE` supportano espressioni SQL nelle chiavi:

```php
// Uso legittimo degli operatori nelle chiavi
$table->where([
    'age > ?' => 18,
    'ROUND(score, ?) > ?' => [2, 75.5],
]);

// Non sicuro: l'attaccante può iniettare il proprio SQL.
$_GET = ['1) UNION SELECT name, salary FROM users WHERE (is_admin = ?' => 1];
$table->where($_GET); // permette all'attaccante di ottenere stipendi da amministratore
```

Si tratta ancora una volta di **Iniezione SQL**.


Eliminazione delle colonne .[#toc-whitelisting-columns]
-------------------------------------------------------

Se si desidera consentire agli utenti di scegliere le colonne, utilizzare sempre una whitelist:

```php
// ✅ Elaborazione sicura - solo colonne consentite
$allowedColumns = ['name', 'email', 'active'];
$values = array_intersect_key($_GET, array_flip($allowedColumns));

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


Identificatori dinamici .[#toc-dynamic-identifiers]
===================================================

Per i nomi dinamici di tabelle e colonne, utilizzare il segnaposto `?name`:

```php
// ✅ Uso sicuro di identificatori affidabili
$table = 'users';
$column = 'name';
$database->query('SELECT ?name FROM ?name', $column, $table);

// ❌ UNSAFE - non utilizzare mai l'input dell'utente
$database->query('SELECT ?name FROM users', $_GET['column']);
```

Il simbolo `?name` deve essere utilizzato solo per i valori affidabili definiti nel codice dell'applicazione. Per i valori forniti dall'utente, utilizzare nuovamente una whitelist.

Rischi per la sicurezza

I database contengono spesso dati sensibili e consentono operazioni pericolose. Nette Database offre una serie di funzioni di sicurezza. Tuttavia, è fondamentale capire la differenza tra API sicure e non sicure.

Iniezione SQL

L'iniezione SQL è il rischio di sicurezza più grave quando si lavora con i database. Si verifica quando un input dell'utente non controllato diventa parte di una query SQL. Un aggressore può iniettare i propri comandi SQL, ottenendo o modificando i dati nel database.

// Codice non sicuro - vulnerabile all'iniezione SQL
$database->query("SELECT * FROM users WHERE name = '$_GET[name]'");

// L'attaccante può inserire qualcosa come: ' OR '1'='1
// La query risultante sarà:
// SELECT * FROM users WHERE name = '' OR '1'='1'
// Questo restituisce tutti gli utenti!

Lo stesso vale per Database Explorer:

// ❌ CODICE NON SICURO
$table->where('name = ' . $_GET['name']);
$table->where("name = '$_GET[name]'");

Query parametriche sicure

Il modo sicuro per inserire valori nelle query SQL è quello delle query parametrizzate. Nette Database offre diversi modi per utilizzarle.

Punti interrogativi segnaposto

Il metodo più semplice è quello di utilizzare dei punti interrogativi segnaposto:

// Query parametriche sicure
$database->query('SELECT * FROM users WHERE name = ?', $_GET['name']);

// ✅ Condizione sicura in Explorer
$table->where('name = ?', $_GET['name']);

Lo stesso vale per tutti gli altri metodi di Database Explorer che consentono di inserire espressioni con punti interrogativi e parametri segnaposto.

I valori devono essere di tipo scalare (string, int, float, bool) o null. Se, ad esempio, è un array, Nette Database includerà tutti i suoi elementi nella query SQL, il che può essere indesiderato, $_GET['name'] è un array, Nette Database includerà tutti i suoi elementi nella query SQL, il che può essere indesiderato.

Array di valori

Per le clausole INSERT, UPDATE o WHERE si possono utilizzare array di valori:

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

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

Nette Database esegue automaticamente l'escape di tutti i valori passati attraverso le query parametrizzate. Tuttavia, è necessario garantire il corretto tipo di dati dei parametri.

Le chiavi di array non sono un'API sicura

Mentre i valori negli array sono sicuri, lo stesso non si può dire per le chiavi:

// Codice non sicuro: le chiavi possono contenere un'iniezione SQL.
$database->query('INSERT INTO users', $_GET);
$database->query('SELECT * FROM users WHERE', $_GET);
$table->where($_GET);

Per i comandi INSERT e UPDATE si tratta di una falla di sicurezza critica: un utente malintenzionato potrebbe inserire o modificare qualsiasi colonna del database. Ad esempio, potrebbe impostare is_admin = 1 o inserire dati arbitrari in colonne sensibili.

Nelle condizioni di WHERE, questo è ancora più pericoloso perché permette la Enumerazione SQL, una tecnica per recuperare gradualmente informazioni sul database. Un utente malintenzionato potrebbe tentare di esplorare gli stipendi dei dipendenti iniettando in $_GET questo tipo di dati:

$_GET = ['salary >', 100000];   // inizia a determinare le fasce salariali

Il problema principale, tuttavia, è che le condizioni di WHERE supportano espressioni SQL nelle chiavi:

// Uso legittimo degli operatori nelle chiavi
$table->where([
    'age > ?' => 18,
    'ROUND(score, ?) > ?' => [2, 75.5],
]);

// Non sicuro: l'attaccante può iniettare il proprio SQL.
$_GET = ['1) UNION SELECT name, salary FROM users WHERE (is_admin = ?' => 1];
$table->where($_GET); // permette all'attaccante di ottenere stipendi da amministratore

Si tratta ancora una volta di Iniezione SQL.

Eliminazione delle colonne

Se si desidera consentire agli utenti di scegliere le colonne, utilizzare sempre una whitelist:

// ✅ Elaborazione sicura - solo colonne consentite
$allowedColumns = ['name', 'email', 'active'];
$values = array_intersect_key($_GET, array_flip($allowedColumns));

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

Identificatori dinamici

Per i nomi dinamici di tabelle e colonne, utilizzare il segnaposto ?name:

// ✅ Uso sicuro di identificatori affidabili
$table = 'users';
$column = 'name';
$database->query('SELECT ?name FROM ?name', $column, $table);

// ❌ UNSAFE - non utilizzare mai l'input dell'utente
$database->query('SELECT ?name FROM users', $_GET['column']);

Il simbolo ?name deve essere utilizzato solo per i valori affidabili definiti nel codice dell'applicazione. Per i valori forniti dall'utente, utilizzare nuovamente una whitelist.