5 More PHP Security Vulnerabilities
In a previous article, I talked about some common security vulnerabilities that can affect your PHP web application. But there are other things besides those ten (okay, seven) attacks to think about when you’re developing. And so, this article offers a compendium of miscellaneous things that are security related; things you should do, things you shouldn’t do, things that other people might try to do, whatever it takes to make an article long enough for my editor to be satisfied with it.
PHP’s Security Profile
Sometimes when you’re hanging around in a bar you hear people (not the regulars, of course, but folks who just wander in) insinuating that PHP is not a very secure language. In the past, there were some legitimate grounds for such feelings.
Most of the historical problems can be traced to poor default settings. A good example is register globals which was deprecated in 5.3 and then removed entirely in 5.4. There’s no sense talking about it; it’s no longer an issue, but let’s just say that it gave people the opportunity to write potentially insecure code. Insecurities that were a result of
php.ini settings have now been mostly neutralized or else are better publicized.
One thing that sometimes gets in PHP’s way, but which is also one of its strengths, is its flexibility. Not everything has to be just such and so for a PHP app to run. You can have loose ends and the code will still work. Unfortunately, loose ends are what keep hackers in business, and so writing secure code often starts with starting with tight, technically correct code.
Filter Input Data
It sounds so simple: inspect data that is entered on your web pages and make sure it is not dangerous. Like who wouldn’t do that, man? The answer is a surprising number of people.
There is a certain school of thought that argues that anyone who is a computer science major should be subjected to a semester’s worth of scams. You know, people coming up to them and offering to give then $100 if they can just advance them the $20 required to get their “check” cashed. Or emails from a lawyer somewhere telling them that a relative they have never heard of has just left them 25-million pounds and all they need to do to claim it is to send their bank information. The goal, of course, is to teach computer people that the world is not a friendly place. We set up a 256-character area for the user to enter comments and some people will use that space to enter SQL commands in an attempt to do an SQL injection attack. Is there no honor anymore?
If you set up a page that allows any type of free form entry on it, you need to review that input carefully and make sure that you keep anything bad from being entered. Use the function
filter_input() to ensure that bad people don’t put bad things in your forms (or even in your files if your input comes with a file transfer or some other I/O operation).
Fortunately, there are already two great articles on SitePoint related to that. The first is Input Validation Using Filter Functions by Toby Osbourn, and the second is ClamAV as a Validation Filter in Zend Framework by Matthew Setter. Between these two articles you should be able to get the lowdown on the downlow about this potential problem.
You might want error messages to appear on your screen during development to give you a hint when something goes wrong with your script. But when you are in production, do you really want this to happen? Every bit of information is life food for a hacker, and even information about your failures may be helpful to those whose only desire is to destroy your site. Consequently, you should never display errors on the screen when you are in production.
How do you control this? Thank goodness the
php.ini file is there because it is for just such needs as this that it exists. In fact, there are four flags that can be set in
php.ini to configure error reporting just as you like.
error_reporting– this flag decides whether you want to know about errors or not. Obviously, you want to know about everything, so the sensible thing is to set this to
E_ALLin both production and test.
display_errors– this flag indicates whether you want the error messages to be displayed on the screen or not. Set this to “on” during development and “off” for production. There’s no sense in giving hackers any more info than necessary; let them do the heavy lifting.
log_errors– indicates whether errors should be logged to a log file. Obviously, you would want this on for production.
error_log– indicates the path to the file where the error messages will be written to. Obviously, for this to take effect, we need to have
With these flags set, you can get all of the information you need during testing while yet protecting yourself in production.
In the previous article I talked about session hijacking, but there is another type of attack that can happen to your sessions: session fixation. Fixation is where you are tricked into using a session ID provided by the hacker. How does this happen?
Generally session fixation occurs when you click on a link that contains a
PHPSESSID parameter that carries the session ID an attacker wants you to use. That link could take you to a form on which your identity is verified and now your identity is tied to the session ID the attacker has given you, allowing them to view any page in your site and access the data associated with that page.
Fortunately, preventing this is relatively easy. Start by checking out the following values in
session.use_cookies– controls the persistence of the session ID when cookies are used. It should be set to 1 or not set at all.
session.use_only_cookies– keeps the ID from being overridden by GET parameters and should be set to 1.
Session.use_trans_sid– makes PHP change the output so that the session ID in links, etc. will persist. This should be set to 0.
session.name– the name of the session parameter. Generally this is set to “PHPSESSID” and knowing that makes it a little easier for hackers. Change this to a more obscure value.
Also, a good rule of thumb to follow is to always perform a
session_regenerate_id() call just before the redirect to any request to authenticate the users. This will ensure that the session ID is not the one provided by the attacker and help protect you from this situation.
User Data Concerns
If your site makes use of user data in any way then you have additional problems you need to keep an eye out for. First and probably foremost you want to think about the data traffic to and from the browser and server. This is an easy target many times, especially with so many people working on public open wireless networks. You might want to consider using an SSL connection (HTTPS for example) on your web site for all of your transactions. Even encrypting the database connection that PHP establishes may not be out of the question depending on the nature of your configuration.
Another thing to be concerned with in this area is the ability of an attacker to steal passwords from your database. This is slightly outside of the scope of this article since it deals mostly with how to encrypt your passwords so that they can’t be easily recovered using rainbow tables or other attack methods. I suggest checking out the article Why You Should Use Bcrypt to Hash Stored Passwords by Callum Hopkins for more information.
Is this all? I mean if you do everything in both this and my previous article will your site be secure? Yeah, sure. And keep all your money in a paper bag and carry it with you at all times.
There are more ways to circumvent security than there are, well, than there are lots of other things. In the end, if you only do one thing, think suspiciously about ways that you could be vulnerable, and don’t trust any user input unless it is scrupulously scrubbed.
Yeah, I know that was two things. Do you get my point about not trusting people?
Image via Fotolia