Reputation: 311
I have been researching into PDO's bindValue()
. I know that preparing my SQL statements with PDO is keeping SQL injections from happening.
Code Example:
$stmt = $dbh->prepare('SELECT * FROM articles WHERE id = :id AND title = :title');
$stmt->bindValue(':id', PDO::PARAM_INT);
$stmt->bindValue(':title', PDO::PARAM_STR);
$stmt->execute();
By binding the ID as a number, and the Title was a string, we can limit the damage done when someone tries to do an SQL injection within the code.
Should we always bind our values with a PDO::PARAM_
so we can limit what can be pulled from the database in an SQL injection? Does this add more security with PDO when doing our bindValue()
?
Upvotes: 16
Views: 2240
Reputation: 157919
There are two questions in one. It is essential not to confuse them
While for the second one, for sake of code sanity and DRYness -
There are many ways to avoid manual binding. Some of them are:
ORM is an excellent solution for the simple CRUD operations and must have in a modern app. It will hide SQL from you completely, doing the binding behind the scenes:
$user = User::model()->findByPk($id);
Query Builder is also the way to go, disguising SQL in some PHP operators but again hiding the binding behind the scenes:
$user = $db->select('*')->from('users')->where('id = ?', $id)->fetch();
some abstraction library may take care of the passed data by means of type-hinted-placeholders, hiding the actual binding again:
$user = $db->getRow("SELECT * FROM users WHERE id =?i", $id);
if you are still using PHP in the last century ways, and have raw PDO all over the code - then you can pass your variables in execute(), still saving yourself a lot of typing:
$stmt = $dbh->prepare('SELECT * FROM users WHERE id = ?');
$stmt->execute([$id]);
$user = $stmt->fetch();
As of the third question - as long as you are binding numbers as strings (but not the opposite!) -
as mysql will always convert your data to the proper type. The only case known to me, is a LIMIT clause where you cannot format number as a string - thus, the only related case is one when PDO is set in emulation mode and you have to pass a parameter in LIMIT clause. In all other cases you can omit third parameter, as well as explicit call to bindValue()
without any problem.
Upvotes: 10
Reputation: 522412
You should definitely use the prepare
API and pass values separately from the query, as opposed to doing plain string interpolation (e.g. "SELECT * FROM foo WHERE bar = '$baz'"
→ bad).
For binding parameters, you have three options:
It doesn't really matter which of these you use, they're all equally secure. See these answers for some details about the differences:
When using bindParam
or bindValue
, passing the third PDO::PARAM_
argument type is optional. If you don't pass it, it defaults to binding the argument as string. That means you may end up with a query equivalent to ... WHERE foo = '42'
instead of ... WHERE foo = 42
. It depends on your database how it will handle this. MySQL will cast the string to a number automatically as needed, just as PHP does (e.g. in '42' + 1
). Other databases may be more fussy about types.
Again, all options are equally safe. If you're trying to bind a string 'foo'
using PDO::PARAM_INT
, the string will be cast to an integer and accordingly bound as the value 0
. There's no possibility for injection.
Upvotes: 10
Reputation: 7674
Yes, binding is the way to go. Or parameterised queries which a more generalized term.
@Theo does a wonderful job explaining why parameterized queries is the way to go
You could also use stored procedures for additional security but is an over kill if you have one application to one database. Its good for multiple applications to one database to ensure consistency when handling data
Upvotes: 1
Reputation: 410
Yes you should always bind params with prepared statement. It's more secure, and limit SQL injection. But this is not the only think you must do to query params: a correct type control is required, best if you map a row into an object and throw an exception in it if it has invalid data.
I hope I can be useful!
Upvotes: 2