I am using FluentPDO to handle my database queries.
Upon looking at it's code, it doesn't seem to use any form of escaping. I understand PDO solves a lot of security issues by itself, but it's not immune to them.
As I understand, it is immune to SQL injection as long as we use the prepared statements syntax featured at it's homepage:
$query = $fpdo->from('article')
->where('published_at > ?', $date) // HERE!!
->orderBy('published_at DESC')
->limit(5);
How about escaping variables to prevent second order SQL injection? Would simply using addslashes() suffice? Would it be redundant?
How should I handle security with this library?
Thanks!
FluentPDO passes all parameters through the "execute" method of PDO, for example:
$connection = new PDO(...);
$pdo = connection->prepare($sql);
$pdo->execute($params);
That's why FluentPDO already prepares Queries to avoid SQL Injection.
About sanitizing, read more.
Some nice quotes:
Do not try to prevent SQL injection by sanitizing input data.
Instead, do not allow data to be used in creating your SQL code. Use Prepared Statements (i.e. using parameters in a template query) that uses bound variables. It is the only way to be guaranteed against SQL injection.
or (read more about validating filters)
PHP has the new nice filter_input functions now, that for instance liberate you from finding 'the ultimate e-mail regex' now that there is a built-in FILTER_VALIDATE_EMAIL type
Related
Is this considered completely safe?
$stmt = $dbhandler->prepare("update sometable set somefield=:somestring");
$stmt->bindParam(":somestring",$_REQUEST["hack_me_please"],PDO::PARAM_STR);
$stmt->execute();
And if not, what could make it safer? I'm assuming there are unknown vulnerabilities in PDO/MySQL/PHP that may be exploited in the future so I'm wondering if there is anything reasonable I can do make my queries safer, or is it out of my hands with prepared statements.
If it is this easy, why is SQL injection still a thing? Shouldn't it have gone the way of polio?
No, it's not necessary to sanitize inputs when using prepared statement to protect sql injections but you may do it if you want for any other reason.
If it is this easy, why is SQL injection still a thing? Shouldn't it have gone the way of polio?
it's easy for those who knows about it, nothing is easy unless you know it. I believe sql injection doesn't happen a lot nowadays.
Your example is completely safe because it passes the user input parameters separate from the query string. The reason sql injection still exists is because a lot of users still use the deprecated mysql_* api/driver and are unaware of the alternatives. Also, even using pdo or mysqli you can still pass user input directly into the query string instead of binding it separately.
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
How to prevent SQL injection in PHP?
I am working for a video streaming website for my college library. I am using PHP and MySql. I have not used any parameterized queries in this project.
Recently I came to know about SQL injections. Now that my code is almost done and I have to submit the project in the next two days, how can I now ensure that my code is not SQL injection prone?
Converting the whole thing in to a parameterized interface is what I can't do now. What should I do now to avoid SQL Injections on my website?
The basic idea to prevent SQL injections (if not using Prepared Statements) is to escape your data.
When you inject some expected integer value into an SQL query, make sure it's an integer, using intval().
When you have a decimal/numeric field in your table, use floatval().
And when you have a string (char, varchar, text) field in your table, use the function provided by your API to escape strings :
mysql_real_escape_string()
mysqli_real_escape_string()
PDO::quote()
I really recommend that you go back and do it right with parameterized queries. It is the only solid path towards security. It likely won't take too long to do this once you get started.
You should also know that websites are never "finished". When you launch a site, your work has just begun. Fixing security troubles as you learn about them is part of it, and this is no different.
You'll want to make sure any user provided inputs that get used in SQL queries are escaped using the PHP function mysql_real_escape_string and if you are letting people submit text to run htmlentities on the provided text so XXS isn't possible. If possible, white-list user provided input and discard anything else
This is just touching the surface of what you can do but look into query escaping and preventing cross site scripting.
Use PDO (or alternatively mysqli or some abstraction layer) and prepared statements.
Quick example:
$pdo = new PDO($dsn);
$stmt = $pdo->prepare("SELECT name FROM users WHERE id = ?");
$stmt->execute(array($unsafe_id));
$name = $stmt->fetchColumn();
In this example, $unsafe_id will be safe to use. To quote the manual page:
Calling PDO::prepare() and
PDOStatement::execute() for statements
that will be issued multiple times
with different parameter values
optimizes the performance of your
application by allowing the driver to
negotiate client and/or server side
caching of the query plan and meta
information, and helps to prevent SQL
injection attacks by eliminating the
need to manually quote the parameters.
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.
Can someone give me a little help with this? i have three PHP SQL querys, and i have to protect from SQL Injection. I am searching on google but i think is too hard for me, because it's combinated with PHP and i dont know munch about PHP and lees about SQL
if someone can give me the code protected I'll be grateful
the code:
$q=mysql_query("SELECT * FROM user where email= '".$_REQUEST['email']."'",$link );
$q=mysql_query("UPDATE user SET mobilePhone='".$_REQUEST['mobilePhone']."', fullName='".$_REQUEST['fullName']."' WHERE email='".$_REQUEST['email']."'",$link );
$q=mysql_query("UPDATE user SET mobilePhone='".$_REQUEST['mobilePhone']."' , fullName='".$_REQUEST['fullName']."', password='".$_REQUEST['password']."' WHERE email='".$_REQUEST['email']."'",$link );
Well, the simple way would be to wrap each of the $_REQUEST vars in mysql_real_escape_string()...
$q=mysql_query("SELECT * FROM user
where email= '".mysql_real_escape_string($_REQUEST['email'])."'",$link );
The better way would be to use prepared queries. There are plenty of tutorials available on how to do it, so I'll leave that to you...
The least you can do to prevent SQL injection is to use mysql_real_escape_string function before any variables that go into your queries.
The best you can do is to use prepared statements to avoid SQL injection.
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).
Suggestion:
To be further on safer side, you should always use proper array eg $_POST or $_GET instead of $_REQUEST for security reasons.
Take a look at PHP's mysql_real_escape_string
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.
Is mysql_real_escape_string sufficient for cleaning user input in most situations?
::EDIT::
I'm thinking mostly in terms of preventing SQL injection but I ultimately want to know if I can trust user data after I apply mysql_real_escape_string or if I should take extra measures to clean the data before I pass it around the application and databases.
I see where cleaning for HTML chars is important but I wouldn't consider it necessary for trusting user input.
T
mysql_real_escape_string is not sufficient in all situations but it is definitely very good friend. The better solution is using Prepared Statements
//example from http://php.net/manual/en/pdo.prepared-statements.php
$stmt = $dbh->prepare("INSERT INTO REGISTRY (name, value) VALUES (?, ?)");
$stmt->bindParam(1, $name);
$stmt->bindParam(2, $value);
// insert one row
$name = 'one';
$value = 1;
$stmt->execute();
Also, not to forget HTMLPurifier that can be used to discard any invalid/suspicious characters.
...........
Edit:
Based on the comments below, I need to post this link (I should have done before sorry for creating confusion)
mysql_real_escape_string() versus Prepared Statements
Quoting:
mysql_real_escape_string() prone to
the same kind of issues affecting
addslashes().
Chris Shiflett (Security Expert)
The answer to your question is No. mysql_real_escape_string() is not suitable for all user input and mysql_real_escape_string() does not stop all sql injection. addslashes() is another popular function to use in php, and it has the same problem.
vulnerable code:
mysql_query("select * from user where id=".mysql_real_escape_string($_GET[id]));
poc exploit:
http://localhost/sql_test.php?id=1 or sleep(500)
The patch is to use quote marks around id:
mysql_query("select * from user where id='".mysql_real_escape_string($_GET[id])."'");
Really the best approach is to use parametrized queries which a number of people ahve pointed out. Pdo works well, adodb is another popular library for php.
If you do use mysql_real_escape_string is should only be used for sql injection, and nothing else. Vulnerabilities are highly dependent on how the data is being used. One should apply security measures on a function by function basis. And yes, XSS is a VERY SERIOUS PROBLEM. Not filtering for html is a serious mistake that a hacker will use to pw3n you. Please read the xss faq.
To the database, yes. You'll want to consider adequately escaping / encoding data for output as well.
You should also consider validating the input against what you expect it to be.
Have you considered using prepared statements? PHP offers numerous ways to interact with your database. Most of which are better than the mysql_* functions.
PDO, MDB2 and the MySQL Improved should get you started.
What situations?
For SQL queries, it's great. (Prepared statements are better - I vote PDO for this - but the function escapes just fine.) For HTML and the like, it is not the tool for the job - try a generic htmlspecialchars or a more precise tool like HTML Purifier.
To address the edit: The only other layer you could add is data valdation, e.g. confirm that if you are putting an integer into the database, and you are expecting a positive integer, you return an error to the user on attempting to put in a negative integer. As far as data integrity is concerned, mysql_real_escape_string is the best you have for escaping (though, again, prepared statements are a cleaner system that avoids escaping entirely).
mysql_real_escape_string() is useful for preventing SQL injection attacks only. It won't help you with preventing cross site scripting attacks. For that, you should use htmlspecialchars() just before outputting data that was originally collected from user input.
There are two ways, one is to use prepared statements (as mentioned in other answers), but that will slow down your app, because you now have to send two requests to the Database, instead of one. If you can live with the reduced performance, then go for it; Prepared Statements makes your code prettier and easier to deal with.
If you chose to use mysql_real_escape_string, then make sure that you escape all the strings that are untrusted. An (mysql_real_escape_string) escaped string is SQL Injection secure. If you don't escape all the strings, then you are not secure. You should really combine mysql_real_escape_string with input validation; checking that a variable you expect to hold a number really is a number and within the expected range. Remember, never trust the user.
There are different types of "cleaning".
mysql_real_escape_string is sufficient for database data, but will still be evaluated by the browser upon display if it is HTML.
To remove HTML from user input, you can use strip_tags.
I would suggest you look into using PDO instead of regular MySQL stuff, as it supports prepared statements right out of the box, and those handle the escaping of invalid data for you.
You can try both, as in
function clean_input($instr) {
// Note that PHP performs addslashes() on GET/POST data.
// Avoid double escaping by checking the setting before doing this.
if(get_magic_quotes_gpc()) {
$str = stripslashes($instr);
}
return mysql_real_escape_string(strip_tags(trim($instr)));
}
The best way to go would be to use Prepared Statements
I thought I'd add that PHP 5.2+ has input filter functions that can sanitize user input in a variety of ways.
Here's the manual entry as well as a blog post [by Matt Butcher] about why they're great.