PHP MySQLI Prevent SQL Injection [duplicate] - php

This question already has answers here:
How can I prevent SQL injection in PHP?
(27 answers)
Closed 9 years ago.
I've build a website that will be going live soon and just have a couple questions about preventing SQL injection, I understand how to use mysqli_real_escape_string but I'm just wondering if I have to use that on all variables that I'm getting for my SQL statement and do I have to use it when I'm doing select statements also or just on insert update and delete? Also what other security would you recommend me implementing before I put the site live, thanks in advance for any help!

Any query can be injected whether it's read or write, persistent or transient. Injections can be performed by ending one query and running a separate one (possible with mysqli), which renders the intended query irrelevant.
Any input to a query from an external source whether it is from users or even internal should be considered an argument to the query, and a parameter in the context of the query. Any parameter in a query needs to be parameterized. This leads to a properly parameterized query that you can create a prepared statement from and execute with arguments. For example:
SELECT col1 FROM t1 WHERE col2 = ?
? is a placeholder for a parameter. Using mysqli, you can create a prepared statement using prepare, bind a variable (argument) to a parameter using bind_param, and run the query with execute. You don't have to sanitize the argument at all (in fact it's detrimental to do so). mysqli does that for you. The full process would be:
$stmt = $mysqli->prepare("SELECT col1 FROM t1 WHERE col2 = ?");
$stmt->bind_param("s", $col2_arg);
$stmt->execute();
There is also an important distinction between parameterized query and prepared statement. This statement, while prepared, is not parameterized and is thus vulnerable to injection:
$stmt = $mysqli->prepare("INSERT INTO t1 VALUES ($_POST[user_input])");
To summarize:
All Queries should be properly parameterized (unless they have no parameters)
All arguments to a query should be treated as hostile as possible no matter their source

Related

What does mysqli_prepare() really do? Why should it be called by user and not handled internally by mysqlite3?

Documents really only mentions:
mysqli::prepare -- mysqli_prepare — Prepare an SQL statement for execution
I want to know what actually happens under the hood after calling mysqli_prepare() with a sql statement.
Could anyone elaborate with that and also why couldn't it be skipped? Couldn't this be done internally in mysqlite3?
A reference would be appreciated.
The difference between execute() and prepare() is not that the prepare() method has some internal flag like "secure=true;" which will be set and magically you are save for SQL injections. In fact, you can have SQL injections with prepare() as well when you use it wrong:
$stmt = $db->prepare('SELECT password FROM user WHERE username = "'.$username.'"');
$stmt->execute();
// ...
The point of prepared statements is that the values/arguments/variables for the SQL query are send separated from the actual SQL query to the MySQL server. This way the values/arguments/variables cannot change the SQL query you are trying to send. This prevents SQL injections where the inputs contain values like "='' OR 1 = 1 --".
The prepared statement is building a data structure where you set the values for the prepared statement separated via the additional API calls like bind_param(). The SQL server will use the "prepared" statement and use the values received from bind_param(). The query has been read, analyzed, well, it has been "prepared", and is fixed now (for the duration of this prepared statement) before even the first value with the potential dangerous data has been read. The WHERE condition cannot be altered or weakened, another SQL query cannot be appended or other rows/columns/tables can be edited.
Because of this, you cannot just redirect the execute() call internally to prepare() to be safe, because then you are missing the bind_param() calls. That being said: Use execute() when you have a fixed SQL query without any variables and/or user inputs and use prepare() for prepared statements, where you have an SQL query which depends on variables and/or user inputs.
In very short and in terms all will understand, you will want to use prepared statement(aka mysqli_prepare) to block sql injections, so in other words for security reasons.

Why does mysqli create two lines of log per statement and ORM just one, when using parameterized queries?

Looking at thegeneral MySQL log, when I use mysqli with parameterized queries with PHP I see statements like this:
Prepare SELECT * FROM my_table WHERE id = ?
Execute SELECT * FROM my_table WHERE id = 9
Prepare INSERT INTO my_table SET name = ?
Execute INSERT INTO my_table SET name = 'Alex'
This makes me feel warm and fuzzy, because I distinctly see that first, my query was sent, and them, my parameters, in two separate statements.
But when using an ORM (Doctrine in this case), I see the following:
Query SELECT t0.id AS id_1, t0.name AS name_2 FROM my_table t0 WHERE t0.id = '9'
Query START TRANSACTION
Query INSERT INTO my_table (name) VALUES ('Alex')
Query COMMIT
This has me feel alerted, as I do not see the same sequence of statement being send followed by parameters. It's statement + parameters in one go.
Questions about this that I have are:
Is Doctrine actually using parameterized statements, and why doesn't it do what MySQL does - log two packets, like mysqli does natively?
Is Doctrine safe from injection attacks in whatever it is doing now?
How is Doctrine safe from attacks, when it lumps statement and parameters into the same single query, per query? Does it really do something else here?
Doctrine uses PDO internally in most cases.
http://php.net/manual/en/pdo.prepare.php says in part:
PDO will emulate prepared statements/bound parameters for drivers that do not natively support them, and can also rewrite named or question mark style parameter markers to something more appropriate, if the driver supports one style but not the other.
When emulation of prepared statements is enabled, the prepare() that your app runs is basically a no-op. PDO saves your SQL string, but it does not send the SQL query to the database server at that time.
Then when you call execute(), it copies your parameter values into the appropriate places in the query, using proper string-escaping. Then it finally sends the final string to the database server. No prepare is done at the database server, it just executes the query as-is.
This is also how PDO supports both positional (?) and named (:param) parameters for all brands of RDBMS, even though most brands support one or the other style, but not both.
If you disble emulation of prepared statements, you should see both the Prepare and the Execute lines appear in the query log. I believe this can be done in Doctrine this way:
$pdo = $entityManager->getConnection()->getWrappedConnection();
$pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
While I don't know the Doctrine library specifically, I can speak to MySQL logs and what's going on as far as the DB is concerned:
The first example (prepare/execute) uses prepared statements, while the latter (query) does not. Prepared statements have a number of advantages, primarily performance- and security-related (avoiding SQL injection, as you mentioned), and I would personally avoid an ORM that did not use prepared statements, as they are generally considered a best practice for executing queries from within an application.
That's not to say that Doctrine isn't doing some sanitation internally to protect from SQL injection, and I certainly hope it is; at the same time, it would be more effective to use prepared statements, and I don't know why they wouldn't.

How does Binding parameters prevent Sql Injection? [duplicate]

This question already has answers here:
How can prepared statements protect from SQL injection attacks?
(10 answers)
Closed 6 years ago.
In PHP, I've found a few methods to prevent Sql Injection. Binding parameters is one of them. But I'm unable to find a complete explanation of how binding parameters actually prevent Sql Injection. I was of the notion that binding parameters simply save time in binding different data to the same Sql statement. How does prevention of Sql injection come into picture?
I think a simple example will explain you the thing:
"select * from myTable where name = " + condition;
imagine that user input as a condition is
'123'; delete from myTable; commit;
what happens then? the query executed will be
select * from myTable where name = '123'; delete from myTable; commit;
or actually we have three queries with disastrous consequences:
select * from myTable where name = '123';
delete from myTable;
commit;
in case of bind variables
"select * from myTable where name = #prmName"
whatever user input is it'll be one and only one query and the weird input above will always be treated as a string, not as a part of query. The outcome will be (most probably) an empty cursor, since there're no names within myTable like
"'123'; delete from myTable; commit;"

Restricting php pdo execute() to running just the first sql statement [duplicate]

This question already has answers here:
How can I prevent SQL injection in PHP?
(27 answers)
Closed 8 years ago.
Is there a way to restrict php pdo execute() to run just the first sql statement?
For instance running
SELECT * FROM customer;DROP TABLE invoice
will return all customers but it will also delete the invoice table.
I have a situation where I need a whole SQL statement from a user but it must be a SELECT and nothing additional.
My example is just one of many that could be maliciously entered. It might include additional DROP, UPDATE, DELETE statements etc.
A prepared statement will simply replace ?s with values. It will not stop dangerous SQL statemets being passed to it.
This would not be a problem if there was a way to restrict php pdo execute() to run just the first sql statement?
IF your trying to prevent SQL injection, prepare statements can handle it.
you can use something like this to prevent SQL injection
$stmt = $db->prepare("SELECT * FROM table WHERE id=? AND name=?");
$stmt->bindValue(1, $id, PDO::PARAM_INT);
$stmt->bindValue(2, $name, PDO::PARAM_STR);
$stmt->execute();
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);

How to prevent MySQL sleep injections?

Recently one hacker tried to slow my website using sleep injection. Although we are using precautions like mysql_real_escape_string() to cover most of vulnerable inputs. We are passing id of the product through query string and it makes the command as:
$id = mysql_real_escape_string($_REQUEST['id']);
$qry = "Select * from products where id = ".$id;
but hacker tried to provide input as
?id=3 and sleep(4)
and query becomes
Select * from products where id = 3 and sleep(4);
Although there are some possible solutions like
Check if the product id is numeric or not
Remove word sleep from input using some customized function
Is there any other method to stop this? What is the best method to prevent sleep injections?
You are not escaping correctly. mysql_real_escape_string is for escaping SQL string syntax correctly, but you are simply embedding the value as bare value, not as SQL string. You need:
$qry = "SELECT * FROM products WHERE id = '$id'";
Note the quotes around the id in the query.
If the id is numeric though, casting to a number would be more sensible:
$id = (int)$_GET['id'];
The best method to prevent SQL injections is to use current technology. The MySQL mysql_ family of functions is deprecated and will be removed from PHP in a future revision.
You should use prepared statements with either MySQLi or PDO instead.
These technologies use prepared statements and parameterized queries. SQL statements are parsed by the database server separately from any parameters. It is impossible for an attacker to inject malicious SQL.
You basically have two options to achieve this:
MySQLi:
$stmt = $dbConnection->prepare('SELECT * FROM table WHERE name = ?');
$stmt->bind_param('s', $name);
$stmt->execute();
$result = $stmt->get_result();
while ($row = $result->fetch_assoc()) {
// do something with $row
}
PDO:
$stmt = $pdo->prepare('SELECT * FROM table WHERE name = :name');
$stmt->execute(array(':name' => $name));
foreach ($stmt as $row) {
// do something with $row
}
What happens is that the SQL statement you pass to prepare is parsed and compiled by the database server. By specifying parameters (either a ? or a named parameter like :name) you tell the database engine what you want to filter on. Then when you call execute the prepared statement is combined with the parameter values you specify.
The important thing here is that the parameter values are combined with the compiled statement, not a SQL string. SQL injection works by tricking the script into including malicious strings when it creates SQL to send to the database. So by sending the actual SQL separately from the parameters you limit the risk of ending up with something you didn't intend. Any parameters you send when using a prepared statement will just be treated as strings (although the database engine may do some optimization so parameters may end up as numbers too, of course).
This is wrong question to ask.
"How to prevent mysql injections?" it has to be. Sleep or not sleep - it doesn't matter.
And there are plenty of answers on this question already
if you want a canonical one, then How can I prevent SQL injection in PHP?
if you want to understand, how it works, here I explained it in details
you should convert your queries into "prepared statements" using PDO or mysqli.

Categories