[ En fran�ais: http://www.nexen.net/interview/index.php?id=30 ]
The Open Web Application Security
Project released a helpful document that lists what they think are the top ten security
vulnerabilities in web applications.
These vulnerabilities can, of course, exist in PHP
applications. Here are some tips on how to avoid them. I've included
related links and references where relevant.
1. Unvalidated Parameters
Most importantly, turn off register_globals . This
configuration setting defaults to off in PHP 4.2.0 and later. Access
values from URLs, forms, and cookies through the superglobal arrays
$_GET , $_POST , and $_COOKIE .
Before you use values from the superglobal arrays, validate them to
make sure they don't contain unexpected input. If you know what type of
value you are expecting, make sure what you've got conforms to an
expected format. For example, if you're expecting a US ZIP Code, make
sure your value is either five digits or five digits, a hyphen, and
four more digits (ZIP+4). Often, regular expressions are the easiest
way to validate data:
if (preg_match('/^\d{5}(-\d{4})?$/',$_GET['zip'])) {
$zip = $_GET['zip'];
} else {
die('Invalid ZIP Code format.');
}
If you're expecting to receive data in a cookie or a hidden form
field that you've previously sent to a client, make sure it hasn't been
tampered with by sending a hash of the data and a secret word along
with the data. Put the hash in a hidden form field (or in the cookie)
along with the data. When you receive the data and the hash, re-hash
the data and make sure the new hash matches the old one:
// sending the cookie
$secret_word = 'gargamel';
$id = 123745323;
$hash = md5($secret_word.$id);
setcookie('id',$id.'-'.$hash);
// receiving and verifying the cookie
list($cookie_id,$cookie_hash) = explode('-',$_COOKIE['id']);
if (md5($secret_word.$cookie_id) == $cookie_hash) {
$id = $cookie_id;
} else {
die('Invalid cookie.');
}
If a user has changed the ID value in the cookie, the hashes won't
match. The success of this method obviously depends on keeping
$secret_word secret, so put it in a file that can't be
read by just anybody and change it periodically. (But remember, when
you change it, old hashes that might be lying around in cookies will
no longer be valid.)
See Also:
- PHP Manual: Using
Register Globals
- PHP Cookbook: Recipe 9.7 ("Securing PHP's Form Processing"), Recipe 14.3 ("Verifying Data with Hashes")
2. Broken Access Control
Instead of rolling your own access control solution, use PEAR
modules. Auth does cookie-based authentication for you
and Auth_HTTP does browser-based authentication.
See Also:
3. Broken Account and Session Management
Use PHP's built-in session management functions for secure,
standardized session management. However, be careful how your server
is configured to store session information. For example, if session
contents are stored as world-readable files in /tmp, then any user
that logs into the server can see the contents of all the
sessions. Store the sessions in a database or in a part of the
file system that only trusted users can access.
To prevent network sniffers from scooping up session IDs,
session-specific traffic should be sent over SSL. You don't need to do
anything special to PHP when you're using an SSL connection, but you
do need to specially configure your webserver.
See Also:
- PHP Manual: Session handling functions
- PHP Cookbook: Recipe 8.5 ("Using Session Tracking"), Recipe 8.6 ("Storing Sessions in a Database")
4. Cross-Site Scripting (XSS) Flaws
Never display any information coming from outside your program
without filtering it first. Filter variables before including them in
hidden form fields, in query strings, or just plain page output.
PHP gives you plenty of tools to filter untrusted data:
htmlspecialchars() turns & > "
< into their HTML-entity equivalents and can also convert
single quotes by passing ENT_QUOTES as a second
argument.
strtr() filters any characters you'd like. Pass
strtr() an array of characters and their replacements. To
change ( and ) into their entity
equivalents, which is recommended to prevent XSS attacks, do:
$safer = strtr($untrusted, array('(' => '(', ')' =>
')'));
strip_tags() removes HTML and PHP tags from a
string.
utf8_decode() converts the ISO-8859-1 characters
in a string encoded with the Unicode UTF-8 encoding to single-byte
ASCII characters. Sometimes cross-site scripting attackers attempt to
hide their attacks in Unicode encoding. You can use
utf8_decode() to peel off that encoding.
See Also:
5. Buffer Overflows
You can't allocate memory at runtime in PHP and their are no
pointers like in C so your PHP code, however sloppy it may be, won't
have any buffer overflows. What you do have to watch out for, however,
are buffer overflows in PHP itself (and its extensions.) Subscribe to
the php-announce mailing list to keep abreast of patches and
new releases.
See Also:
6. Command Injection Flaws
Cross-site scripting flaws happen when you display unfiltered,
unescaped malicious content to a user's browser. Command injection
flaws happen when you pass unfiltered, unescaped malicious commands to
an external process or database. To prevent command injection flaws,
in addition to validating input, always escape user input before
passing it to an external process or database.
If you're passing user input to a shell (via a command like
exec() , system() , or the backtick operator),
first, ask yourself if you really need to. Most file operations can be
performed with native PHP functions. If you absolutely, positively
need to run an external program whose name or arguments come from
untrusted input, escape program names with
escapeshellcmd() and arguments with
escapeshellarg() .
Before executing an external program or opening an external file,
you should also canonicalize its pathname with
realpath() . This expands all symbolic links, translates
. (current directory) .. (parent directory),
and removes duplicate directory separators. Once a pathname is
canonicalized you can test it to make sure it meets certain criteria,
like being beneath the web server document root or in a user's home
directory.
If you're passing user input to a SQL query, escape the input with
addslashes() before putting it into the query. If you're
using MySQL, escape strings with
mysql_real_escape_string() (or
mysql_escape_string() for PHP versions before 4.3.0). If
you're using the PEAR DB database abstraction layer, you can use the
DB::quote() method or use a query placeholder like ? ,
which automatically escapes the value that replaces the
placeholder.
See Also:
7. Error Handling Problems
If users (and attackers) can see the raw error messages returned
from PHP, your database, or external programs, they can make educated
guesses about how your system is organized and what software you
use. These educated guesses make it easier for attackers to break into
your system. Error messages shouldn't contain any descriptive system
information. Tell PHP to put error messages in your server's error log
instead of displaying them to a user with these configuration
directives:
log_errors = On
display_errors = Off
See Also:
8. Insecure Use of Cryptography
The mcrypt extension provides a standardized interface
to many popular cryptographic algorithms. Use mcrypt
instead of rolling your own encryption scheme. Also, be careful about
where (if anywhere) you store encryption keys. The strongest algorithm
in the world is pointless if an attacker can easily obtain a key for
decryption. If you need to store keys at all, store them apart from
encrypted data. Better yet, don't store the keys and prompt users to
enter them when something needs to be decrypted. (Of course, if you're
prompting a user over the web for sensitive information like an
encryption key, that prompt and the user's reply should be passed over
SSL.)
See Also:
9. Remote Administration Flaws
When possible, run remote administration tools over an SSL
connection to prevent sniffing of passwords and content. If you've
installed third-party software that has a remote administration
component, change the default administrative user names and
passwords. Change the default administrative URL as well, if
possible. Running administrative tools on a different web server than
the public web server that the administrative tool administrates can
be a good idea as well.
10. Web and Application Server Misconfiguration
Keep on top of PHP patches and security problems by subscribing to
the php-announce mailing list. Stay away from the automatic
PHP source display handler (AddType
application/x-httpd-php-source .phps ), since it lets attackers
look at your code. Of the two sample php.ini files
distributed with PHP ( php.ini-dist and
php.ini-recommended ), use
php.ini-recommended as a base for your site
configuration.
See Also:
|