Possible Duplicate:
SQL injection that gets around mysql_real_escape_string()
I havent seen any valuabe or not outdated info on this.
So, there is this question: Does mysql_real_escape_string() FULLY protect against SQL injection? Yet it is very outdated(its from '09), so as of php 5.3 and mysql 5.5 in '12, does it protect fully ?
mysql_real_escape_string ALONE can prevent nothing.
Moreover, this function has nothing to do with injections at all.
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
long time since I read a blog post about this so it may no longer hold true BUT...
The posts stated that if you had unicode encoded characters in your string they would be missed by real escape string but would be evaluated by mysql engine - alluding to the idea that you could indeed still be open to a well placed injection.
I can't remember the blog post but this question on here is in the same ball-park.
Yes. By properly escaping the string using the native mysql escape functions, it's not possible to "break out" and execute a query.
However, a better approach would be to use prepared statements. This will do a number of things. By using prepared statements you take advantage of even more optimization from the database and it will properly escape any data passed in. Take a look at: http://php.net/manual/en/mysqli.prepare.php
Related
This question already has answers here:
How can I prevent SQL injection in PHP?
(27 answers)
Closed 8 years ago.
First of all, let's get one thing straight, while im sure it's not the ONLY solution to sql injections, PREPARED STATEMENTS ARE BETTER and MORE SECURE... that's granted.
So let's not debate it anymore, as I just needed to explore the escaping options and target the user inputs rather than the statement..
(a bit of back story)
I have a huge application w/ lots of basic SQL statements which i need to make "safer" in a short period of time. Converting all statements to PDO is a monster of a task which requires resources not available to this situation.
But good thing is that there's a hook in the application where ALL incoming $_GET/$_POST passes through a function before making available as plain variable in the scripts... ( eg.globalize($_POST) )
So i'm looking to target that function instead and focus on "cleaning" user input ...
I pretty much got a good grasp of SQL injection techniques, and basically much of its concept, such as:
1) Whenever there is user input involved in a statement, that's when the attacker has an opportunity
2) The main mission is to break your statement's quoting by simple single or double quotes as string, or character codes, in the attacker's input..
3) Escaping is good at preventing SQL injections except for that situation when the DATABASE character encoding is able to ready multibyte representations of those nasty illegal strings and the script based escaping misses it.
Based on the above premise, what if:
1) All my SQL Statements follow a standard where user input is quoted using single quotes ALWAYS, therefore there is no guess work for me anymore on what type of quote i need to escape (single quotes)
2) all user inputs (POST / GET) go through a function (eg. globalize() ) that basically addslashes() and globalizes each variable
3) This is an intranet application and the scripts can be made aware of the database encoding support.
QUESTION:
What are the threats currently available in the above situation and how can we handle them?
...i personally was looking into simply adding routines to the globalize() function similar to mysql_real_escape_string() .. or go as far as "tweaking" the SQL statements to use mysql_real_escape_string() as that is a lot easier/faster to do than programming statements on each sql query..
PS
Of course this script may never be as secure as prepared statements, but i just need to make it hard enough for most attackers (not looking to 100% bullet proof it as it is not that worth it)
Using
mysql_real_escape_string($link,$non_escaped_string);
See here: http://php.net/manual/en/mysqli.real-escape-string.php
While it might well work, there are a few possible issues.
If you use addslashes then there are potential exploits, hence for MySQL mysql_real_escape_string() is generally better. There is a potential flaw in mysql_real_escape_string() (which also applies to the default use of pdo), but this is so esoteric you pretty much have to try to make your code open to an attack based on it.
The bigger issue is that your user input could possibly be used on different databases with different character sets. Hence you should specify the link to the database that the escaped string will be used in. If you do not specify this the the details of the last link opened will be used. If no link has already been used then it will try and connect itself with some default connection parameters and the results are likely to be unpredictable.
If you just escape all the $_POST / $_GET / $_REQUEST arrays (and remember that $_COOKIES array is also subject to being changed by a mischievous user) then the likely place you would do this would be when the scripts are first loaded, when you are unlikely to have connected to the appropriate database.
A further issue is that some of the code you are dealing with (and which you seem not to have the time deal with in detail) is bound to already escape the input data. Hence you will land up double escaping it with strange results. Related (but less likely to be an issue) is escaping numeric fields
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'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'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.
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.