Dovrei mysql_real_escape_string tutti i cookie che ricevo dall'utente per evitare l'iniezione di mysql in php?
-
01-07-2019 - |
Domanda
Quando un utente accede al mio sito, il mio script verifica la presenza di 2 cookie che memorizzano l'ID utente + parte della password, per accedervi automaticamente.
È possibile modificare il contenuto dei cookie tramite un editor di cookie, quindi immagino sia possibile aggiungere contenuto dannoso a un cookie scritto?
Dovrei aggiungere mysql_real_escape_string
(o qualcos'altro) a tutte le mie chiamate cookie o esiste una sorta di procedura integrata che non consente che ciò accada?
Soluzione
Cosa tu Veramente Ciò che devi fare è non inviare questi valori dei cookie che sono in primo luogo hackerabili.Invece, perché non eseguire l'hashing del nome utente, della password e di un sale (segreto) e impostarlo come valore del cookie?cioè.:
define('COOKIE_SALT', 'secretblahblahlkdsfklj');
$cookie_value = sha1($username.$password.COOKIE_SALT);
Quindi sai che il valore del cookie sarà sempre una stringa esadecimale di 40 caratteri e puoi confrontare il valore che l'utente restituisce con qualunque cosa sia presente nel database per decidere se sono validi o meno:
if ($user_cookie_value == sha1($username_from_db.$password_drom_db.COOKIE_SALT)) {
# valid
} else {
#not valid
}
mysql_real_escape_string
fa un ulteriore successo al database, a proposito (molte persone non si rendono conto che richiede una connessione DB e interroga MySQL).
Il modo migliore per fare quello che vuoi se non puoi cambiare la tua app e insisti nell'usare valori di cookie modificabili è usare istruzioni preparate con parametri associati.
Altri suggerimenti
Lo scopo di mysql_real_escape_string non è proteggere dagli attacchi injection, ma garantire che i dati siano archiviati accuratamente nel database.Pertanto, dovrebbe essere richiamato su QUALSIASI stringa che entra nel database, indipendentemente dalla sua origine.
Dovresti, tuttavia, Anche utilizzare query parametrizzate (tramite mysqli o PDO) per proteggersi dall'iniezione SQL.Altrimenti rischi di finire come la scuola della piccola Bobby Tables.
Utilizzo solo mysql_real_escape_string prima di inserire variabili in un'istruzione SQL.Ti confonderai solo se alcune delle tue variabili lo sono Già sei scappato, e poi scappi di nuovo da loro.È un classico bug che vedi nelle webapp dei blog dei principianti:
Quando qualcuno scrive un apostrofo continua ad aggiungere barre rovinando le pagine del blog.
Il valore di una variabile non è pericoloso di per sé:è solo quando lo metti in una corda o qualcosa di simile che inizi a vagare in acque pericolose.
Naturalmente, però, non fidarti mai di nulla che provenga dal lato client.
Le istruzioni preparate e l'associazione dei parametri sono sempre una buona strada da percorrere.
PEAR::MDB2 supporta istruzioni preparate, ad esempio:
$db = MDB2::factory( $dsn );
$types = array( 'integer', 'text' );
$sth = $db->prepare( "INSERT INTO table (ID,Text) (?,?)", $types );
if( PEAR::isError( $sth ) ) die( $sth->getMessage() );
$data = array( 5, 'some text' );
$result = $sth->execute( $data );
$sth->free();
if( PEAR::isError( $result ) ) die( $result->getMessage() );
Ciò consentirà solo ai dati corretti e alla quantità preimpostata di variabili di entrare nel database.
Ovviamente dovresti convalidare i dati prima di arrivare a questo punto, ma preparare le dichiarazioni è la convalida finale che dovrebbe essere eseguita.
Dovresti mysql_real_escape_string nulla potrebbe essere potenzialmente dannoso.Non fidarti mai di qualsiasi tipo di input che possa essere modificato dall'utente.
Sono d'accordo con te.È possibile modificare i cookie e inviare dati dannosi.
Credo che sia buona pratica filtrare i valori che ottieni dai cookie prima di utilizzarli.Come regola generale filtro qualsiasi altro input che potrebbe essere manomesso.
Yegor, puoi memorizzare l'hash quando un account utente viene creato/aggiornato, quindi ogni volta che viene avviato un accesso, esegui l'hashing dei dati pubblicati sul server e li confronti con ciò che è stato memorizzato nel database per quel nome utente.
(In cima alla mia testa in php sciolto - trattalo come pseudo codice):
$usernameFromPostDbsafe = LimitToAlphaNumUnderscore($usernameFromPost);
$result = Query("SELECT hash FROM userTable WHERE username='$usernameFromPostDbsafe' LIMIT 1;");
$hashFromDb = $result['hash'];
if( (sha1($usernameFromPost.$passwordFromPost.SALT)) == $hashFromDb ){
//Auth Success
}else{
//Auth Failure
}
Dopo un'autenticazione riuscita, è possibile archiviare l'hash in $_SESSION o in una tabella di database di nome utente/hash autenticati memorizzati nella cache.Quindi invia nuovamente l'hash al browser (ad esempio in un cookie) in modo che i successivi caricamenti della pagina inviino l'hash al server per confrontarlo con l'hash conservato nell'archivio della sessione prescelta.
mysql_real_escape_string è così superato...Al giorno d'oggi dovresti davvero utilizzare l'associazione dei parametri.
Elaborerò menzionando ciò a cui mi riferivo dichiarazioni preparate e fornisci un collegamento a un articolo che dimostra che a volte mysl_real_escape_string non è sufficiente: http://www.webappsec.org/projects/articles/091007.txt
Consiglierei di utilizzare htmlentities($input, ENT_QUOTES) invece di mysql_real_escape_string poiché ciò impedirà anche qualsiasi output accidentale del codice HTML effettivo.Ovviamente potresti usare mysql_real_escape_string e htmlentities, ma perché dovresti?