Whether you're planning the development of a brand new application or trying to prevent legacy code from causing a costly data breach, if you're going to be writing PHP, where should you begin? That is the question we will attempt to answer, in detail.
The Easy Solution: Hire Security Consultants
Most people don't have the free time to teach themselves to become a security expert, especially if they have a business to run or ten thousand lines of code to write and test before next Tuesday's launch. There's a lot of information to take in, and by the time you feel like you've caught up, the goalposts have already moved.
If this sounds like you, you may want to hire a security consultant (or team of consultants) to manage the complexity of your software and reduce the risk to your business. A good security consultant can not only identify the most dangerous vulnerabilities and recommend (and even implement) solutions for them, but they will do so while working with your time and budgetary constraints.
What if I Don't Know Who to Turn to?
Paragon Initiative Enterprises offers application security, code auditing, and web development services. Send us an email and tell us where you are today and were you'd like to be tomorrow, and we'll share our insight on how to get there.
How to Develop More Secure PHP Applications
There are two primary causes for the unintentional creation of insecure web applications, regardless of the language being used:
- A lack of knowledge about security
- Bad development habits
Developers who don't know about the risks involved with writing a widget a certain way are unlikely to make the secure choice. Thanks to the work of MITRE and OWASP, the most common vulnerabilities (and their consequences) are widely known and accessible. However, when teams are under pressure to meet a tight deadline, bad habits and insecure development practices may still emerge.
The cure for a lack of knowledge about security is, of course, to acquire more knowledge about security. Education is the only effective long-term security strategy. Any company that is not educating their junior developers about web application security and common vulnerabilities does them a great disservice. (Our application security reading list on Github is a great place to start.)
But what about bad development habits? There isn't an immediately obvious and effective solution available, like how a lack of knowledge can be solved by acquiring knowledge. In our opinion, the only effective cure for bad development habits is to engineer the tools, libraries, and frameworks that developers use to be secure by default. If it's easier to do the secure thing than it is to do something risky, when placed under stress and hard deadlines, developers will be less likely to opt for increasing risk.
Understanding and Preventing Vulnerabilities
If you're new to application security and haven't read A Gentle Introduction to Application Security, we recommend it. The main take-away is four rules to keep in mind when writing software that will prevent most security vulnerabilities.
- Prevent data from corrupting the instructions that operate on it.
- Be explicit and comprehensive with your application logic.
- Keep your software up to date and don't rely on abandoned components.
- Don't write your own cryptography.
With these four points in mind, the next step is to map the possible interactions of data within our application. For a typical line-of-business CRUD app, we might have a diagram that looks like this (note: this doesn't consume any external APIs, or else the diagram would quickly become far more complicated):
Keep in mind, this is an incredibly simplified view of a web application. We aren't including operating systems, network devices, or communication protocols. To clarify:
- Your Code is the code you're directly responsible for. Models, controllers, views, cron jobs, etc.
- External Code is anything you're not directly responsible for. This might include libraries (e.g. defuse/php-encryption) or utilities (e.g. https://github.com/composer/composer).
Someone attempting to break into your system will mostly be interested in these pathways (highlighted in green):
- Any combination of pathways that can lead to a corrupted database query (i.e. SQL injection)
- Any way to trick your application into misusing external code (e.g. abusing naive file system operations)
- Any pathway that results in client-side code execution (e.g. cross-site scripting and cross-site request forgery)
Consequently, these are also where you should focus your application hardening efforts, with a couple of caveats. You typically only have control over your code, and it's usually not your job to look under the hood and fix vulnerabilities in external code. This is a double-edged sword.
Upside: If external code leads to a compromise, e.g. because of a zero-day vulnerability, you're not directly responsible for it.
Downside: You probably can't negotiate for the time to review it for possible vulnerabilities anyway.
So what can you do to keep your application safe?
At the very least, keep all of your software up to date (which takes care of point 3 on our list of 4 things to always keep in mind) and hope you're never hit with a zero-day exploit. Since zero-days are extremely rarely used, this is actually an effective way to prevent most attacks, since you're unlikely to be targeted by one.
"Keep everything up to date" also applies to:
- Your operating system
- Your web server software
- Your database software
- PHP itself
- The framework you're using
- Any and all external libraries
Great, now let's focus on what a typical PHP developer actually has control over:
Focal Points for PHP Developers
Without swapping your PHP programmer hat for a system administration or network engineer role, your application security efforts will mostly be focused on:
- Communication between your code and the database. We've previously covered how to prevent SQL injections in PHP: Use prepared statements where you can, use a very strict whitelist where you can't.
- Communication between your code and the framework, which is usually the gateway to the web browser. Your goal in this interaction is the prevention of cross-site scripting exploits: Properly escape any information you serve the user, in a contextually reasonable fashion. If you use a template engine (e.g. Twig), it should provide a quick and convenient method for doing this.
- Communication between your code and any external code. The specifics for how you secure this interaction depends entirely on what the external code is, what it does, and how it's meant to be used. You're most likely to run into confused deputy problems here, where input validation and explicit application logic are your most effective mitigation strategies.
Finally, all communication between your server and the end-user can only be secure if you're using HTTPS. We previously covered this in our post about secure PHP sessions and our white-paper about secure PHP encryption.
What About the Other Arrows in the Chart?
Great question. Here are some other great questions:
- How do you secure the way the framework interacts with the database? Or external code? Or the end user's web browser?
- How can you be sure that the external code doesn't leave your application wide-open?
- What if your web server software is remotely exploitable?
- What if the PHP SAPI for your web server isn't secure?
- What if the PHP interpreter, or one of the core extensions your application uses, contains a vulnerability?
- What about your server's operating system?
The list goes on. At the end of the day, there are two paths you can take:
- Secure what you can with the limited time you have, keep everything else up to date.
- Become a security expert, and give other people the answer to at least one of these questions they don't have time for.
While we do anticipate that most people will prefer the first option, the second is also an excellent choice.
What Happens If My Website Gets Compromised Despite My Best Efforts?
There are a few things you can do, proactively, to limit the damage of being "hacked." Most of this is common wisdom to information security experts.
- Store as little sensitive information as you can, to protect your customers.
- Implement secure user authentication. Most importantly, use a proper password storage algorithm.
- Keep regular offline backups of all your code and data so you can recover quickly.
The odds are usually stacked against you being able to identify how the attacker got their foot in the door, unless you happen to have an enormous amount of computer forensics and incident response experience. If you ask the general public, they'll probably point to some common problem, such as a weak administrator account password or a vulnerable WordPress plugin rather than offer any relevant insight.
The most important thing to do is to notify your customers about the breach as soon as you possibly can, with as much detail as you can afford to provide, and as close to zero unwarranted speculation as possible.
Often, the hardest thing to do, should a security breach ever happen, is to learn to move forward. For both the company and its customers. If you take security seriously (and while every company will say it does in their breach notification press releases, we mean if you truly take security seriously), you might never have to endure a data breach. Be sure that you don't get complacent, or you might overlook something that an attacker won't.
For another perspective in more general terms, Defuse Security's article on web application security is a must read.