61924

Prevent XSS and SQL injections

— Frank — ? Comments

Just never trust user input/data. Everything that comes from the user is evil and you should always filter or escape it. In this article I'm going to explain how you can protect your website against the evil visitors that try to input malicious data into your database or website.

Magic quotes

This should be disabled, because it only causes trouble.What this does is automatically escape quotes and backslashes from all $_POST and $_GET data. This causes a problem, as when you run it through mysql_real_escape_string(), it will cause the backslashes put in by magic quotes to be escaped again.

Run this function to disable Magic quotes:

function disable_magic_quotes()
{
    // Turn off magic_quotes_runtime
    if (get_magic_quotes_runtime())
        set_magic_quotes_runtime(0);

    // Strip slashes from GET/POST/COOKIE (if magic_quotes_gpc is enabled)
    if (get_magic_quotes_gpc())
    {
        function stripslashes_array($array)
        {
            return is_array($array) ? array_map('stripslashes_array', $array) : stripslashes($array);
        }

        $_GET = stripslashes_array($_GET);
        $_POST = stripslashes_array($_POST);
        $_COOKIE = stripslashes_array($_COOKIE);
        $_REQUEST = stripslashes_array($_REQUEST);
    }
}

When to filter/escape user input

You don't have to filter user input all the time. Only if you output data to the browser (or something else) or input it in a database.

Here is an example where filtering isn't needed:

<?php

$section = isset($_GET['section']) ? $_GET['section'] : false;

if ($section == 'section1')
    echo 'Section 1';
else if ($section == 'section2')
    echo 'Section 2';
else
    echo 'Default section';

?>

The code just checks if $_GET['section'] has a certain value and nothing is send to the browser.

In the following cases you must filter the input. Note that these examples are wrong.

Url: http://example.com/index.php?id=123
Code: mysql_query('SELECT row FROM table WHERE id='.$_GET['id'].' LIMIT 1');

Url: http://example.com/index.php?page=about
Code: echo $GET['page'];

Now an example with a form:

<?php echo $_POST['text']; ?>

<form ... >
    <input type="text name="text"/ >
    <input type="submit" value="Submit" />
</form>

These were some simple examples and you shouldbe able to see where the vulnarebilities are. Not only $_GET and $_POST should be checked, but also $_SESSION, $_COOKIE, $_FILES, $_REQUEST, $_ENV, $_SERVER and all incoming data.

How to filter/escape

There are a lot of methods to filter data. You can use the built-in PHP functions (or built-in methods from other languages) or libraries like htmlpurifier.

Here are some correct examples:

<?php

// htmlspecialchars() to escape <, > and & to HTML entities
$js = '<script type="application/x-javascript">alert('Boo!');</script>';
echo htmlspecialchars($js, , ENT_QUOTES, 'UTF-8');

// mysql_real_escape_string() to prevent SQL injections
$mysql = ';DROP TABLE table ---';
mysql_query('SELECT row FROM table WHERE id='.mysql_real_escape_string($mysql).' LIMIT 1');

// You can use intval() to force a variable to an int
$id = 'this is not an id';
mysql_query('SELECT row FROM table WHERE id='.intval($id).' LIMIT 1');

?>

If you use another database type than MySQL like PostgreSQL, MySQLi or SQLite you can use pg_escape_string(), mysqli::real_escape_string() or sqlite_escape_string(). For other database types you could check the PHP database extensions.

You can also use the Filter functions from PHP. A great guide about the Filter functions can be found here.

I also recommend looking through the is_* functions (is_int, is_bool) With these functions you can check if a variable is the datatype you expected it to be.

(Re)Sources

Some useful resources (about XSS ans SQL injection...) that could be used.

End

Well, that's it. I hope this article was useful. Let me know if you think something is wrong or could be improved.

Share

Comments