I have a function that checks user input and wanted to know if it prevents against all attacks of this sort. Also, if I wanted to include this function on each page that needed it could I put it in a php page of its own then 'include()' it into them pages where it's required. Thanks.
function secure_data($value)
{
if (get_magic_quotes_gpc()) {
$value = stripslashes($value);
}
if (function_exists("mysql_real_escape_string" )) {
$value = mysql_real_escape_string($value);
} else {
$value = addslashes($value);
}
return $value;
}
Since you're using quotes, I'm assuming that your main question is how to protect against SQL injections, if I'm not mistaken. (Note: securing against SQL-injection is something else then securing against for example Cross Site Scripting!); and will not guarantee you a secure application.
The best solution for SQL injection is not to use this function, but to use prepared statements with either mysqli or PDO.
(See: How can I prevent SQL injection in PHP? )
Other interesting links:
Background information on sql injection:
https://www.owasp.org/index.php/SQL_Injection
Other validation:
http://www.faqs.org/docs/gazette/superglobals.html
Input validation from OWASP:
https://www.owasp.org/index.php/Input_Validation
Related
Will this function below be able to prevent XSS attacks and sql injections ?
require_once('security.class.php');
function secure_data($data) {
$data = mysql_real_escape_string($data);
$filtered_data = filter_var($data, FILTER_SANITIZE_STRING);
$secure_class = new security_class();
$clean_data = $secure_class->xss_clean($filtered_data);
return $clean_data;
}
The security class is from codeigniter.
You shouldn't be trying to "brute force" security like this - layering all of these different filters/escapes one after another on every piece of data is silly and may actually make the escaping not work as intended.
This is because the kinds of characters that are added for one kind of escaping may be removed by another. You may also end up with over-escaping.
Instead, you should use the escaping function that is specifiy for what you are actually trying to do:
Before you put values into a SQL query, run them through mysqli_real_escape_string() (or better yet, use prepared statements via MySQLi/PDO).
Before you echo values out to a HTML response, run them through HTML escaping and/or XSS cleaning.
Etc.
In my web app is a config file which includes i.e. database connection settings ans is always loaded at the first line of a PHP script. I would like to include a function which cleans all POST and GET data for maybe existing XSS and SQL Injection risks.
I am not sure if that function is really enough
function make_safe($variable)
{
$variable = strip_tags(mysql_real_escape_string(trim($variable)));
return $variable;
}
foreach ($_POST as $key => $value) {
$_POST[$key] = make_safe($value);
}
//Same for $_GET & $_SESSION
Do you have recommendation for this problem?
This function:
function make_safe($variable)
{
$variable = strip_tags(mysql_real_escape_string(trim($variable)));
return $variable;
}
Will not work
SQL injection and XSS are two different beasts. Because they each require different escaping you need to use each escape function strip_tags and mysql_real_escape_string separatly.
Joining them up will defeat the security of each.
Use the standard mysql_real_escape_string() when inputting data into the database.
Use strip_tags() when querying stuff out of the database before outputting them to the screen.
Why combining the two function is dangerous
From the horses mouth: http://php.net/manual/en/function.strip-tags.php
Because strip_tags() does not actually validate the HTML, partial or broken tags can result in the removal of more text/data than expected.
So by inputting malformed html into a database field a smart attacker can use your naive implementation to defeat mysql_real_escape_string() in your combo.
I'm trying to make sanitize function to keep rest of the code simple.
Since I'm using MYSQLi I wonder if the following code is correct?
function sanitize ($data){
global $db_connect;
return htmlentities(strip_tags($db_connect->real_escape_string($data)));
}
function array_sanitize ($item) {
global $db_connect;
$item = htmlentities(strip_tags($db_connect->real_escape_string($item)));
}
I see two reasons why you sanitize the string:
Prevent from SQL injections
You should use prepared statements instead of using real_escape_string() to prevent from SQL injections. The Mysqli Extension supports prepared statements. They are most secure and easy to use. Use them.
Prevent from XSS attacks
To prevent from XSS attacks htmlentities() and strip_tags() may help. You should also make sure, that the functions handling the input charset correctly.
You should also read this document from OWASP
Does this protect against SQL injection attacks?
function sanitize($value) {
// Stripslashes
if (is_array($value)) {
if (get_magic_quotes_gpc()) {
$value = array_map("stripslashes", $value);
}
$value = array_map("mysql_real_escape_string", $value);
} else {
if (get_magic_quotes_gpc()) {
$value = stripslashes($value);
}
$value = mysql_real_escape_string($value);
}
return $value;
}
$_REQUEST = array_map('sanitize', $_REQUEST);
$_GET = array_map('sanitize', $_GET);
$_POST = array_map('sanitize', $_POST);
$_COOKIE = array_map('sanitize', $_COOKIE);
What could I add to sanitize() to protect against cross-site scripting?
What other channels would allow attackers to insert malicious code?
The one-word answer would be "yes". However:
If $value is an array that contains other arrays it won't be handled correctly. You should loop over $value make a recursive call to sanitize for each array you find.
It's preferable to use prepared statements instead of doing this. Of course, if you already have a complete application and are not building from scratch this can be problematic.
Finally, the other ways in which someone can subvert your application are cross-site scripting (aka CSS or XSS) and cross-site request forgeries (CSRF). There are lots of resources here on SO and on the internet you can use to get up to speed. As a starting point, protection against XSS involves calling htmlspecialchars on anything you output, while protection against CSRF involves requiring a session-specific id code for each operation your privileged users are allowed to perform on your site.
Array-safe sanitize version
function sanitize($value) {
if (is_array($value)) {
foreach($value as &$item) {
$item = sanitize($item);
}
} else {
if (get_magic_quotes_gpc()) {
$value = stripslashes($value);
}
$value = mysql_real_escape_string($value);
}
return $value;
}
Update:
For higher visibility: Bjoern's link to this question ( What's the best method for sanitizing user input with PHP? ) is really good.
No.
Use PHP Data Objects Or... Use a Database Abstraction Layer Or... Some framework that does this.
Don't write your own because:
Someone else has
Their code works fine
You can use their code for free
They thought of all the issues you don't know about yet.
It's a lot of work to do this, it's already been done, just spend twenty minutes and figure out someone else's code that does this.
If it is applied after the database connection was established, then it escapes the initial input data correctly.
Now you will have problems using such escaped values for HTML output however. And it does not protect against second order SQL injection (querying the database, then using those values as-is for a second query). And more importantly, most applications work on the input values. If you do any sort of rewriting or string matching, you might undo some of the escaping.
Hencewhy it is often recommended to apply the escaping right before the query is assembled. Nevertheless, the code itself is functional for the general case and advisable if you can't rewrite heaps of legacy code.
You should add html_entities. Most of the time you put $_POST variables into a textbox, like:
<textarea><?php echo $_POST['field']; ?></textarea>
They can mess up your HTML by filling in and do anything they want.
There is some risk in using the function extract in the superglobal variables as $_POST and $_GET, I work of the following way.
There is risk of SQL INJECTION or there is an alternative to extract
if(get_magic_quotes_gpc()) {
$_GET = stripslashes($_GET);
$_POST =stripslashes($_POST);
}
function vars_globals($value = '') {
if(is_array($value))
$r = &$value;
else
parse_str($value, $r);
return $r;
}
$r = vars_globals($_GET);
extract($r, EXTR_SKIP);
Yes there is a risk. You don't want to blindly import user input into your symbol table. You should take the time to validate and/or sanitize user input. The filter_var function can help with this.
When inserting into a database, use the driver's escape mechanism to eliminate the possibility of injection. If you're using mysql_* functions, you'd use mysql_real_escape_string. However, it is much better to use PDO and parameterized queries for this.