Is there a way to disable multiple statement queries in PDO? A method that works with all the drivers supported?
Alternatively, is there any well known filter that detect multiple statements in a string?
I know that prepared statements can better prevent SQL injection risks, there are reasons why I can't use them in this case.
You are barking the wrong tree.
Multiple statement is not a synonym for SQL injection. It's just a subset, a very small one, out of zilliards other possible ways to exploit an injection.
Therefore you should protect from injection, not multiple statement. For this, a query that is sent to database API have to be 100% hardcoded in your script. To achieve that, always substitute all the variables in the query with placeholders.
Yes, there is a way to disable multiple statement queries, at least for PDO MySQL, you can do it by using the PDO::MYSQL_ATTR_MULTI_STATEMENTS constant [1,2]; the constant exists as of PHP 5.5.21 and PHP 5.6.5.
I have looked for an equivalent for PostgreSQL, SQLite and MS SQL Server but I haven't found it. However, according to my tests, PDO PostgreSQL and SQLite don't allow multiple statement queries, while pdo_sqlsrv does. I haven't found official documentation about this, though, so it could depend on my driver version or other factors.
References:
[1] http://php.net/manual/en/ref.pdo-mysql.php
[2] https://bugs.php.net/bug.php?id=68424
Related
I know there are many questions out there already regarding this subject, however none I have found specifically answer my question.
I have created a simple PHP function that validates all user supplied input. Given the nature of the application I am developing, it is rare that the use of any characters other than numbers and letters are required. Occasionally commas (,), hyphens (-), ampersands (&) and single-quotes ('). My PHP function ensures that all input only contains these characters, and then adds a single backslash in front of each instance of one of these symbols.
I am assuming that if I guarantee that all input is sent through this function before being used in a MySQLi query, I am safe from SQL injection and have no need to use prepared statements, parameterised queries etc, regarding security only.
Am I correct?
tl;dr NO
There are many attack vectors and many different kinds of SQL Injection out there. For instance, use the wrong method from the MySQLi class and you're open to many attacks.
Just don't even bother thinking about building your own stuff, you'll fail, you'll fail hard. Follow best practices and concentrate on other parts while becoming the most awesome programmer this world has ever seen.
On a last note, prepared statements are offering you many benefits. Although the caching of queries as mentioned by #Zanon is sadly not one of them if you use MySQL (it would be with e.g. PostgreSQL). But that is up to the documentations of the software (and their exact versions) you use.
It seems from our discussion in the comments that the underlying reason you want to avoid parameterised queries is because you couldn't get mysqli_stmt_get_result() working under MAMP as it requires the mysqlnd native driver.
In fact, that has no bearing on your ability to use parameterised queries or prepared statements. It's an enhancement to the normal method of fetching bound results from prepared statements instead of the older (but still standard and perfectly-supported) mysqli_stmt_bind_result(), which will work fine without mysqlnd.
Please use parameterised queries. If you also want to use prepared statements with bound result variables without the mysqlnd driver, use mysqli_stmt_bind_result() instead of mysqli_stmt_get_result().
If you have any problems using parameterised queries, please post a new question with a complete, minimal example of the code you're having problems with.
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.
I think it is a good idea to turn off multiple statements like this to prevent this type of sql-injection.
Example of multiple statements:
$query = "UPDATE authors SET author=UPPER(author) WHERE id=1;";
$query .= "UPDATE authors SET author=LOWER(author) WHERE id=2;";
$query .= "UPDATE authors SET author=NULL WHERE id=3;";
pg_query($conn, $query);
Is it possible to prevent multiple statements in posgresql settings or for example using posgre's related PHP code?
Or maybe there is any way of parsing SQL queries before passing them to pg_query in order to detect queries which consists of more than one statement?
No, there is no way to disable multi-statements in PostgreSQL. Nor, as far as I know, is there any way to do so in the PHP Pg or PDO PostgreSQL drivers.
They aren't your problem anyway. Disabling multi-statements might be a (slight) SQL injection harm mitigation, but it wouldn't be any real protection. Consider writeable CTEs, for example, or qualifier removal attacks.
Instead, protect your code properly in the first place. Rigorously use parameterized statements instead of string concatenation, so there's no SQL injection opportunity in the first place. It's not hard to avoid SQL injection, you just have to be a little bit sensible with your coding practices.
Use PDO or pg_query_params for all queries, and make sure you don't concatenate text that's come from outside the immediate scope directly into SQL text, use a parameter. Even if it comes from elsewhere in the application and is considered "trusted" ... later refactoring might change that.
I think it is a good idea
It is, actually, not.
You have to prevent injections, not multiple queries.
I've had a good read with this question mysqli or PDO - what are the pros and cons?. But I think it's a bit dated. Are prepared statements still the best solution against injections?
I'm going to create a new php interface to access my mysql database so I want to get it right from the start.
Also doesn't pdo slow your query's down a lot?
Use prepared statements/parametrized queries. This is completely safe since you do not mix SQL with data in the same string and you don't have to think about escaping anymore. At least if you don't start making your column/table names dynamic in a way users can modify them.
The advantages you get by using PDO us absolutely worth the minimal performance loss.
Note: I've looked at this question: Preventing SQL injection without prepared statements (JDBC) . And as I somewhat expected... the answer is to use prepared statements. I'm in a different set of circumstances... so I'd like to know the best path for this.
I'm using a downloaded script (phpsimplechat) where the author wrote his own simple SQL layer (notice: it supports PostgreSQL and MySQL). Unfortunately, I've ran some tests on it and it is vulnerable to SQL Injection. The script does everything I want simply from a features standpoint, so I'd like to salvage it.
Fortunately, it is open source... but I'd rather not rewrite all of the SQL queries to use prepared statements in phpsimplechat. The 3rd party library uses its own SQL layer instead of PDO... and under that uses the older mysql module (thus, I can't use prepared statements. Even if I changed mysql -> mysqli, I have to deal with "dbQuery" layer he put on top of all of his code). I do NOT need the PostgreSQL code, so answers can be MySQL specific.
I've read that addslashes is insufficient to protect against all SQL Injection attempts. Is mysql_real_escape_string safe to use?
Yes, mysql_real_escape_string is guaranteed to be safe if you use it correctly, i.e. make sure that all strings appearing in queries are escaped.