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.
Related
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
How to prevent SQL injection?
This is more of a philosophical point i'm trying to determine, out of curiosity.
I know that theoretically, any password or encryption is crackable.
But is it the same with SQL injection, where one just has to find the appropriate measures to deal with /bypass whatever security measures are implemented in the site? Or is injection something that can be definitively and with certainty defended against using a fixed set of security measures?
Im essentially wondering if it is possible to the input fields in my site unhackable through injection, or whether there will always be some vulnerability?
Being vulnerable to SQL injection is a bug. A well-built application will not contain such a bug, and no amount of effort will make such a bug appear.
SQL injection implies the data entered conforms to valid SQL (though typically injected in a creative way to produce undesired results).
To protect against it, you simply need to ensure that any user supplied data is encoded in a way that it cannot be misused.
As mentioned in a link above ( How can I prevent SQL injection in PHP? ), using prepared statements is a best practice to protect against SQL injection.
Sql injection is a technique used to hijack the security of website.
Sql injection occurs when data specified in input fields are not filtered for escape characters and passed into sql query for execution.
For testing sql injection please refer the following url.
http://sqlzoo.net/hack/
In above url try specifying "'" in field for name and specify "OR 1=1 #" in field for password
So the resultant query will be
SELECT * from user where name='' OR 1=1#' and password='';
In the above example you can notice that query is broken after specifying above data in input fields and any anonymous user can easily login into website.
There are several techniques to prevent sql injection.
(1) Input data must be filtered using mysql_real_escape_string while being passed into sql query for execution.
For more details about mysql_real_escape_string function please refer the documentation mentioned in below url.
http://php.net/manual/en/function.mysql-real-escape-string.php
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Best way to prevent SQL injection in PHP?
I have been doing some research about SQL Injection but I have some questions that I couldn't find answer to. Isn't it possible to prevent SQL injection attacks on string levels? What I mean is, can't we prevent it by;
Finding illegal characters before processing them through mysql queries?
$postID = $_POST['id'];
if($postID contains characters)
remove characters;
if($postID still contains characters)
then exit;
else
mysql_real_escape_string($postID); //just in case?
continue to do whatever you are doing...
Is it really necessary to use PDO/mysqli stuff? Is it sufficient to analyze your sql strings to be processed in mysql? Please keep in mind that I am not a PHP or MySQL expert while replying. I am someone who is trying to learn about them.
Sure, you can protect against injection with mysql_real_escape_string($postID), as long as you don't mind a query every time you call the function.
PDO and MySQLi provide a lot more than just injection protection. They allow for prepared statements that can protect agaisnt injection without multiple calls to the db. This means faster overall performance. Imagine trying to insert to a table a user record with 30 columns... that's a lot of mysql_real_escape_string() calls.
Prepared statements send all the data at once along with the query and escape it on the server in one request. Mysql DB's support prepared statments, the old php mysql_ libraries don't support them.
Time to move on to mysqli or preferrably PDO--you'll never look back.
I would encourage you to use PDO (PHP Data Objects). It will help against SQL injection and should speed up queries. Also, your application becomes more abstracted from the database.
Something like the following:
$stmt = $conn->prepare("INSERT INTO table_name VALUES(:id, :firstname, :lastname)");
$stmt->bindValue(':id', $id);
$stmt->bindValue(':firstname', $firstname);
$stmt->bindValue(':lastname', $lastname);
$stmt->execute();
If your ID it's an integer, just use
$postID = (int)$_POST['id'];
And of course, validate if $postID it's != zero after that line.
I wouldn't encourage you to use the mysql_ functions anymore because they're deprecated.
Check: http://php.net/manual/en/function.mysql-real-escape-string.php for more information on why the regular mysql_ has been discontinued.
You could switch to mysqli really easy. It really isn't that complicated. Plus if you want to escape characters and you don't want to be replacing every mysql_real_escape_string for the new way of escaping, you could use this function:
function mysql_string_safe($stringtoclean)
{
//In this case,
$safestring = mysqli_real_escape_string('your_handle_here',$stringtoclean);
return $safestring;
}
So then you would replace mysql_real_escape_string for mysql_string_safe.
Mysqli is really similar to mysql_ but It's more secure. I've switched to it and it didn't take too long, it was easy since it was just replacing stuff. Connecting to the database is different too. On the other hand, PDO has support towards different database drivers but if you want to save time and you're not going to switch database drivers, just use mysqli.
Is it really necessary to use PDO/mysqli stuff?
No.
Is it sufficient to analyze your sql strings to be processed in mysql?
No.
Learning Material
MySQL SQL Injection Cheat Sheet
SQL Injection Prevention Cheat Sheet
How to Avoid SQL Injection Vulnerabilities
more security cheat sheets
Coding Security Controls
Don’t write your own security controls! Reinventing the wheel when it comes to developing security controls for every web application or web service leads to wasted time and massive security holes. The OWASP Enterprise Security API (ESAPI) Toolkits help software developers guard against security‐related design and implementation flaws - https://code.google.com/p/owasp-esapi-php/
Just use PDO and prepare your statements.
This question already has answers here:
How can I prevent SQL injection in PHP?
(27 answers)
Closed 1 year ago.
I have a Single Page Application in which the browser does all the logic work. Except for initial loading, the server is pretty much a fancy interface to the database.
The browser sends data dictionary keys, column name / value pairs, and where clauses for SELECT, for example. The server assembles the parts into SQL, executes the queries, and replies. NEW: In a SELECT, for example, the table name and columns pulled are from the data dictionary - the browser supplies the data dictionary key and the SELECT where clause.
This very open environment is very susceptible to SQL Injection attacks. The goal is to prevent damage from said attacks.
Problems to be Overcome
First, as discussed, it is impossible to paramaterize a random SELECT where clause - SELECT cannot use a prepared statements.
Second, mysqli, the library for paramaterized statements with MySQL, does not support NULL nor MySQL functions, eg, CURRENT_DATE or NOW(), as discussed.
Proposed Solution
First, if SELECT cannot be paramterized, then execute SELECT by a user who has no DML or DDL rights. This will prevent SQL Injection Attacks from changing the database.
Second, write a wrapper function for mysqli that will allow NULL and MySQL functions to be passed as parameters. This will allow parameters to be easily used for all DML.
Third, shadow highly sensitive data where it cannot be seen or touched by normal queries or normal users. This will put sensitive data, such as passwords, out of the range of attacks.
Forth, write a wrapper order to enforce the user / query type relationship. This will ensure SELECT are executed by the select user, for example
The result of that effort is here. The question is, logically, will this approach successfully protect against SQL Injection Attacks?
Non-Answer Answers
I proposed this same question before. Due to my poor job of presentation, received answers and comments ended up focusing on spurious issues instead of addressing the (admittedly) difficult question - does this actually work?
As a reference, here are some of those comments and answers.
Use PDO's prepared statements
First, prepared statements cannot be used for all SELECTs - how does PDO help? Second, mysqli does not accept NULL or MySQL functions - how does PDO help?
Why re-invent the wheel
If you know of an approach that overcomes these problems, I would really really like to know - this is a difficult problem.
no mysql_real_escape_string() in sight
Values should be sanitized before being passed to the database query functions. mysql_real_escape_string() is one of a set of sanitizing functions available, for example, one would use a different sanitizer for dates.
too much work
Please share with me your know of any approach that overcomes these problems - I would really like better insight. That said, from my setting up the whole thing again, following my notes it took between 30 and 45 minutes. No time costs incurred thereafter.
I am happy with mysqli
How are you going to prevent SQL Injection Attacks when you cannot parameterize your SELECT? Do you expect to never use NULL when updating a column? Every man to his own poison, but these are issues I hope to solve - not live with.
#Konerack pointing out limited number of parameters
Right. Changed to code to use eval() (shudder) which solved the problem. Needs security review.
The Question Again
Will this approach protect against SQL Injection Attacks while overcoming the problems of no parameterized SELECT and mysqli's parameter limitations?
The answer is simple:
For parameters use PDO or mysql_real_escape_string().
For other dynamic SQL (table names, column names, syntax elements) use whitelisting.
See: How to prevent SQL injection with dynamic tablenames?
You cannot trust the browser to keep within the bounds you set in Javascript. This can be easily manipulated. So you must treat all data from that end as untrusted. Make sure you check all elements in the where clause against a list of allowed keywords.
For this purpose you'd use:
Check against whitelist for symbols: =, <>, >, LIKE, NULL, IS.
Check against a whitelist for boolean operators: AND, OR, XOR, NOT
All values must be properly enclosed in single ' quotes and you will need to feed these through mysql_real_escape_string() to make sure there are no shenanigans.
All values not in (1,2) and not enclosed in single quotes are column names, check them against a whitelist of allowed column names.
Reject all other input.
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.
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.