Writing Secure PHP Applications

Download Report

Transcript Writing Secure PHP Applications

Writing Secure PHP Applications
How things can go wrong?
How to prevent the disaster?
Never, ever, trust user inputs
Input Validation
 Always use server side validation as client side (javascript)




validation can easily be bypassed
Use white-listed values
Use built-in escape functions
Validate for correct data types, like numbers
Don’t expect the return value from selections, radio buttons
or check boxes of a form to be the ones you mentioned. So,
always revalidate.
PHP Error Messages
 Great tool for both developer and hacker.
 Can reveal server software and directory structure, even database




login information.
Need to set error_reporting to 0 using php.ini or .htaccess file in
production server.
Should have separate .htaccess files for development and
production servers.
Use proper error handlers when necessary (instead of just
showing the error message and die()ing )
Further Reading :
http://perishablepress.com/press/2008/01/14/advanced-phperror-handling-via-htaccess/
Bad Features of PHP
Register Globals
 Consider the following code test.php
if ($password == "my_password") {
$authorized = 1;
}
if ($authorized == 1) {
echo "Lots of important stuff.";
}
 test.php?authorized=1 will produce “Lots of important stuff.”
 To disable register_globals using .htaccess file –
php_flag register_globals 0
 To disable register_globals using php.ini –
register_globals = Off
Bad Features of PHP
Magic Quotes
 Originally introduced to save programmers the trouble of
using addslashes()
 Major problems associated with it is –
a. When both magic quotes and addslashes() are used, you
end up with multiple slashes being added, causing errors
b. If you think magic quotes is turned on, but actually it is
not, then inputs go unchecked.
c. It only escapes double and single quote, but there are other
database-specific characters that need to be escaped
Bad Features of PHP
Magic Quotes
 Disabling using .htaccess –
php_flag magic_quotes_gpc 0
php_flag magic_quotes_runtime 0
 Disabling using php.ini –
magic_quotes_gpc = Off
magic_quotes_runtime = Off
magic_quotes_sybase = Off
SQL Injection
 Most common and most destructive security hazard
 Lets see the common way to check username and password entered into a form
–
$check = mysql_query("SELECT Username, Password, UserLevel FROM Users
WHERE Username = '".$_POST['username']."' and Password =
'".$_POST['password']."'");
 If we enter the following in the “username” input box and submit ' OR 1=1 #
 The query that is going to be executed will now look like this –
SELECT Username, Password FROM Users WHERE Username = '' OR 1=1 #' and
Password = ''
 As you can see, this query will return all the users from the database and as
generally first user on a user table is the admin, the hacker will easily gain
admin privilege.
 We need to either use mysql_real_escape_string() on all database inputs (not
just on string types) or use mysqli extension.
File Manipulation
 Some sites currently running on the web today have URLs that
look like this:
index.php?page=contactus.html
 The user can very easily change the "contactus.html" bit to
anything they like. For example,
index.php?page=.htpasswd
 By changing the URL, on some systems, to reference a file on
another server, they could even run PHP that they have written on
your site.
 When users download a file from your server, if the file name
depends on user input, he can easily manipulate it to download
system files by giving inputs like – “../../../etc/passwd”
File Manipulation
 To prevent remote and system files inclusion, make these changes
in your php.ini file –
1. Correctly set “open_basedir”
2. Set “allow_url_fopen” to Off
Always validate file names to make sure only valid characters are
included –

function isValidFileName($file) {
/* don't allow .. and allow any "word" character */
return preg_match('/^(((?:\.)(?!\.))|\w)+$/', $file);
}
 Use database and hidden, generated file names if possible for file
downloads.
Using Defaults
 MySQL uses default username of “root” and blank password
 SQL Server uses “sa” as default user with a blank password
 Hackers will first try to use the default username, password
combination everywhere – be it a MySQL server or CMS
like Wordpress, Joomla or Drupal.
 Make sure first thing you do after installing any software on
server is to change default username, passwords.
 Also, create separate users other than “root” with appropriate
permissions on MySQL.
Leaving Installation Files Online
 Many PHP programs come with installation files. Many of
these are self-deleting once run, and many applications will
refuse to run until you delete the installation files.
 Many however, will not pay the blindest bit of attention if the
install files are still online. If they are still online, they may
still be usable, and someone may be able to use them to
overwrite your entire site.
Predictability
 If a hacker wants to gain admin access of your site, first
location they will try to look into may be http://www.yoursite.com/admin/
 Make sure your admin area is not predictable. Use something
like –
http://www.yoursite.com/jsfh8sfsifuhsi8392/
 Same goes with username and password. Don’t use an
username ‘admin’ or ‘administrator’. Pick something unusual
 Use a combination of lower and upper case letters along with
digits to prevent dictionary attack.
File Systems
 Always disable directory listing by placing a ‘index.html’ file
in every folder.You can also disable by using .htaccess or
httpd.conf file, but using ‘index.html’ will make sure you’re
protected even if your server settings are changed.
 Don’t place common files in a directory like
‘www.mywebsite.com/includes/’. Use something out of
web root for that and give it an unusual name.
 Don’t give a file the extension ‘.inc’ as it is usually rendered
as text and can reveal the whole source code (and maybe
database login information too). If you must use ‘.inc’, use
‘.inc.php’ instead as it will be rendered as php file.
Session Hijacking
 By default, session information in PHP is written to a
temporary directory.The file itself contains the information
in a fairly readable format.
 As the file has to be readable and writable by the Web server
user, the session files can create a major problem for anyone
on a shared server. Someone other than you can write a
script that reads these files so they can try to get values out of
the session.
 Encrypt everything that you put into session. It is not
completely safe though.
 Store session data in a different place, like a database.
Storing Passwords
 Do not store password as plain text
 Do not try to invent your own password security
 Do not encrypt passwords as they are reversible. Security
through obscurity is not sufficient.
 Do not use MD5 – though this cryptographic hashing
function is irreversible , it is quite easy to make a list of
millions of hashed passwords (a rainbow table) and compare
the hashes to find the original passwords. MD5 is also prone
to brute forcing (trying out all combinations with an
automated script) because of collisions.
Storing Passwords
 Do not use a single site-wide salt. A salt is a string that is hashed
together with a password so that most rainbow tables
(or dictionary attacks) won’t work.
$password = 'swordfish';
$salt = 'something random';
$hash = md5($salt . $password);//Value: db4968a3db5f6ed2f60073c747bb4fb5
 Use a cryptographically strong hashing function like SHA-1 or
even SHA-256 (using PHP’s hash() function).
 Use a long and random salt for each password.
 Use a slow hashing algorithm to make brute force attacks
near impossible.
 Regenerate the hash every time a users logs in.
Storing Passwords
 Code to create the hash and salt
$username = 'Admin';
$password = 'gf45_gdf#4hg';
// Create a 256 bit (64 characters) long random salt
// Let's add 'something random' and the username
// to the salt as well for added security
$salt = hash('sha256', uniqid(mt_rand(), true) . 'something
random' . strtolower($username));
// Prefix the password with the salt
$hash = $salt . $password;
// Hash the salted password a bunch of times
for ( $i = 0; $i < 100000; $i ++ ) { $hash = hash('sha256',
$hash); }
// Prefix the hash with the salt so we can find it back later
$hash = $salt . $hash;
Storing Passwords
 Code to validate password
$username = 'Admin';
$password = 'gf45_gdf#4hg';
$sql = ' SELECT `hash` FROM `users` WHERE `username` = "' .
mysql_real_escape_string($username) . '" LIMIT 1 ;';
$r = mysql_fetch_assoc(mysql_query($sql));
// The first 64 characters of the hash is the salt
$salt = substr($r['hash'], 0, 64);
$hash = $salt . $password;
// Hash the password as we did before
for ( $i = 0; $i < 100000; $i ++ ) {
$hash = hash('sha256', $hash);
}
$hash = $salt . $hash;
if ( $hash == $r['hash'] ) {
// Ok!
}
Login Systems
 You should add a turing test to your admin login page. Have a randomly
generated series of letters and numbers on the page that the user must
enter to login. Make sure this series changes each time the user tries to
login, that it is an image (rather than simple text), and that it cannot be
identified by an optical character recognition script.
 Add in a simple counter. If you detect a certain number of failed logins
in a row, disable logging in to the administration area until it is
reactivated by someone responsible. If you only allow each potential
attacker a small number of attempts to guess a password, they will have
to be very lucky indeed to gain access to the protected area. This might
be inconvenient for authentic users, however is usually a price worth
paying.
 Make sure you track IP addresses of both those users who successfully
login and those who don't. If you spot repeated attempts from a single
IP address to access the site, you may consider blocking access from that
IP address altogether.
Powerful Commands
 PHP contains a variety of commands with access to the operating
system of the server, and that can interact with other programs.
Unless you need access to these specific commands, it is highly
recommended that you disable them entirely.
 For example, the eval() function allows you to treat a string as
PHP code and execute it. This can be a useful tool on occasion.
However, if using the eval() function on any input from the user,
the user could cause all sorts of problems.You could be, without
careful input validation, giving the user free reign to execute
whatever commands he or she wants. For example –
eval("shell_exec(\"rm -rf {$_SERVER['DOCUMENT_ROOT']}\");");
Powerful Commands
 The php.ini file gives you a way to completely disable certain
functions in PHP - "disable_functions". This directive of the
php.ini file takes a comma-separated list of function names,
and will completely disable these in PHP. Commonly
disabled functions
include ini_set(), exec(),fopen(), popen(), passthru(), readfil
e(), file(), shell_exec() and system().
 It may be (it usually is) worth enabling safe_mode on your
server. This instructs PHP to limit the use of functions and
operators that can be used to cause problems. If it is possible
to enable safe_mode and still have your scripts function, it is
usually best to do so.
Cross-Site Scripting (XSS)
 Unlike SQL Injection, which relies on the use of delimiters in
user-input text to take control of database queries, code
injection relies on mistakes in the treatment of text before it
is output.
 Let's say you've not added a limit to username lengths.
Someone could, if they wanted, create a user with the
following username:
username<script type="text/javascript" src="http://www.website.com/malicious.js"></script>
 Anyone that then views a page with that username on it will see a
normal username, but a JavaScript has been loaded from another
site invisibly to the user.
Cross-Site Scripting (XSS)
 It allows attackers to add keyloggers, tracking scripts or porn




banners on your site, or just stop your site working
altogether.
It can also used for cookie hijacking so that a real user can be
faked.
Always use htmlentities() function to output user-generated
texts.
Limit the character set that can used for a particular text type
Disallow HTML input if possible. If that is not an option,
only allow limited HTML tags
Cross-Site Request Forgery (CSRF)
 CSRF attacks are exploits that take advantage of user privileges to
carry out an attack. In a CSRF attack, your users can easily
become unsuspecting accomplices. For example –
<img src="http://www.example.com/processSomething?id=123456789" />
 CSRF attacks are often in the form of <img> tags because the
browser unwittingly calls the URL to get the image. However, the
image source could just as easily be the URL of a page on the same
site that does some processing based on the parameters passed into
it. When this <img> tag is placed with an XSS attack — which
are the most common of the documented attacks — users can
easily do something with their credentials without knowing it —
thus, the forgery.
Cross-Site Request Forgery (CSRF)
 Never let the user do anything with a GET request - always use




POST.
Confirm actions before performing them with a confirmation
dialog on a separate page - and make sure both the original action
button or link and the confirmation were clicked.
Add a randomly generated token to forms and verify its presence
when a request is made.
Time-out sessions with a short timespan (think minutes, not
hours). Encourage the user to log out when they've finished.
Check the HTTP_REFERER header (it can be hidden, but is still
worth checking as if it is a different domain to that expected it is
definitely a CSRF request).
References
 How to store passwords safely with PHP and MySQL –
http://elbertf.com/2010/01/store-passwords-safely-with-php-andmysql/
 Writing secure PHP series –
http://www.addedbytes.com/writing-secure-php/writing-secure-php-1/
http://www.addedbytes.com/writing-secure-php/writing-secure-php-2/
http://www.addedbytes.com/writing-secure-php/writing-secure-php-3/
http://www.addedbytes.com/writing-secure-php/writing-secure-php-4/
 Seven habits for writing secure PHP applications by IBM http://www.ibm.com/developerworks/opensource/library/os-phpsecure-apps/index.html
 5 Helpful Tips for Creating Secure PHP Applications http://net.tutsplus.com/tutorials/php/5-helpful-tips-for-creatingsecure-php-applications/
Finally, Be Completely
and Utterly Paranoid
Thank you