PHP is one of the most used web scripting languages on the web. As of 2013, 240 million websites run PHP which makes it an ideal target for an attacker. In 2013, 9% of all vulnerabilities listed by the National Vulnerability Database were linked to PHP, historically, about 30% of all vulnerabilities listed since 1996 in this database are linked to PHP.
In this post we are going to discuss some best practices in security for PHP projects. There are two main ways to secure your PHP projects. First, and this may sound obvious, is to: Write secure codes. And the second and again, probably just as obvious sounding is to: Secure your configuration. I’ll caution you to not be fooled by how easy this sounds since PHP, as a language, has changed over the years and continues to evolve with regards to features, speed and security.
Having said that, this doesn’t mean that you’re going to have to constantly maneuver these changes in impossible ways. Lucky for us it is possible and preferable to use many of the widely available PHP frameworks that make our jobs easier. Most frameworks have already taken into consideration and implemented security by design and ensure protection against some of the more common security issues. In this post I’ll go over these three common security vulnerabilities in more detail so you have a better idea of what you’re up against:
- Cross Site Scripting (XSS)
- Cross Site Request Forgery (CSRF)
- SQLi among other issues.
Safeguarding against XSS can be as simple as validating everything that comes from your users or more plainly put: Don’t trust user input. If you read my last post you should remember how often I emphasized this point so now let’s take a look at this example together:
<?php$name = $_GET['name'];echo "Welcome $name<br>";?>
Here value of $name will get reflected on the page, if it has value “Manish” from
htmlspecialchars() is used to convert special characters into HTML entities.
<?php$name = htmlspecialchars($_GET['name']);echo "Welcome $name<br>";?>
The above code will validate input for special characters (<,>,\,/ ). I don’t see a better way than simply and consistently validating everything, but do let me know if you do.
Fun Fact: Did you know? On October 4, 2005, within just 20 hours, more than a million MySpace users were affected because of XSS (Samy’s worm) which made it the fastest spreading virus of all time!
Cross Site Request Forgery or CSRF is another major issue with PHP projects, in this attack the user is forced to execute unwanted actions (like send money, change email) in applications in which the user is currently authenticated.
Suppose you are logged in at xyz.com and “xyz.com/send.php?send_amount=100&send_to=123” is used to send $100 to a user with user ID 123. What if the attacker was able to make you click on a link by sending it to your Facebook chat or email, landing you on a page containing the following code:
As soon as you click the the link, the page will try to load image and make a request to the link in image tag. If you are authenticated to xyz.com, it will send $100000 to attacker’s ID 321.
CSRF is equally as easy with POST and GET requests. Prevent it by using a token with every request that validates on the server side. Do this especially for requests that make important changes, like change of email, request money transfer, etc.
SQL injection (SQLi) is a technique where an attacker creates or alters existing SQL commands to override valuable ones, expose hidden data, or even to execute dangerous system level commands on the database host. This is accomplished by the application taking user input and combining it with static parameters to build an SQL query. It can also be seen as a type of injection attack.
SQL Injection could be executed with something as simple as setting the password field to “password’ OR 1=1”, and query will look like
SELECT id FROM users WHERE username=’username’ AND password=’password’ OR 1=1’
Since, 1=1 is always true it can lead to authentication bypass. Using PDO or MySQli or passing database query through mysql_real_escape_string function can protect applications from SQL injection.
Caution should be exercised with session implementations as well. You could for example, invalidate a session whenever a violation occurs (ie. 2 IPs in same session), establish an inactivity logout, don’t expose session ID, don’t make session ID obvious/easy to guess, prevent against session fixation.
In addition to the PHP vulnerabilities we just went over above (XSS, CSRF and SQLi), I also suggest being careful with error handling. Internal exception handling can leak valuable information such as stack traces, database dumps, and error codes; providing hackers insight on potential exploitable flaws and vulnerabilities. Hide .php from the URLs and don’t expose PHP versions in the response header. Simply set expose_php to OFF in your php.ini file.
At Synapse we provide free security audits including the above listed PHP vulnerabilities as part of our on boarding process for new platforms and while maintaining existing customer accounts. We do this because it’s the right thing to do -- not only for your platform, but also for the protection of end-user data. While this does not guarantee 100% security, it does prevent many commonly identified security vulnerabilities. If you are one of our customers and have questions about your security audit, don’t hesitate to reach out to us.