Parameterized PDO statements: should trusted, constant values be parameterized? - php

SELECT name FROM customers WHERE location = ? AND active = '1'
In this query, the value for location would come from an untrusted source, but the value for active is going to always be = 1. I'm using PDO for php/mysql.
Should I also parameterize the value for active?
If active wasn't a constant but came from a changing and trusted source, should I still parameterize? (ie. for caching benefits?)

No, there is no benefit to parameterizing constant values.
The purpose of parameterizing is to allow application data to be combined with SQL expressions safely and repeatedly. The safely part is to prevent SQL injection. The repeatedly part is so you can execute a prepared query again with different values, possibly relieving the RDBMS from having to re-parse and re-optimize the query.
Neither of these is an issue if you always use the same constant value in your query. You are not at risk of SQL injection from a hardcoded value, and you can re-execute the query if you need to, without re-parsing.
There's no caching of parameters going on. If anything, using prepared statements makes it harder for MySQL to cache the results (i.e. the query cache has limitation on caching results from prepared statements). But once you use prepared statements, it doesn't matter if it has one parameter versus two or more.
I do wonder why you put the integer in quotes. I see that a lot, but I have no idea how that got started or who thought it was necessary.

Related

Is it safe to truncate a table without using a prepared statement?

I've used the following sort of code a few times in my current project to clear out some tables. Incase it's not obvious I'm using PDO.
$clearResult = $db->query('TRUNCATE TABLE table_name');
I'm currently going through and updating a few of my earlier scripts to make sure they all make use of prepared statements and are written in a way to reduce (hopefully stop) sql injection.
No, there's no user input in the actual query so there's no risk of injection.
You do have to make sure that a user isn't able to trigger the truncate though, unless they're authorized.
It's not the SQL operation that determines whether or not a prepared statement should be used. To prevent SQL Injection, a prepared statement should be used when any variable is involved in the query where bound parameters are permitted. That is not limited to just user input either, any variable at all should be a bound paremeter, regardless of where it came from.
In your example there are no variables required for the query, and so there is no security benefit of using a prepared statement.
Even if your table_name was coming from user input or a variable, a prepared statement would not be a solution because it is not possible to bind the table name.
Prepared statements would have no effect on your truncate query.
PDO prepared statements are useful when running queries with user input as they allow you to use features such as bound parameters to sanitise user input.
They are also useful for optimising queries that will run multiple times.
You might want to read up a little on prepared statements in the PHP documentation - PHP documentation for prepared statements:
Many of the more mature databases support the concept of prepared
statements. What are they? They can be thought of as a kind of
compiled template for the SQL that an application wants to run, that
can be customized using variable parameters. Prepared statements offer
two major benefits:
The query only needs to be parsed (or prepared) once, but can be
executed multiple times with the same or different parameters. When
the query is prepared, the database will analyze, compile and optimize
its plan for executing the query. For complex queries this process can
take up enough time that it will noticeably slow down an application
if there is a need to repeat the same query many times with different
parameters. By using a prepared statement the application avoids
repeating the analyze/compile/optimize cycle. This means that prepared
statements use fewer resources and thus run faster.
The parameters to
prepared statements don't need to be quoted; the driver automatically
handles this. If an application exclusively uses prepared statements,
the developer can be sure that no SQL injection will occur (however,
if other portions of the query are being built up with unescaped
input, SQL injection is still possible). Prepared statements are so
useful that they are the only feature that PDO will emulate for
drivers that don't support them. This ensures that an application will
be able to use the same data access paradigm regardless of the
capabilities of the database.

How do you bind parameters to a query that isn't prepared?

I'm making a small web application that will be receiving data input by users regularly. When researching how to make sure the data input is cleansed first, and for that it would seem prepared statements are the way to go.
I've found this SO question however, and as my application (at least as far as I know) won't be doing more than one query per page request, it would seem all I really need is the binding of values to parameters in the query.
I've been looking through the PHP manual on PDO and mysqli, but I can't find any examples where values are bound to a normal query. All the examples I've found have a $stmt->prepare somewhere prior to the binding.
Is whether or not the statement is "prepared" something that's determined by the support of the database, and the prepare statement will always be in the code? Or is there a way to bind parameters directly into a $dbh->query(...)?
To explain why I'm looking to see if its possible to not use prepare, is due to this statement from the SO question I linked earlier in the post:
When not to use prepared statements? When you're only going to be running the statement once before the db connection goes away.
When not to use bound query parameters (which is really what most people use prepared statements to get)?
and this
Personally I wouldn't bother. The pseudo-prepared statements are likely to be useful for the safe variable quoting they presumably provide.
How do you bind parameters to a query that isn't prepared?
You don't. An SQL string with parameters (i.e. question marks in specific places) needs to be parsed (i.e. prepared) first before those question marks can be treated as insertion points for parameter values.
Therefore you always need to call prepare() before you can call bind().
A parameterized statement is a string that contains SQL and placeholder markers (for example question marks, but different databases use different placeholders):
$sql = "SELECT user_id FROM user WHERE user_name = ?"
Now assume there's a value you want to insert at this location:
$_POST["username"]
Preparing a statement, broadly speaking, gives the question marks their special meaning "a value can be inserted here". In other words, it creates parameters from the placeholders.
$stmt->prepare($sql)
Binding a value to a parameter sets the parameter to a specific value.
$stmt->bind_param("s", $_POST["username"])
Now the query can be executed without the SQL string and the user-supplied value ever actually coming into contact with each other. This is the important bit: SQL and parameter values are sent to the server separately. They never touch each other.
$stmt->execute();
The advantages are:
You can bind a new value to the parameter and execute the query again without having to repeat all of it (useful in a loop).
SQL injection is impossible, no matter what value $_POST["username"] contains.
You don't. Here's why:
If using $dbh->query(...)
you can just call SQL with the parameters interpolated into the SQL string. By using a query like
$dbh->query("INS INTO MY_TABLE_OF_NAMES ('$name');");
10 or so years ago, this is how most SQL was done. This is the most straightforward way of invoking the database, using the SQL interface already implemented by the RDMS, without the need for a special lower-level interface. But people discovered that this was dangerous because of something called SQL injection.
http://en.wikipedia.org/wiki/Sql_injection
The simplest and most common example goes something like this. Suppose you had an SQL call on your web page that would run:
INS INTO MY_TABLE_OF_NAMES VALUE ('$name');
But then someone would come to your site and enter there name as bob'); DROP TABLE MY_TABLE_OF_NAMES;
Suddenly your interpolated SQL statement becomes
INS INTO MY_TABLE_OF_NAMES VALUE ('bob'); DROP TABLE MY_TABLE_OF_NAMES; );
Which would subsequently insert bob into your database, delete all of your names, and throw an error for the trailing ); when your website ran it.
So, prepared statements were invented. Instead of interpolating strings directly into your SQL, it will use ? characters to denote dynamic values, and a bind function is used to insert the string safely. This way malevolent input will never be interpreted as SQL code by your database engine and your site can't be tricked into doing things it doesn't want to do. The prepare command takes an SQL string takes a bit of SQL and semi-compiles it into a lower-level database language leaving spaces open of dynamic strings wherever a ? is used. Bind then fills one of those open spaces with a piece of data, encoded to escaped ASCII, so that it cannot be misinterpreted as SQL code. Once all of those ?s are filled, the SQL is ready to be sent to the RDMS to be run.
So to answer your question, you will never bind a parameter to a simple query. If you want dynamic variables in a simple query you will just interpolate them into the SQL string. But this is dangerous. Prepared statements allow you to precompile an SQL statement then safely bind dynamic parameters to it to create safe dynamic SQL. Binding to SQL is purely a construct of prepared statements.
In order to use bound parameters, you have to use prepared statements. This is just the way things are currently implemented in pdo and mysqli. I'm not sure if certain database products support some type of communication protocol where parametrized sql(sql text which uses placeholders) is sent along with the parameter values without having to first do an explicit prepare call, but pdo and mysqli don't expose this functionality if it's available. It would sure be a welcome feature to web apps.
With pdo, yes, whether or not the sql statement actually gets prepared when you call $dbh->prepare($sql) does depend on database support. pdo will emulate prepared statements when the database doesn't support them, or it can always emulate them if its configured to do so. In fact, pdo emulates prepared statements for the mysql driver by default, and has done so by default for a very long time. It emulates them by creating dynamic sql, quoting the values, just like you would. In this case, the sql(with the final values embedded into the text) is sent to the database when you call $stmt->execute(). Yes, sql injection is possible here under certain scenarios.

How do protect yourself against SQL injection when using prepared statements/store procedures in PHP?

I've been looking at how best to protect against sql injection in PHP/mysql beyond just using the mysqli/mysql real escape since reading this Is mysql_real_escape_string enough to Anti SQL Injection?
I have seen this very good thread How can I prevent SQL injection in PHP?
I use to do alot of ms sql server stuff on the desktop/internal tools, we always wrote stored procedures to protect against this so I read up on the equivalent in PHP/mysql using PDO http://php.net/manual/en/pdo.prepared-statements.php
In the above there is the line :
The parameters to prepared statements don't need to be quoted; the driver automatically handles this. If an application exclusively uses prepared statements, the developer can be sure that no SQL injection will occur (however, if other portions of the query are being built up with unescaped input, SQL injection is still possible).
I've been lead to believe that PDO do protect against sql injection attacks so can anyone provide a instance where PDO isnt sufficient from a security standpoint?
You can still get SQL injections from stored procedures which are internally using the PREPARE syntax (in MySQL) to create dynamic SQL statements.
These need to be done with extreme care, using QUOTE() as necessary.
Ideally, we should not need to use PREPARE in stored routines, but in certain cases it becomes very difficult to avoid:
Prior to MySQL 5.5, the LIMIT clause cannot use non-constant values.
Lists used in an IN() clause cannot be (sensibly) parameterised, so you need to use dynamic SQL if this pattern is used
It is sometimes desirable to use dynamically generated ORDER BY clauses.
etc
In the case where it is necessary to use PREPARE, then I would recommend, in order of preference:
If something is an INT type (etc) it is not susceptible to SQL injection, and you can place the value into the query without a problem (e.g. for LIMIT)
String values can be placed into an #variable before the EXECUTE, or passed in to the EXECUTE clause
List-values (for example for IN()) need to be checked for validity.
Finally, QUOTE() can be used to quote string values, which can be useful in some cases
It's not the structure you use (stored procedures, prepared statements etc.) that is decisive, but whether you are at any point concatenating SQL together using unchecked user input. For example, you can execute dynamic SQL from within a stored procedure, in which case the danger is still there.
The easiest way (from the injection-avoidance point of view) is to use SPs or PSs with bound-in variables: these do not need to be checked as they will be recognized as values to go within a predefined placeholder.

mysqli prepared statements and mysqli_real_escape_string [duplicate]

This question already has an answer here:
Is mysql_real_escape_string() necessary when using prepared statements?
(1 answer)
Closed 3 months ago.
I'm currently using the mysqli php extension.
Traditionally I have used mysqli_real_escape_string to escape user input. However I am looking at changing over the code (hopefully in as few steps as possible) to use prepared statements.
I want to be clear on this - provided I use prepared statements to bind all of my variables, can I be confident that sql injection is impossible? (And dispense completely with mysqli_real_escape_string?)
Thanks
If you correctly bind all your variables you can dramatically reduce the risk of SQL injection. It is still possible to get an SQL injection if you create SQL dynamically for example:
'SELECT * FROM ' . $tablename . ' WHERE id = ?'
But if you avoid things like this it is unlikely you will have problems.
Speaking of security, there is no difference between both methods, if you correctly bind or format your variables.
Binding is just simpler, because it can be used just for any case, while escaping can't (so, you have to cast some variables instead of escaping/quoting).
Also, bear in mind that no binding nor escaping can make identifier safe. So, if you have to use a field name or operator in your query, you have to use a value, hardcoded in your script.
Here's my high-level view on the topic.
When using dynamic SQL strings, you are relying on the escaping function working correctly. Unfortunately, this is not always the case, as can be seen in this (admittedly old) example:
http://dev.mysql.com/doc/refman/5.0/en/news-5-0-22.html
Once your data values have been escaped, the SQL string has to be parsed and compiled by the database server. If the escaping function has not done its job properly, or a clever new SQL injection attack has been discovered, there is a chance that the server will mistake data for SQL statements.
If you use prepared statements with parameters, the statement is first parsed and compiled. The data values are combined with the compiled statement when it is executed. This separates the SQL logic from the data values - the opportunity to confuse the two should never occur.
So, yes, you can dispense with mysqli_real_escape_string, but I would not go so far as to say that using prepared statements with parameters makes SQL injection impossible. It makes it significantly harder, but as with the mysqli_real_escape_string bug, I guess there's always the chance that a yet to be discovered (or newly created) bug will make the seemingly impossible, possible.

Do prepared statements in PDO really increase security?

I wonder if those prepared statements of PDO really increase security, or if they are just a "cheap" text-replace in the query. The point of prepared statements actually is, that whatever gets inserted as parameter, will not be parsed by the DBMS as part of the instructions itself, so a parameter like
"'; DROP TABLE foobar;"
has no effect and does not break the query. Does anyone know this in detail? I thought to use PDO with prepared statements for preventing sql injection. It turns out that they are hard to use (and don't even work, at least on my local machine), so I want to find this out before wasting much more time with PDO ;-)
Creating a prepared statement sends the query-with-wildcards to the server for parsing, and returns a token to call that statement.
A call merely involves sending the data bound to every parameter. This means there will be no parsing of the data (because it's not part of a query string), and that the structure of the query is fixed when the prepared statement is parsed and cannot be altered by injection.
So, yes, a prepared statement definitely increases safety.
It also means you do not have to incur the parsing overhead if you reuse a prepared statement for several requests.
Yes, they increase security. PDO or MySQLi also increases speed versus the regular MYSQL methods in PHP because the data is passed in a more compact form.

Categories