PHP/MYSQL Prevent sql injection attacks function - php

I want to upgrade and make more systematic, my protection against sql injection attacks. I gather the three main methods are pdo, prepared statements and mysql_escape_string, that pdo is considered best but mysql_escape_string considered adequate if you are meticulous. I don't think I am ready to go to PDO or prepared statements as I have a lot of complicated queries involving multiple tables so this would be a huge task. But I want to make use of mysql_escape_string more programmatic.
Rather than escape every individual variable that users submit, I was thinking of escape the SQL commands with a standard function that might require some modification to handle punctuation Is this a sound approach or will escaping the whole query create problems-I do use apostrophes, backticks and %, for example. It would seem that a standard function for every sql statement would be more systematic and standard than the variable by variable approach. So question is what modifications to handle punctuation might be needed? Also, is there anything else that ought to go into the function such as htmlspecialchars and strip_tags as I gather mysql_escape_string is not 100% complete?
Here is basic function.
function safe($sql) {
$safesql = mysql_real_escape_string($sql);
return $safesql;
}

I don't think I am ready to go to PDO or prepared statements as I have a lot of complicated queries involving multiple tables so this would be a huge task.
Huge? Perhaps. Worth the effort though.
will escaping the whole query create problems
Yes. Your function will have no way of knowing if a piece of SQL is an injection attack or something you intended.
You have to escape text at the point where it is inserted into SQL. You can't insert text into SQL and then figure out which bit was SQL and which bit was text afterwards.
is there anything else that ought to go into the function such as htmlspecialchars and strip_tags
strip_tags throws data away. I wouldn't use it.
Both strip_tags and htmlspecialchars offer protection against unsafe data being inserted into an HTML document. Use them before inserting data into an HTML document, not before inserting data into SQL.

The only way to make it work with the whole query is if you write your own SQL parser, and even then, you must try to magically see which parts of the query is SQL injections. That's not possible so no, you cannot do this with the entire query at once.

Personally, I think you can safely assume that protecting your "complicated queries" on your own is much more complex and time-consuming than just using PDO, ActiveRecord or the likes. Additionally, you'll make your code more database-agnostic.

Just to clarify, you shouldn't be using mysql_real_escape_string around your whole query, only the string values you are using to build your query.
Example:
"Select Id from table where username ='".mysql_real_escape_string($username)."' limit 1";

I personally like the db-class the guys from phpBB have written. It's excellent, fast and pretty secure.

Related

PDO execute($input_parameter) protects from sql injections as bindParam/bindValue?

Does execute($input_parameter) protect from sql injections just like bindParam/bindValue?
If the answer is yes, bindParam()/bindValue()/execute() are invulnerable to any sql-inject attack? Or I need to take measures to prevent such attacks?.
Thanks for help!.
As far as execute($input_parameters) being as safe as separate bindParam/bindValue/execute steps, the answer would appear to be basically, yes.
However, you might still need to take further measures depending on how you constructed the query string that you pass to your PDO::prepare call. It is not always possible to parameter-ize everything in the prepared query string. For example, you can't use a parameter for a table or column name. If you allow user data or any external data into that query string you must still sanitize that data before passing the string to prepare.
Refer to these stackoverflow questions for more details:
how safe are PDO prepared statements
Are PDO prepared statements sufficient to prevent SQL injection?
In general you should be filtering all input data anyway, so if you wanted to be extra safe you could sanitize any input data that is destined for SQL-type stuff using the filters appropriate for your needs, or even writing a FILTER_CALLBACK custom function if you wish.
In the case of table or column names coming from user-provided data, a common validation technique is to check the values against arrays of allowable names.
Hope this helps. Good luck. Stay safe! ;)
Yes, it does the same thing. I cannot say that it is invulnerable, because the underlying SQL engine could itself be vulnerable. But that really isn't in your hands anymore.
So for all practical reasons, yes, its safe.
EDIT: Look at the PHP Documentation (1st and second example). One is with bindParam() and the other uses execute().

php: clear input data before inserting it into mysql database

I'm wondering what's the best way to celar input data before inserting it into a mysql database.
There are a lot of function: trim, addslashes, mysql_real_escape_string and so on.
At this moment i'm using this simple function:
function filter($var){
$data = preg_replace('/[^a-zA-Z0-9]/','',$var);
$data = trim(addslashes($data));
return $data;
}
What's the best way to do it? Thanks
to be on the safe side, when dealing with mysql, mysql_real_escape_string() -- always use this. always.
Using mysql_real_escape_string() is enough for security reasons. Another way to do it is using prepared statements.
But you should check what information in what type you want in your database. There are several functions and language constructs you could use: Typecasts, filter_*() functions, int_val(), abs(), trim(), and a whole lot more.
I suggest you take a look at prepared statements that pretty much protect you against all form of 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).
The best thing is to do multiple things:
Validate data
Clean data
escape date
The validation is to check whether the data you've got makes any sense. For instance if you expect a birth date you check whether the format is correct and maybe even whether the date amkes sense. This not only has security benefits but also prevents some (not all) errors of wrong data. The tools there depend on the case, regular expression (preg_match) are often a good choice.
Cleaning data is often not really needed, but nice, for instance if a user types in some value use trim() to split of some whitespaces, which might be mistakes from copy and paste or such. This has no security benefit but improves the overall quality of your data. Which is good.
Both of these things should be done early in your script. While "early" depends on your achitecture. Sometimes it makes sense to clean first an validate then or doing it at once (preg_replace)
Then when sending data of to a database or putting it in HTML or any of these things oyu have to escape it accordingly to the system you are using. You should do that for all data, even when you verfied the format beforehand to be on the safe side. When talking to mysql these are the real_escape_string functions for instance, for HTML it is htmlentities() or htmlspecialchars(). with databases it is also a good idea too look into prepared statements, either PDO->prepare + execute() or mysqli->prepare() +execute()

PHP: Is mysql_real_escape_string sufficient for cleaning user input?

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.

simple PHP $_GET sanitization question

I have a record edit link that GETs a 7 character alphanumeric text string which is always ZZZZ111 in structure and is then used in a MySQL query to pull all related data for that record id.
Is mysql_real_escape_string() all I need in terms of sanitizing this $_GET['id'] ? Or are there more steps to take to protect my database?
mysql_real_escape_string() will escape any malicious characters. In addition, you can use a regex like /^[A-Za-z]{4}\d{3}$/ to make sure that the user indeed entered a valid input.
To make input safe for an SQL query, mysql_real_escape_string() should be sufficient, though I suggest switching to PDO and prepared statements. They tend to be a little nicer to use, and a little more efficient (the statement is only parsed once, and the query can be re-used).
However, you also should make sure your pages are immune to cross-site scripting by (e.g.) filtering HTML from fields based on a whitelist.
If you plan on showing you data to users you would like to remove any HTML tags aswell. Maybe someone inserted a malicious javascript in a guestbook post for example?
this can be done with http://php.net/manual/en/function.htmlentities.php
Or you can use a inputfilter class to allow certain tags etc.
I found this one very useful http://www.phpclasses.org/browse/package/2189.html
mysql_real_escape_string() is a good start, and I would agree that using prepared statements would be a pretty good choice. Zend_Db is nice if you want to look into some DB abstraction which can make PDO easier to work with.
I'd also take this as an opportunity to write some sort of RegEx validator for your input. A sample regex that could get you started is:
[A-Z]{4}[0-9]{3}
More info on PHP and regex can be found here: http://www.regular-expressions.info/php.html
mysql_real_escape_string should do the job for $_GET['id']. Also, take a look at prepared statements via PDO.

Why is using a mysql prepared statement more secure than using the common escape functions?

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.

Categories