As I was teaching students how to prevent SQL injection today, I was mildly embarrassed. In professional projects I've used prepared statements / parameterized queries as one layer of prevention against SQL injection (although I've never used mySQL professionally). In theory, I thought SQL injection was impossible when using a prepared statement.
But then this worked...
$Search = $_GET['s'];
$stmt = $mysqli->prepare("SELECT * FROM products WHERE id = ?");
$stmt->bind_param("i", $Search);
$stmt->execute();
$Results = $stmt->get_result();
If I pass the parameter "?s=1 OR 1=1" then I can get a full listing of all products. I still can't insert another query at the end, but I am confused about why this type of basic SQL injection is possible in mysql/php. I assumed that the parameter "1 OR 1=1" would be rejected because it isn't numeric (obviously I could run that numeric check ...).
Can anyone explain why this works, and what I don't understand about prepared statements in php/mysql?
My school computer has an out-of-the-box Zend WAMP installation btw.
EDIT: This is the string value that is causing my confusion:
$Search = "1 OR 1=1";
I tried to reproduce your case, but couldn't.
Database
Code
Output
Seems, that 1=1 condition was ignored.
That's ok, no any kind of SQL injection here, you do not see list of all products (at least code you provided cannot show it)
you do not need to cast to int, lets go deeper what bind_param actually do:
it has string "i" which means 1
integer
argumentyou're passing value from $_GET which is
string
bind_param tries to convert String to int, so check this php code:
so, you output products with id=1, maybe you have some of them?