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/
Related
I've read in several places that htmlspecialchars is not enough to prevent SQL injection attacks. I'm working with a legacy codebase and it uses this to sanitize user input:
stripslashes(htmlspecialchars(trim($value), ENT_QUOTES, 'UTF-8'))
My gut tells me that this is also unsafe but my coworker insists that it is. I don't have much experience in working with plain PHP so could someone please tell me why this is unsafe so that I can convince my coworker to use something better?
I've read in several places that htmlspecialchars is not enough to prevent SQL injection attacks
It protects against XSS attacks, but SQL is not HTML so it does nothing for SQL injection.
(You should move the htmlspecialchars encoding to "before inserting into HTML" instead of "before inserting into SQL")
My gut tells me that this is also unsafe but my coworker insists that it is.
Your gut is right. The fact it leaves quote characters alone shouts unsafe!.
Take a look at Bobby Tables. It demonstrates the problem and provides a number of solutions. Anything that uses bound parameters is good.
Use prepared statements.
disable magic quote in php.ini and use PDO. bum
htmlspecialchars to escape params in SQL is the ugliest
It may prevent you from XSS, but not from SQLi, because it doesn't quote any SQL-specific (or DBMS-specific) special characters. The most modern solution is to use PDO with Prepared Statement or PDO:quote(). Legacy solutions cover mysql_escape_string() and such. Refer the manual about the db-driver you are using, about the features it provides to prevent you from SQLi.
You should be calling a database specific escaping function on things you insert into queries.
For a MYSQL database, use mysql_real_escape_string.
It depends on the type of SQL query it is injecting. SQL injections in string fields (enclosed with ' and ") can be disabled by encoding or removing this characters. But in general this is not the solution!
You should NEVER EVER concatenate the SQL string together and send it to the database, especially if it contains user supplied data. You should always use the prepare statement to prepare a SQL statement with placeholders and then pass the parameters separately. Yes, this means that you will probably need to have more than one line of code and you will call corresponding SQL functions.
This is the only good solution for this that is implemented in all programming languages.
mysql_real_escape_string would be better than mysql_escape_string as it has been deprecated.
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.
I'm new to PHP, and not yet familiar with how this works.
If I use mysqli_real_escape_string() and parameterize every variable in the SQL query, can I spare myself doing the validation with is_numeric(), etc.?
What is the best way to create a injection detection system? Simply validate the user's input with regex stuff and save it in the database?
Parametrizing your query is enough, you don't need anything else. You'll input the stuff they "inject" als a string, and there is nothing especially wrong with sql in a database... I suspect SO's database is full of SQL ;)
Escaping a value for MySQL simply adds a backslash in front of of the following characters: NULL \n \r \ ' " and 0x1A. It does nothing else.
An "escaped" value isn't magically safe for use in SQL. Escaping prevents special characters (such as quotes) from being misinterpreted. But if you insert an escaped value into an SQL query without surrounding it in quotes, then you've completely missed the point, and you are no more safe than you would have otherwise been.
Remember, the security procedure is quote and escape. You should always use those two together, since neither is safe without the other.
Also, if you can absolutely guarantee that your input value contains none of the above characters, then you also can be certain that your escaped string will always be identical to the unescaped one, and therefore escaping serves no additional purpose under those conditions.
But More Importantly:
Finally we have, in retrospect, realized that SQL was poorly designed from a security perspective, and relying on users properly quote and escape their data is just a really bad idea.
Parameterized queries are the solution, since it safely separates the data from the control structure. Parameterized queries are possible with mysqli by using prepare() followed by bind_param(). No escaping is necessary when using this method, and you can be confident that you are absolutely immune from SQL injection attacks.
Even if you have protected your variables against injection by using a parameterized query or mysql_real_escape_string() (not mysql_escape_string()), you should still validate them on the server side to ensure that they match the expected type of input. That way, if they do not, you can return an error message to your user with a request to retry those form fields.
If you use a parameterized query, such as offered by MySQLi as prepared statements, you needn't also escape the strings. However, if you don't use a parameterized query, it is essential to call mysql_real_escape_string() on every input parameter received by PHP.
This is a good question, and I think one of the best ways to avoid SQL injection is to learn about proper use of prepared statements
These will really help out the security of your application.
The issue with sql injection is the user inserting SQL data into a command and not validating that the data meets your business rules.
Making sure all user data is passed through mysqli_real_escape_string or used prepared statements is the best way to avoid problems.
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.
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.