È sicuro usare solo intval per disinfettare l'input dell'utente per una selezione del database, come nell'esempio seguente?
$id = intval($_GET['id']);
$query = "SELECT * FROM table WHERE id='$id'";
intval
è garantito per produrre un intero (restituisce 0
se "non riesce") e un intero è una cosa sicura da usare in una query MySQL. Questa risposta link su SO è d'accordo:
Yes, intval() is safe. There is absolutely no way to perform an SQL injection when the parameter is converted to integer, because (obviously) the format of an integer does not allow putting SQL keywords (or quotes, or whatever) in it.
Sospetto che lo stesso vale per usi diversi da SQL.
La regola empirica è: se l'input proviene da qualsiasi altro luogo rispetto al codice stesso, i dati forniti devono essere considerati "contaminati". Dovrai assicurarti che il valore sia quello che ti aspetti e non rovinare la tua dichiarazione SQL (iniezione).
Anche se mi chiedo perché non stai usando / utilizzando PDO e usi i marcatori nella tua dichiarazione, quindi queste cose vengono gestite automaticamente.
Ma sceglierei di fare qualcosa di simile (usando un operatore ternario):
$id = (is_numeric($id) && $id > 0) ? $id : false;
if ($id !== false) {
... code goes here ...
}
Raddoppia la possibilità che $id
sia un numero intero realistico.
Per prima cosa, controlla se $ id è un valore numerico valido (usando is_numeric) quindi, infine, lancia l'id $ per digitare (int).
Gli input sono per definizione sicuri per qualsiasi situazione a cui possa pensare, sebbene per l'uso come parametro di un comando CLI, assicurati che non siano negativi poiché il trattino principale può significare che vengono presi come flag al posto di params; e per i casi in cui vi sono limiti alle dimensioni dello spazio di archiviazione, fai attenzione ai limiti in quanto i flussi in eccesso potrebbero essere sfortunati.
Tuttavia, sarei propenso a creare una serie di metodi di convalida dell'input dell'utente, se lo fai spesso. Qualcosa come:
public function getValidInt(
string $name,
int $minValue=PHP_INT_MIN,
int $maxValue=PHP_INT_MAX,
int $defaultValue=0
) {
assert($minValue < $maxValue, 'Min bound must be less than max.');
if (!array_key_exists($name, $_GET)) {
return $defaultValue;
}
$userValue = (int)$_GET[$name];
// Could instead return $defaultValue if it's out of bounds.
return min($maxValue, max($minValue, $userValue));
}
In questo modo è estremamente semplice ottenere valori untiinted e controllati dai limiti con un valore predefinito valido se non vengono specificati.
Per le stringhe, potrebbe essere simile a:
public function getValidString(
string $name,
string $validationRegex='.*',
int $minLength=0,
int $maxLength=PHP_INT_MAX,
int $defaultValue=''
)
... e così via.
Aggiungere cose simili all'inizio del tuo progetto significa che starai pensando a ogni input da parte dell'utente e non accumulerai un enorme compito di debito tecnologico di "convalidare tutti gli input dell'utente" mentre ti avvicini alla fine del progetto. Tutto già deve essere corretto; le stringhe saranno inserite nella whitelist, le inte saranno controllate e così via.
L'escaping e il detainting sull'input dovrebbero idealmente essere trattati come un separato interesse dall'escaping per l'uso in un database, visualizzati come HTML, ecc. La rimozione di tag HTML dannosi dalle stringhe è qualcosa che dovresti fare su input (non dovrebbe esserci nessuno chiamato <span onclick="alert('whee')">Fred</span>
memorizzato nel tuo database, anche se non hai ancora mostrato il loro nome sullo schermo. Scappare prima di lanciare una variabile in HTML o MySQL o riga di comando dovrebbe essere la tua ultima conferma di ultima possibilità che hai assicurato le variabili di salvataggio, non il tuo solo controllo.
Is it safe to only use intval to sanitize the user input for a database select, as in the following example?
Risposta breve: No.
OK, intval () ti fornisce sempre un valore intero che non infrange il tuo SQL.
Il problema è che, mentre il valore restituito è un numero intero, è valido ? Puoi garantire che il valore restituito da intval (ad esempio 0) mai corrisponda a un record di dati reale ? Con il codice che non esegue ulteriori verifiche, è possibile creare inavvertitamente un record con una chiave pari a 0 e consentire a più utenti di accedere allo stesso record, poiché tutti [tutti] inseriscono valori numerici non validi. Non bene.
Tutto per la mancanza di un messaggio di errore educato come "L'ID deve essere numerico".
Leggi altre domande sui tag php mysql code-security