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.
Related
I coded these two blocks of code, but they seem to do the same. I don't understand when you should use each one of these.
$query= $db->query("SELECT * FROM forum_table WHERE forum_id = '$id'");
and
$sql="SELECT * FROM forum_table WHERE forum_id = '$id'";
if ($query = $db->prepare($sql))
$query->execute();
I don't get how those differ
Well, In case of
$query= $db->query("SELECT * FROM forum_table WHERE forum_id = '$id'");
This is very simple and known to all, simple a query executing directly as it is, no extra magic in it.
$sql="SELECT * FROM forum_table WHERE forum_id = '$id'";
if ($query = $db->prepare($sql))
$query->execute();
While in your second piece of code you have used the same query but you have prepare the query before executing (which you are not doing the right way, that is you are not leaving the placeholders to bind parameters to it,which is what the recommended and purposeful way of using prepared statements.),
By making placeholders in prepared statements for binding parameters to it later prepare actually make a template before actual execution of the query which helps in many ways.
Prepared statements reduces parsing time as the preparation on the query is done only once (although the statement is executed multiple times).
Note: It is best practice to bound parameters into the prepare statement so that if the query has to run multiple time with different parameters.Only
Bound parameters minimize bandwidth to the server as you would need to send only the parameters each time, and not the whole query.
Last but not the least, Prepared statements are very useful against SQL injection if parameters are bind to it.
For a start both of those statements are exactly the same so there is literally no difference.
There is a hint at something very different going on with the second block.
prepared statements
As for when to use one over the other.. always use prepared statements
At the start of my application, I check for the account status. This is an internal check I control as I provide the application on a sub-domain.
I have been using this:
// Retrieve account status for application
$query = "SELECT `client_account_status` FROM `version_control` WHERE id = '1' ";
However, as I adapt to prepared statements, I am curious if this is absolutely necessary when there is no user input to check?
$stmt = mysqli_stmt_init($link);
if (mysqli_stmt_prepare($stmt, 'SELECT client_account_status FROM version_control WHERE id = 1')) {
mysqli_stmt_execute($stmt);
mysqli_stmt_bind_result($stmt, $client_account_status);
mysqli_stmt_fetch($stmt);
mysqli_stmt_close($stmt);
}
Necessary, no. Recommended, yes. However the way your query is currently written you get no benefit from the prepared statement. Instead it should be:
mysqli_stmt_prepare($stmt,
'SELECT client_account_status FROM version_control WHERE id = ?'));
mysqli_stmt_bind_param($stmt, 'i', 1);
mysqli_stmt_execute($stmt);
The problem with your initial version is that mysql has no way of knowing what part of your query is a parameter and what part is the SQL statement. The point of parameterized queries is to clearly separate the statement from the parameters.
See How can I prevent SQL injection in PHP? for more information on preventing SQL injection.
No, it is not necessary when there is no user input. It can sometimes still be useful to use a prepared statement when there is input though, even if it's not user input. This is because preparing a statement allows it to be executed more efficiently if it is run lots of times with different data each time.
This question is going to have a lot of opinions, I'll add mine to the list...
I personally always go with PDO, or Doctrine's DBAL library.
A query using something like the DBAL class would happen as so:
$result = $db->fetchColumn('SELECT client_account_status FROM version_control WHERE id = :id', [
'id' => $id
]);
In PDO it can be as easy as so:
$pdo->prepare('SELECT client_account_status FROM version_control WHERE id = :id');
$result = $pdo->execute(array(':id' => $id));
It's always easy to read and it doesn't require you to write 5 lines of code every single time you want to do something with the database.
You can have both security and efficiency, and it seems given how you asked your question that you only want to avoid mysqli prepared statements out of the complexity and annoyance of writing so much code for so little to happen.
I have gone through various document (SO post as well) about how exactly Prepared statement of PDO protect user from SQL injection.
Although,I understand it protect user because in prepared statement,user record is directly not executing on server insted we are sending positional / named parameter ( ? / :name) and then we send actual data in execute statement, and because of that it saves us from SQL Injection.
Well, Now if I have below code for SQL :
$query = "select * from user where id = $user_input_id";
and user input id = 1
So query will be something like :
$query = "select * from user where id = 1";
This is perfect till now. But if user entre $id = "1; DROP TABLE users;" so query will be something like :
$query = "SELECT * FROM users where id=$id";
and hence ,it will execute
$query = "SELECT * FROM users where id=1; DROP TABLE users;";
It works and out user table will drop because this query directly execute:
Well,I have read that prepared statement can save user from this :
and prepared statement working like :
$data = "1; DROP TABLE users;"
$db->prepare("SELECT * FROM users where id=?");
$db->execute($data);
In execute statement as well,record with Drop table is passing,so how exactly it won't execute drop table statament ? execute also performing some part on server right ?
Anyone can please explain how exactly prepared statement here save user from SQL injection ?
Thanks
Without explicitly setting a type (see PDOStatement::bindValue() for an example), it will treat the passed value as a string, so it will do this effectively:
SELECT * FROM users where id='1; DROP TABLE users;'
Btw, this would actually happen if you're using emulated prepared statements (PDO::ATTR_EMULATE_PREPARES); without this, it will send the parametrised query first followed by the actual data.
That is why you can additionally set the type of binded data to the type you need.
$stm->bindParam(":id", $id, PDO:PARAM_INT)
Additionally, PDO does some escaping of the data, and the string you provided will not break the query at ;, but will be inserted as plain string in the db.
SQL injection is an attack against the SQL parsing step, not the statement execution step. In this, it has similarities to other parse attacks such as cross site scripting and XML injection attacks.
SQL injection works because the common (broken) technique of creating SQL statements by using string concatenation operators to combine both code and (untrusted) data in a single string allows for the possibility of a specially crafted string to violate the statement data protocol (typically by breaking out of a data context using string delimiters embedded in data), and allowing the attacker to manipulate the SQL parser into executing different code to that originally intended.
When one uses a prepared statement, one is telling the parser 'treat the statement purely as trusted code, and provide some slots into which I will insert the data for execution'.
When you drop the string '1; drop table users' into the data slot you created using the '?' placeholder, that string is not processed by the parser, and hence it has no opportunity to influence the parsing of the string : you made it impossible for the contents of the string to break out of a data context.
Using your example, the database will execute the equivalent statement to :
SELECT * FROM users where id="1; drop table users;"
This is a perfectly valid select statement, which may or may not return rows depending on the data in your tables, but which is almost certainly not going to work properly.
Nevertheless, the approach bypassed the attempt at SQL injection.
Be aware : using prepared statements is the ONLY generalised way to avoid SQL injection attacks. In general, attempts to filter untrusted input data are broken.
I can see many discussions on why is better to use PDO bindValue vs bindValue. But what I could not find was precice information on why should I use that vs a simple variable in the query. Could anyone tell me? thanks
$sex = 'male';
$s = $dbh->prepare('SELECT name FROM students WHERE sex = :sex');
$s->bindParam(':sex', $sex);
$s->execute();
VS
$sex = 'male';
$s = $dbh->query('SELECT name FROM students WHERE sex = $sex'); // OR PREPARE, The question is how to pass the variable.
Like others have said, you want to use PDO to prevent SQL injection. Say a user with bad intentions types something like ';drop table students;-- into an input box on your site. Without PDO, the final query will look like this:
SELECT name FROM students WHERE sex = '';drop table students;--'
See what would happen? The select statement would run and not find any results (unless you have students in your table with no sex specified). Then, the drop statement would run, and your entire students table would be deleted.
This is just one example—there are all kinds of SQL injection attacks, many of them more dangerous than this. Using PDO prevents pretty much all of them. Internally, the bound variables are kept separate from the query itself.
The main reason is by using prepared statements and bound variables you protect yourself against the most common vector used for sql injection attacks.
A second reason is if you have multipe requests to run the same query statement, but with different variable values, you can save time by only having the server calculate the execute plan once, then run it on the the variables as you call the same statement over and over. Think about looping over the same statement several time. This is the concept of serverside prepared statements which mysql allows and PDO supports.
Historically, I've always used
mysql_real_escape_string()
for all input derived from users that ends up touching the database.
Now that I've completely converted over to MySQLi and I'm using prepared queries with bound parameters, have I effectively eliminated the possibility of SQL injection attacks?
Am I correct in saying I no longer need
mysql_real_escape_string()?
This is my understanding and the basis of a project of mine:
http://sourceforge.net/projects/mysqldoneright/files/Base/MysqlDoneRight-0.23.tar.gz/download
This is not something I want to get wrong though as now that I've released it, it could affect others as well.
All user provided input will now end up in bind_parms.
The queries provided in the prepare phase are static.
Yes. Using the prepared query will escape parameters.
It's not so simple. You can use bound parameters instead of interpolating application variables into SQL expressions in place of literal values only:
$sql = "SELECT * FROM MyTable WHERE id = ".$_GET["id"]; // not safe
$sql = "SELECT * FROM MyTable WHERE id = ?"; // safe
But what if you need to make part of the query dynamic besides a literal value?
$sql = "SELECT * FROM MyTable ORDER BY ".$_GET["sortcolumn"]; // not safe
$sql = "SELECT * FROM MyTable ORDER BY ?"; // doesn't work!
The parameter will always be interpreted as a value, not a column identifier. You can run a query with ORDER BY 'score', which is different from ORDER BY score, and using a parameter will be interpreted as the former -- a constant string 'score', not the value in the column named score.
So there are lots of cases where you have to use dynamic SQL and interpolate application variables into the query to get the results you want. In those cases, query parameters can't help you. You still have to be vigilant and code defensively to prevent SQL injection flaws.
No framework or data-access library can do this work for you. You can always construct a SQL query string that contains a SQL injection flaw, and you do this before the data-access library sees the SQL query. So how is it supposed to know what's intentional and what's a flaw?
Here are the methods to achieve secure SQL queries:
Filter input. Trace any variable data that gets inserted into your SQL queries. Use input filters to strip out illegal characters. For instance, if you expect an integer, make sure the input is constrained to be an integer.
Escape output. Output in this context can be the SQL query which you send to the database server. You know you can use SQL query parameters for values, but what about a column name? You need an escaping/quoting function for identifiers, just like the old mysql_real_escape_string() is for string values.
Code reviews. Get someone to be a second pair of eyes and go over your SQL code, to help you spot places where you neglected to use the above two techniques.
When you bind parameters to a prepared statement, it escapes the data automatically, so you shouldn't escape it before you send it through. Double escaping is usually a bad thing. At the very least, it produces ugly results with extra escaped characters later on.