Secure PHP Programming for Web Developers
Security in PHP is the same as any server side programming language, they are all vulnerable to the same attacks.
PHP has a history of being vulnerable mainly because of its popularity.
1) More non-security aware developers use PHP then any other language, so there code has flaws almost 100% of the time.
2) There are more sites written in PHP then any other server side language, thus more chances to find security holes amongst so many.
PHP has had a rep of having security problems in the PHP core itself, but this has improved greatly. Much of which can be attributed to the Hardened-PHP project.
http://www.hardened-php.net/suhosin/
If you are using a shared host, ask if they have PHP4 with the suhosin patch or PHP5 or higher. I’m not sure if PHP5 still needs Suhosin but it seems many large sites aren’t using the two together so I believe PHP5 has a better security then PHP4 natively.
As a developer I think there are just about 4 or so main security vulnerabilities to keep in mind when coding.
1) XSS (Cross Site Scripting)
This is the most common vulnerability in any website. It is estimated that around 70% of websites have an XSS vulenerability.
http://en.wikipedia.org/wiki/Cross-site_scripting
A simple example in PHP:
<?php echo $_GET['username']; ?>
What happens is the PHP echo’s a variable passed in from HTTP (in this case a GET parameter). If a user typed in the browser URL:
site.com/example.php?username=<script>alert('document.cookie')</script>
They would see the cookies saved for their session. An attacker can make a user click a link that will also retrieve these cookies from JavaScript, and send it to them - without the user knowing.
To prevent it:
<?php echo htmlentities($_GET['username'], ENT_QUOTES, 'UTF-8'); ?>[
This will turn any HTML into HTML entities. You also have to specify the encoding you used for the page (in this case UTF-8). The reason is so PHP codes not mangle the character encoding, which can also result in XSS.
I must say here, that you should never use your own PHP filtering functions for HTML, or any other "cleansing" of user input. Most likely you will miss something that an attacker will use.
2) XSRF - Cross Site Request Forgery
This is similar to XSS and just as common or maybe even more common. It is when a website fails to protect it's users from being used by 3rd parties without their knowledge.
http://en.wikipedia.org/wiki/Cross-site_request_forgery
And example of this in PHP is a simple comment form.
<form action="submit.php"> <textarea name="comment"> <input type="submit" value="Post Comment" /> </form>
Imagine the comment form is only available for logged in users. Now an attacker can just send an already logged in user the URL:
site.com/submit.php?comment=I hacked you&submit=Post Comment
So when the logged in user clicks on that link, they have posted the comment without knowing. This can even be done in a hidden frame, so the user never see's it.
So the attacker is using the user's already authenticated session (privileges) to do his/her bidding.
Preventing XSRF:
<form action="submit.php"> <textarea name="comment"> <input type="submit" value="Post Comment" /> <input type="key" value="some_random_value" /> </form>
Notice the new <input /> called "key". It will contain a random value remembered by PHP. This random value should be saved, and be unique for every form that is sensitive.
This way, the attacker would not be able to make the user post something on their behalf, since they don't know the value of "key".
(This only works if you don't have an XSS vulnerability of the page itself, as that can lead to the attacker knowing what the value of "key" is)
3) SQL injection
SQL injection is when an attacker manages to manipulate any SQL database queries in your website in a way you didn't intend.
http://en.wikipedia.org/wiki/SQL_injection
Example:
<?php $query = "SELECT * FROM users where password = '".$_GET['password']."'"; $result = mysql_query($query); ?>
Because the $_GET['password'] can be anything the attacker wishes to put in the URL, they could craft a URL like:
site.com/login.php?username=joe&password=nothing' or 1
Notice the ‘ in the value for the parameter “password”
This will make your sql query:
SELECT * FROM users where password = 'nothing' or 1
This would make it return the first user instead of the user with password = “nothing” since “or 1″ is always true.
Preventing SQL injection:
< ?php $query = "SELECT * FROM users where password = '".mysql_real_escape_string($_GET['password'])."'"; $result = mysql_query($query); ?>
the function mysql_real_escape_string() will prevent any SQL injection by escaping any character that would otherwise terminate the string.
4) Remote File inclusion
Remote file inclusion is when an attacker can include remote file into your PHP code. This is the most dangerous attack, as it allows the attacker to execute arbitrary code on your PHP server.
http://en.wikipedia.org/wiki/Remote_File_Inclusion
eg:
<?php
include('/pages/'.$_GET['page'].'.php');
?>
With this code the developer is hoping to have a URL such as:
site.com/pages.php?page=home
And this would include the file:
/pages/home.php
However, any attacker can now place a URL such as:
site.com/pages.php?page=../../passwords.txt
And it would reveal the contents of the file passwords.txt
Or they could use it to include a remove file from their server, if the URL wrappers are enabled for file includes (which is common).
It is best not to have any user input in the files to include. However, if you think it is beneficial to your PHP website, then make sure you have a predefined list of files that can be included.
For example:
<?php
if (in_array($_GET['page'], array('home', 'contact', 'links', 'about')) {
include('/pages/'.$_GET['page'].'.php');
}
?>
With these in mind, you should be able to keep your PHP site secure from most attacks. Now in one paragraph:
When ever you write a PHP page, make sure all input from users (HTTP) is escaped according to the the following rules, HTML just be entity encoded with htmlentities(), XML with htmlspecialchars(), SQL must be escaped by mysql_real_escape_string(). User input should not be used for file inclusions at all, but if you do, then make sure it is from a predefined list of possible files. All forms must contain a secure, random, key that is used to authenticate it only once so that there can be no subsequent posts of the same form, or posts from other sources.
That actually covered all the points above. Can you see how simple it is? It is just keeping those in mind at all times while coding that is the hard part.
Related posts:
- Security of Fiji’s Major Company Websites Taking a look at the largest websites on the com.fj domain (Fiji domains) I was surprised that 8 out of...
- Secure password hashing and storage in PHP Everyone knows you should never store passwords as plain text, right? Recently I’ve come across a lot of bad advice...
- Client Side Application development for Web Developers Coming from a web development background, you would probably find using either Adobe AIR, or XUL the simplest to understand...
- Google AJAX Language API with PHP I had noticed some time ago that Google had released an API for their language translation service. A recent forum...
Another good article on securing your PHP code is:
http://www.addedbytes.com/php/writing-secure-php/
It also mentions register_globals which I forgot about here. Register globals has been deprecated however, and removed as of PHP6.0.
Thanks for sharing this great article on how Secure PHP Programming for Web Developers.
This is exactly what I was looking for, simple and even for me possible to understand
Nice tutorial. I like this