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.
Related
This question already has answers here:
How can I prevent SQL injection in PHP?
(27 answers)
Closed 9 years ago.
I have been fussing around with my PHP code and SQL statements and while I do know that one could use prepared statements when dealing with this, I still wonder how a SQL injection could be performed here.
$name = mysql_real_escape_string(htmlspecialchars($_POST["Name"]));
$age = (int) mysql_real_escape_string(htmlspecialchars($_POST["Age"]));
$amount = (int) mysql_real_escape_string($_POST["Amount"]);
$sql = "insert into nice_table set
name='{$name}',
age='{$age}',
amount='{$amount}'";
$db->sql_query($sql);
I don't know a lot about all different methods when performing a SQL injection, but all the stuff I've looked up passes just fine through this without any database errors. Would it actually be safe to use this instead of the classic prepared statements?
What would be passed right through, for example? I must be missing something, because it can't be this simple and still hold as tight as prepared statements, right?
mysql_real_escape_string ALONE can't prevent all type of SQL Injection.
Whenever you need escaping, you need it despite of "security", but just because it is required by SQL syntax. And where you don't need it, escaping won't help you even a bit.
The usage of this function is simple: when you have to use a quoted string in the query, you have to escape it's contents. Not because of some imaginary "malicious users", but merely to escape these quotes that were used to delimit a string. This is extremely simple rule, yet extremely mistaken by PHP folks.
This is just syntax related function, not security related.
Depending on this function in security matters, believing that it will "secure your database against malicious users" WILL lead you to injection.
A conclusion that you can make yourself:
No, this function is not enough.
Prepared statements is not a silver bullet too. It covers your back for only half of possible cases. See the important addition I made to the famous question for the details
mysql_ functions are deprecated. Preffer mysqli or pdo classes.
And AFAIK, it is possible to use special characters to avoid mysql_real_escape_string.
I would preffer to use prepared statements and validation. You probably wants only alfanumerics and dot to be possible inputs on name. That would help too :P
No, you are using mysql_real_escape_string() properly, so this will be safe.
For the latter two variables, you could also do
$age = intval($_POST["Age"]);
$amount = intval($_POST["Amount"]);
and that will be just as safe. Intval always returns an integer (0 on error), so it's impossible to contain any not-mysql-safe characters.
I'm using PHP PDO for my queries, everywhere, but I read that in very rare cases there could still be "second order injections" where an unsafe variable is stored then executed when used in another statement.
Will prepared statements still protect against this? As long as I make sure I always use them? Or do I have to take more precautions? Am I still vulnerable to XSS attacks?
I also have a couple more questions, just out of curiosity, if you all don't mind:
Is it possible to have an SQL Injection with only alphanumeric characters, spaces, and one dash? Like select * from something where name='$some_variable'. All the examples I've seen seem to require other characters like semicolons, quotes, or double dashes.
I've read many SQL examples where the unsafe variable could be set to form another statement, eg
$foo = "foo'); INSERT INTO users (name) VALUES ('hi";
$bar = ("INSERT INTO users (name) VALUES ('$foo')");
But I just tested and mysql_query doesn't even allow multiple statements. I know you can still have injections within 1 statement, but can I confirm that you won't have problems with multiple statements in PHP?
Not to beat a dead (or is it a very alive?) horse, but...
Injection can only happen when data is read by the SQL engine as commands. In a very simple case, if you allow unescaped " characters in your data, and your data is encapsulated by " characters in SQL, they you have enabled an SQL injection attack.
The key to preventing any SQL injection is to properly validate and escape incoming data EVERY time, at the time it goes into the SQL statement. An easy way to do this is to just use prepared statements, which take care of it for you, allowing you to safely pass parameters to an SQL statement.
Each database library has it's own way of escaping or using prepared statements. In MySQL and PHP, you have mysqli_real_escape_string(), which should be used EVERY TIME PERIOD, when you are using the mysqli library.
The PDO library has it's own way, but if I recall correctly, prepared statements were a big part of PDO -- use them 100% of the time, and you will be OK in that regard.
To prevent agains XSS attacks, use HTML Purifier, and never strip_tags(), see links below for more info, PDO prepared statements should be fine for SQL Injection prevention:
http://www.reddit.com/r/PHP/comments/nj5t0/what_everyone_should_know_about_strip_tags/
http://htmlpurifier.org/
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 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.
There's a comment in another question that says the following:
"When it comes to database queries,
always try and use prepared
parameterised queries. The mysqli and
PDO libraries support this. This is
infinitely safer than using escaping
functions such as
mysql_real_escape_string."
Source
So, what i want to ask is: Why are prepared parameterized queries more secure?
An important point that I think people here are missing is that with a database that supports parameterized queries, there is no 'escaping' to worry about. The database engine doesn't combine the bound variables into the SQL statement and then parse the whole thing; The bound variables are kept separate and never parsed as a generic SQL statement.
That's where the security and speed comes from. The database engine knows the placeholder contains data only, so it is never parsed as a full SQL statement. The speedup comes when you prepare a statement once and then execute it many times; the canonical example being inserting multiple records into the same table. In this case, the database engine needs to parse, optimize, etc. only once.
Now, one gotcha is with database abstraction libraries. They sometimes fake it by just inserting the bound variables into the SQL statement with the proper escaping. Still, that is better than doing it yourself.
For one, you're leaving the escaping of dangerous characters to the database, which is a lot safer than you, the human.
... it won't forget to escape, or miss out on any special characters which could be used to inject some malicious SQL. Not to mention, you could possibly get a performance improvement to boot!
I am not extremely versed in security but here is an explanation that I hope will help you:
Let's say you have a statement like:
select [integer] from mydb
Pretend when you prepare it, the statement is compiled down to bytes in our imaginary sql implementation.
01 00 00 23
Opcode for select Prepared bytes number of "mydb"
for your integer
Now when you execute, you will insert the number into the space reserved for your prepared statement.
Compare it to if you just use escape, you could possibly insert as much gibberish in there and maybe cause the memory to overflow, or some bizzare sql command that they forgot to escape.
Because with prepared statements, you can't forget to escape the content. So there are no way to introduce insecurity.
mysql_real_escape_string is as safe as prepared statements IF you remember to use mysql_real_escape_string each time you call mysql_query, but it's easy to forget.
Prepared statements solve a fundamental problem of application security that mere data sanitation does not: They result in a complete separation of the data and the instructions. When the two get confused, insecurity is the result. This is true for SQL injection as well as buffer overflows.
(There are other ways to be insecure.)
Very best case, it might not be, but it's at least equally safe; and why take the chance?
The function is not safe because of this exploit http://shiflett.org/blog/2006/jan/addslashes-versus-mysql-real-escape-string. That is why prepared statements are preferred and it gives performance improvement as well.