Best security questions in May 2012

How are input keys exploitable by malicious users?

18 votes

In the CodeIgniter PHP framework, there is a function that automatically runs on each request that, among other things, filters the GET/POST/COOKIE array keys, and kills the application if it encounters characters it deems unsafe.

To prevent malicious users from trying to exploit keys we make sure that keys are only named with alpha-numeric text and a few other items.

Something like:

// foreach GET/POST/COOKIE keys as $str...
if ( ! preg_match("/^[a-z0-9:_\/-]+$/i", $str))
{
    exit('Disallowed Key Characters.');
}

For example, this will trigger if you accidentally post something like <input name="TE$T"> or have a query string like ?name|first=1.

I can see this being a good way to enforce common sense key names, or catch mistakes while developing an application, but I don't understand: How can a malicious user possibly "exploit keys" in $_POST data for instance? Especially since (I would assume) input values are just as exploitable, what is this actually preventing?

Your question, in itself, brings up a good point: it's unclear what exactly you're being protected against. But there are some popular items it could be addressing:

  • magic quotes
  • things that could eventually lead to SQL injection
  • strings that could be executed by way of shell commands
  • things that could conflict with your URL
  • things that could conflict with HTML
  • things that resemble a directory traversal attack
  • cross site scripting (XSS) attacks

But other than those, I really can't think of why you'd always why you'd want to generally protect via preg_match("/^[a-z0-9:_\/-]+$/i", $str).

I've got the feeling that they're overprotecting simply because CodeIgniter is so widely used that they need to protect against things they themselves haven't thought of yet for the sake of their users who may be even less-aware of such attacks than CodeIgniter's developers.

Secure string compare function

15 votes

I just came across this code in the HTTP Auth library of the Zend Framework. It seems to be using a special string compare function to make it more secure. However, I don't quite understand the comments. Could anybody explain why this function is more secure than doing $a == $b?

/**
 * Securely compare two strings for equality while avoided C level memcmp()
 * optimisations capable of leaking timing information useful to an attacker
 * attempting to iteratively guess the unknown string (e.g. password) being
 * compared against.
 *
 * @param string $a
 * @param string $b
 * @return bool
 */
protected function _secureStringCompare($a, $b)
{
    if (strlen($a) !== strlen($b)) {
        return false;
    }
    $result = 0;
    for ($i = 0; $i < strlen($a); $i++) {
        $result |= ord($a[$i]) ^ ord($b[$i]);
    }
    return $result == 0;
}

It looks like they're trying to prevent timing attacks.

In cryptography, a timing attack is a side channel attack in which the attacker attempts to compromise a cryptosystem by analyzing the time taken to execute cryptographic algorithms. Every logical operation in a computer takes time to execute, and the time can differ based on the input; with precise measurements of the time for each operation, an attacker can work backwards to the input.

Basically, if it takes a different amount of time to compare a correct password and an incorrect password, then you can use the timing to figure out how many characters of the password you've guessed correctly.

Consider an extremely flawed string comparison (this is basically the normal string equality function, with an obvious wait added):

function compare(a, b) {
    if(len(a) !== len(b)) { 
        return false;
    }
    for(i = 0; i < len(a); ++i) {
        if(a[i] !== b[i]) {
            return false;
        }
        wait(10); // wait 10 ms
    }
    return true;
}

Say you give a password and it (consistently) takes some amount of time for one password, and about 10 ms longer for another. What does this tell you? It means the second password has one more character correct than the first one.

This lets you do movie hacking -- where you guess a password one character at a time (which is much easier than guessing every single possible password).

In the real world, there's other factors involved, so you have to try a password many, many times to handle the randomness of the real world, but you can still try every one character password until one is obviously taking longer, then start on two character password, and so on.

This function still has a minor problem here:

if(strlen($a) !== strlen($b)) { 
    return false;
}

It lets you use timing attacks to figure out the correct length of the password, which lets you not bother guessing any shorter or longer passwords. In general, you want to hash your passwords first (which will create equal-length strings), so I'm guessing they didn't consider it to be a problem.

Why is it a bad idea to tell your server to parse HTML as PHP?

11 votes

You know you can make a server parse HTML pages as PHP (execute PHP code in a HTML doc) using .htaccess?

Well, some people say it's bad to do so. Why?

Some people also say it opens a security vulnerability in your application. How?

The source code is still removed before the document reaches the browser, so it can't be the case of unauthorized access to source code, right?

Let me start with a little story: back when I was a security contact at a Linux distribution vendor, the PHP security team begged Linux vendors to stop calling interpreter crashes security bugs, even when the PHP interpreter was running inside the web server (say, mod_php on Apache). (At the time, roughly one interpreter crash was being found per week.)

It took a little bit of conversation for them to actually convince us that whoever supplied the running PHP code is completely trusted and any attempt to control what the scripts could do from the interpreter was misguided -- and if someone figured out how to crash the interpreter to walk around the restrictions it tried to impose (such as the entire silly safe mode pile of crap), it was not a security flaw, because the safe execution of scripts was not the goal of the PHP interpreter -- it never was and never would be.

I'm actually pretty happy with the end result of the discussions -- it clearly defined PHP's security goals: You should only ever allow execution of PHP code that you 100% completely trust. If you do not trust it, you do not run it. It's that simple.

Whatever operating system resources are available to the interpreter are all available and fair game, regardless of whether the script exploits a bug in the interpreter or just does something unexpected.

So, please do not allow random code to be executed in the context of your webserver unless that is what you really want.

Please use the principle of least privilege to guide what resources are available to every program.

Consider using a mandatory access control tool such as AppArmor, SELinux, TOMOYO, or SMACK to further confine what your programs can and can't do. I've worked on the AppArmor project since 2001 or so and am fairly confident that with a day's effort most system administrators can enhance their sites security in a meaningful way with AppArmor. Please evaluate several options, as the different tools are designed around different security models -- one or another may be a better fit.

But whatever you do, please don't run your server in a fashion that needlessly opens it up to attack via extra vectors.

Secure storage of database credentials

4 votes

Had a major problem recently where my web hosting company messed up and all my php files were displayed in plain text. This was a major issue for me for obvious reasons. Mainly because mysql database details were exposed.

I am now trying to change the way in which my php files get the login information for the database so that this will never happen again even if the hosting company fail me.

my current set up looks like this :

     include 'info.php';

    class Login {

var $host;
var $username;
var $password;
var $db;
var $url;

Inside the info.php is the username, password and so on for the database. I want to make it so that the info.php file can never be viewed and only my .php files are able to access info.php in order to get the login infomation.

How can i set this up? This is a bit of a tricky one for me to explain so please dont be harsh and -1 me for a bad description.. just ask and i will clear up any gaps in my description.

Simply place info.php outside your webroot. This way, you can include it, but should your web hosting f*#$ up, no one else can view that file, even as plain text.

You would then include it like this:

include('../info.php');

This way, even if someone finds out that you have a file called info.php that stores all your passwords, they cannot point their browser to that file.

The above would be the ideal and most watertight solution. However, if that is not possible due to permissions, the other option would be to place all sensitive files in a directory and block direct access to that directory using a .htaccess file.

In the directory you want to block off access to, place an .htaccess file with the following contents:

deny from all