views:

509

answers:

6

How do you protect your website from Local File Inclusion & SQL Injection (PHP)?

+2  A: 

There are numerous measures to be taken. Be sure to sanitize all input before storing in the database. I suggest using mysql_real_escape_string() on all data that will be stored. Limit character-input to reasonable lengths, and be sure you're getting the TYPE of data you are expecting for that field. Lock multiple attempts to submitting specific areas of data. Crawl the contents of uploaded files looking for malicious patterns.

Wikibooks has a chapter on SQL Injection;

The list goes on and on. Fortunately, even a little effort in this area can patch a great number of vulnerabilities.

Jonathan Sampson
or better yet, parametrized queries
Joe Philllips
Yes, another great suggestion.
Jonathan Sampson
IIRC, mysql_real_escape_string() will not save you if the param is a number (or any non-string). You need to coerce such parameters to be numbers either by using some printf()-style function or by typecasting.
rmeador
rmeador, great suggestion regarding expected data types. I've updated the post.
Jonathan Sampson
+2  A: 

http://php.net/manual/en/security.php

I.devries
+1  A: 

for protecting against SQL injection i'd recommend using PDO (http://us3.php.net/pdo). There's extensions etc that you need which can block adoption but it's good stuff.

Personally I use a home brewed DB access layer that all my queries go thru which implements a bunch of nice-to-have's including mysql_real_escape_string()

arin sarkissian
A: 

Like others have said, mysql\_real\_escape\_string() is the safest method to prevent SQL injection. I use a custom DB interface class for all my SQL, which passes all the needed variables through a sanitize() function. Here's that sanitize function stripped from the class in case you wanna take a look at it.

/**
* Sanitize variable for querying
*
* @param mixed $var      The variable to sanitize
* @param bool $deep      Will inspect the string deeper, converting 'null' to NULL and adding '' around strings
* @param mixed $numstrings  Whether or not to treat numbers as strings (ie add quotes)
* @return $var
*/
function sanitize($var, $deep = true, $numstrings = false) {
    if (is_array($var)) {   //run each array item through this function (by reference)
        foreach ($var as $key=>$val) {
     $var[$key] = sanitize($val, $deep, $numstrings);
        }
    }
    else if (is_null($var) || ( $deep && preg_match('/^null$/i', $var) > 0 ) ) {   //convert null variables to SQL NULL
        $var = "NULL";
    }
    else if (is_bool($var)) {   //convert boolean variables to binary boolean
        $var = ($var) ? 1 : 0;
    }
    else if ($numstrings && is_string($var)) {
        $var = mysql_real_escape_string($var);
        if ($quotes) {
     $var = "'". $var ."'";
        }
    }
    else if (!is_numeric($var)) { //clean strings
        $var = mysql_real_escape_string($var);
        if ($deep) {
     $var = "'". $var ."'";
        }
    }
    return $var;
}

As for "local-file inclusion", I use two different methods. Keep in mind that the safest technique is to keep sensitive files in a place not accessible from the web.

If it's only a file or to I don't want the world to see, I simply append '.ht' to the filename. Apache, by default, denies access to files beginning with '.ht'. Just make sure not to name your files the same as Apache config files (.htaccess, .htpasswd, etc).

If you have multiple files that you don't want accessed, keep them all in a sub-directory of your site (again, sensitive files should be elsewhere). Then in the sub-directory, add a .htaccess file that denies access to the directory (they are still accessible via PHP).

#this is all you need in the file
Order Allow , Deny
Deny from all
tj111
+1  A: 

Prepared statements for SQL (see PDO::prepare()) or proper escaping (PDO::quote()).

For local paths you need to carefully sanitize input (brutal, but safe: preg_replace('/[^a-z]/','',$str)) or avoid using untrusted data in paths altogether (use IDs, predefined strings, etc.)

porneL
A: 

By "local file inclusion", do you mean the case where you call include() or suchlike on a path constructed from user input, such as in a very simple file-based CMS or similar? If so, the answer is basically the same as for SQL injection - you have to sanitise the input.

Sanitising file paths requires you to set some ground rules about where files can be included from, and to ruthlessly reject any input which doesn't conform. For example, if you're just including files by name in a subdirectory, then you might apply the following basic algorithm:

  1. Reject file names which contain ., .. or / (or \ under Windows)
  2. Limit file names to basic alphanumeric characters
  3. Prepend the include directory name and append the appropriate extension

The PHP documentation has some more information about filesystem security. You could also set up open_basedir to confine file access to within a specific directory tree, but that is part of PHP's "safe mode", which is deprecated (and will be removed in PHP 6.0), owing to it not really being very safe.

Rob