Il tuo codice ha la variabile $username
nella parte superiore della tua domanda, ma poi hai $user
nella parte inferiore.
Intendi forse usare la stessa variabile?
$username = ($_GET ['user']);
$sth = $dbh->query( "SELECT username, user_state, last_activity, alerts_unread, conversations_unread, message_count
FROM xf_user WHERE username='$user'" );
// ^^ Should this ALSO be $username ?
$row = $sth->fetch();
Modifica:Ok, ora sei semplicemente carino con il tuo PDO::ATTR_EMULATE_PREPARES
. Osserva questo:
Database e struttura delle tabelle:
Database changed
mysql> show tables
-> ;
+----------------+
| Tables_in_prep |
+----------------+
| users |
+----------------+
1 row in set (0.00 sec)
mysql> select * from users;
+----+---------+--------+
| id | userid | pass |
+----+---------+--------+
| 1 | Fluffeh | mypass |
+----+---------+--------+
1 row in set (0.00 sec)
E del codice PHP che viene copiato dal tuo, con l'attributo PDO aggiunto:
<?php
//$username = ($_GET ['user']);
$username="Fluffeh";
$dbh = new PDO('mysql:host=localhost;dbname=prep', 'prepared', 'example');
$dbh->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_OBJ);
$sth = $dbh->query( "SELECT userid, pass FROM users WHERE userid='$username'" );
echo "Trying to use $username.\n";
print_r($sth->fetch());
echo "----------------------------------------\n\n";
?>
<?php
//$username = ($_GET ['user']);
$username="user2693017";
$dbh = new PDO('mysql:host=localhost;dbname=prep', 'prepared', 'example');
$dbh->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_OBJ);
$sth = $dbh->query( "SELECT userid, pass FROM users WHERE userid='$username'" );
echo "Trying to use $username.\n";
print_r($sth->fetch());
echo "----------------------------------------\n\n";
?>
<?php
//$username = ($_GET ['user']);
$username="Oh my' or 1=1 or 'm=m";
$dbh = new PDO('mysql:host=localhost;dbname=prep', 'prepared', 'example');
$dbh->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_OBJ);
$sth = $dbh->query( "SELECT userid, pass FROM users WHERE userid='$username'" );
echo "Trying to use $username.\n";
print_r($sth->fetch());
echo "----------------------------------------\n\n";
?>
<?php
//$username = ($_GET ['user']);
$username="(select id from users limit 1)";
$dbh = new PDO('mysql:host=localhost;dbname=prep', 'prepared', 'example');
$dbh->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_OBJ);
$sth = $dbh->query( "SELECT userid, pass FROM users WHERE id='$username'" );
echo "Trying to use $username.\n";
print_r($sth->fetch());
echo "----------------------------------------\n\n";
?>
<?php
//$username = ($_GET ['user']);
// Changed this one to be a non-string, you might be checking an ID instead.
$username="(select id from users limit 1)";
$dbh = new PDO('mysql:host=localhost;dbname=prep', 'prepared', 'example');
$dbh->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_OBJ);
$sth = $dbh->query( "SELECT userid, pass FROM users WHERE id=$username" );
echo "Trying to use $username.\n";
print_r($sth->fetch());
echo "----------------------------------------\n\n";
?>
<?php
//$username = ($_GET ['user']);
$username="bob'; drop table users; \
";
// This one is tricker to do in PHP code. I could easily enter this into a text field however.
$dbh = new PDO('mysql:host=localhost;dbname=prep', 'prepared', 'example');
$dbh->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_OBJ);
//$sth = $dbh->query( "SELECT userid, pass FROM users WHERE id='$username'" );
echo "Trying to use $username.\n";
print_r($sth->fetch());
echo "----------------------------------------\n\n";
?>
E l'output:
Trying to use Fluffeh.
stdClass Object
(
[userid] => Fluffeh
[pass] => mypass
)
----------------------------------------
Trying to use user2693017.
----------------------------------------
Trying to use Oh my' or 1=1 or 'm=m.
stdClass Object
(
[userid] => Fluffeh
[pass] => mypass
)
----------------------------------------
Trying to use (select id from users limit 1).
----------------------------------------
Trying to use (select id from users limit 1).
stdClass Object
(
[userid] => Fluffeh
[pass] => mypass
)
----------------------------------------
Trying to use bob'; drop table users; \
.
----------------------------------------
Oh, il motivo per cui ho lasciato l'ultimo fino all'ULTIMO è questo output ora nel mio database:
mysql> show tables;
Empty set (0.00 sec)
Sì, è vero, ho appena lasciato cadere un tavolo. Lasciatemelo dire ancora una volta, avevo una dichiarazione selezionata e con un piccolo trucco ho inserito un valore che CHIUNQUE con mezzo cervello e qualche intento malevolo poteva fare in un campo di testo, e ABBANDONATO LA TAVOLA.
Ora, concesso, se stai impostando le cose correttamente, potresti anche impostare un utente diverso per le istruzioni select e concedere loro solo select
diritti dal tuo database, per impedire che questo genere di cose accadano - ma siamo onesti... non lo sei vero?
Chiaramente l'impostazione dell'emulazione non è sufficiente. Seriamente, ora PER FAVORE vai leggi quella risposta , usa le istruzioni preparate e usa i parametri se vuoi essere sicuro nel tuo codice.