james mckay dot net

because there are few things that are less logical than business logic
09
May

Avoiding password re-use is not that easy

Another wrong argument that occasionally comes up in favour of plain text passwords is that you shouldn’t be responsible for the fact that your users do stupid things, like re-using passwords. Unfortunately, it’s not that simple.

In the eighteen months since I started using KeePass to manage my online passwords, I’ve found that it involves a certain amount of friction. For starters, it’s less user-friendly. Rather than just typing your user name and password straight into your browser, you have to switch to the KeePass window, find your website, and then paste. There are shortcut keys and a search facility to make things easier, but it is a bit of a learning curve. Furthermore, when you register with a new site, you have to fiddle about with the password generator in order to create a new password, and on top of that, some websites have undocumented limitations or bugs in their password forms. One well known website that I use allows you to set passwords of any length, but limits you to 20 characters in the login screen, for example.

That’s a relatively minor complaint, of course. A much more serious difficulty is synchronising passwords between different devices, not all of which may support your password manager of choice. KeePass for the iPhone is not yet available outside the USA and Canada, for example. Third party password managers may not even be an option on certain other Internet-enabled devices such as the PlayStation, Internet TV, and so on. Then there are situations such as a friend’s computer when you don’t have your password database on you; Internet cafes and kiosks; and locked-down workstations on corporate networks.

Clearly, avoiding password reuse requires a certain amount of discipline, sacrifice, and technical know-how. Even many relatively tech-savvy users view it as one of those things that “I must get round to someday” — a bit like taking up exercise or flossing your teeth. So where does that leave your non-technical users?

The overwhelming majority of non-technical users are shockingly ignorant about even the most basic aspects of web use. A couple of years ago, Google interviewed passers-by in Times Square, New York, and found that more than ninety percent of the people they stopped didn’t even know the difference between a web browser and a search engine:

The upshot of all this is that as a data controller, it is totally unrealistic to expect your users not to re-use passwords. They shouldn’t re-use passwords, and they should use a password manager, and they should choose secure passwords, and you should warn them of the risks. But to many of your users, if you try to explain the risks to them and what to do about it, their eyes will just glaze over and they will say to you, “Oh, I’m not a computer person. That’s all too technical to me.” They will re-use passwords. In so doing, many of them will entrust you with the login details to their e-mail, Facebook, PayPal, and possibly even their bank accounts. They shouldn’t, but they do. And with that in mind, you have a responsibility to do everything in your power to protect those details.

29
Apr

Eight wrong reasons why you are storing passwords for clear text recovery

The recent data loss by Sony of seventy million PlayStation users’ personal details was a serious lapse. They have assured us that their users’ credit card details were encrypted, though Graham Cluley of Sophos has asked questions about exactly what kind of encryption they were using.

A more serious issue is that they admitted that users’ passwords were compromised. This can mean only one thing: they were storing passwords in a form that could be recovered to plain text. The press doesn’t tend to make as much noise about passwords as about credit cards, which is a pity, because passwords are at least as valuable to a fraudster, if not more, for the simple reason that the overwhelming majority of people re-use passwords on multiple websites, including high-value ones such as their e-mail and their bank.

It’s a sobering reminder to all of us web developers that we should not be implementing plain text password recovery, period. It is inexcusable. And, it could be argued, illegal in some jurisdictions.

It is inexcusable because it is a security compromise that is totally unnecessary. Yet it is sometimes mandated by pointy-haired bosses and clueless clients despite developers’ objections. There was a question on Stack Overflow a while ago asking how you can ethically approach storing passwords for later plain text retrieval. I replied that you can’t.

Here are some of the excuses that people make for storing passwords in plain text.

1. “My site is small and obscure, nobody is going to try hacking it.”

If you are thinking that way, I have bad news for you. Hackers love small, obscure websites precisely because their developers think exactly that, and they are consequently riddled with SQL injection vulnerabilities exposing plain text passwords. Sites like that are low hanging fruit to a malicious user.

Furthermore, hackers operate botnets that trawl the Internet probing every website they come across for security holes. Even the smallest, most obscure website should expect to be probed by malicious scanners weekly if not daily.

How small and obscure is “smallest and most obscure”? How about my own blog, circa December 2005? At the time, it had been going for only seven months, and since I was (a) a lot more reserved and introverted back then than I am now, and (b) a complete blogging newbie, I had kept a very low profile with it up to then. Only half a dozen or so of my close friends knew of its existence. I had even turned off the feature to ping Technorati and other blog aggregators. Yet there it was, on the receiving end of an SMTP injection probe.

Bottom line: if you are collecting user registrations, you are not small and obscure. Period.

2. “Users’ logins to my site are a low-value asset.”

No they are not.

No matter how much we nag them, how much we tell them to be careful, people will still re-use passwords. There are far too many people who, when you tell them they need to use KeePass or something similar, will just shrug and say to you, “Oh, that’s too complicated for me, I’m not a computer person.” They regard good password practices as a tinfoil hat, because, after all, you’re not Fort Knox.

Consequently, if your password database gets breached, your attackers have not just got away with your users’ logins on your site. They have got away with your users’ logins on Facebook, eBay, PayPal, GMail, and their bank accounts. Give an identity thief access to your clients’ e-mail, and you have given them access to their entire life.

Far from being a low-value asset, your users’ logins are the most valuable asset that you are dealing with. They are arguably even more valuable than their credit card numbers.

3. “A password reset is harder from a usability perspective than a password reminder.”

No it is not. Not if you implement it correctly.

People only think that a password reset is harder to use because they think you have to e-mail your users a new password, and it usually ends up looking like transmission line noise. But there is a better alternative.

E-mail your users a one-time, time-limited link to a page on your website that lets them choose a new password then automatically logs them in once they’ve done so. This is actually easier to use than either a password reset or a password reminder, since one click from their e-mail client opens their web browser straight to the “choose a new password” page.

If you want to see this in action, this is how Amazon does it. So does Twitter. So does any other website that takes security seriously these days.

4. “As an administrator, I need to be able to log on as any other user, so that I can troubleshoot if need be.”

Regardless of whether this user story is a good idea or not (it might be controversial if, for instance, you are Facebook and word of it gets out), you do not need to know the other user’s password in order to facilitate it.

All you need is a button on your user administration page that allows an already authenticated superuser to switch identity to the user in question with a single click of the mouse. It’s exactly the same principle as the Unix su command.

Any web developer who isn’t able to implement this is, quite frankly, incompetent.

5. “Two-way encryption is sufficient.”

No it is not.

If you want to allow your users to recover their passwords through your web front end, your web front end has to be able to decrypt them. If your end users can decrypt their passwords, there is always the possibility that a malicious user can do likewise. If your code has a bug in it that lets a malicious user view passwords to which they are not entitled, that would totally nullify the effect of the encryption. Furthermore, you would have to put both your public key and your private key on a public-facing web server, making it all the easier for an attacker to get hold of the means to decrypt your users’ passwords.

6. “But what about credit cards? You need two-way encryption for them, surely?”

Your users’ credit cards should not be recoverable to plain text by the web server either.

If you look at how Amazon stores your credit card information, you will see that they don’t display it back to you once you’ve typed it in, apart from the last four digits. Yet they need access to this information in order to bill you correctly. So how do they do it?

The answer is simple. The web server only has access to their public key. They put the private key (and their back-end administration system) on a completely different server in a completely different subnet, separated from their web servers by firewalls with strict security.

If you want to store credit card details for later processing, this is what you must do. If you can’t do so, you should use a third-party payment provider such as PayPal, send their credit card details to them using web services, and do not store them in your own database.

Despite this, this is still not as secure as a one-way salted hash, and there is still a chance that an attacker could steal your users’ credit card database and the private key. But in this case there is a limit to how
much security you can practically apply without rendering the system unusable. This limit does not apply to passwords, since clear text recovery, as we have seen, is completely unnecessary for passwords.

7. “You need to do a risk assessment before deciding what security is appropriate.”

This one came up on a Stack Overflow discussion a while ago and I just about hit the roof when I saw it.

For crying out loud people, this isn’t a hypothetical, theoretical scenario! It is a scenario that has happened in practice, over and over and over again. It is a scenario that is keeping seventy million PlayStation users awake at night at this very moment. The risks are well known and well documented. If your users’ passwords get compromised, hackers can take control not only of their login to your dinky little website, but also to Facebook, PayPal, their e-mail, their bank. You are exposing them to the risk of identity theft, which can get pretty nasty.

Besides, a risk assessment is only meaningful if you can demonstrate that there is a convincing business case for any security compromises that you have to make. And what compromises do you have to make in order to avoid sending plain text passwords? There aren’t any! I’ve explained above just why the perceived disadvantages are not disadvantages of the sort, and how recoverable passwords are totally unnecessary for a user-friendly, flexible authentication system.

8. “The client/my boss insists on it.”

The best way to approach this is to show them how Twitter and Amazon handle login recovery (“show, don’t tell”), build a prototype, and point to some real-world examples of where things went wrong — the 4chan/Christian dating website that I mentioned a couple of years back is as good an example as any.

If, in spite of this, and being advised that they are probably breaking the law in requiring plain text passwords, they still insist on having passwords recoverable to plain text, you are likely to have other problems with your client. The Daily WTF kind of problems.

If you end up in this kind of situation, sack your client. Or start looking for another job if you’re a permie. Now.

So are there any valid reasons why you can be storing passwords for clear text recovery?

Yes, there is one. And only one. It is this.

You have inherited a legacy application, written by someone else, that has so much bad design and technical debt that it is infeasible to migrate your passwords to an encrypted version.

If you end up in such a situation, get the code under source control before you do anything else, to cover your back if nothing else. Advise the client that they are storing passwords dangerously. Warn them of the implications. Propose an alternative, and quote for it. And recommend that they make it a priority.

16
Sep

If you are saving passwords in clear text, you are probably breaking the law

The Christian dating website that got hacked by 4chan back in August was a textbook illustration of why you should not store users’ passwords in plain text. Most of the users of the site had re-used their user names and passwords on Facebook and their e-mail accounts, which were compromised as a result, in many cases in extremely embarrassing ways.

Reading about this (and a similar event somewhat closer to home a week later) has got me thinking about the whole issue again. A couple of years ago, Mats Helander proposed on his blog that saving plain text passwords should be illegal. (Unfortunately he lost his domain name to squatters a few months later, but the post is still up in the Wayback Machine.) His post was in response to some of Jeff Atwood’s readers, who pointed out that many web developers have bosses and clients who insist on them storing passwords in clear text so that they can e-mail password reminders to their users. To be sure, you can try explaining to them that there are alternative approaches that don’t compromise usability, but if your boss is an “I’m not a computer person” type, or just doesn’t care, you might as well try to strike a match on jelly, or you may even find your job on the line. However, if you could tell your boss or clients that they were asking you to do something illegal, you’d be in a much stronger position to push back.

Now I am not a lawyer, but the other day, I took a close look at the Data Protection Act 1998, and if I understand it correctly, saving passwords in clear text is indeed illegal here in the UK.

The relevant part of the Act is Schedule 1, Part I, paragraph 7, which states the seventh of eight Data Protection Principles:

Appropriate technical and organisational measures shall be taken against unauthorised or unlawful processing of personal data and against accidental loss or destruction of, or damage to, personal data.

This is expanded on in Schedule 1, Part II, paragraphs 9-12, which tells us how to interpret this principle. Paragraph 9 in particular says:

9 Having regard to the state of technological development and the cost of implementing any measures, the measures must ensure a level of security appropriate to—

(a) the harm that might result from such unauthorised or unlawful processing or accidental loss, destruction or damage as are mentioned in the seventh principle, and

(b) the nature of the data to be protected.

It should be noted that these restrictions apply to “personal data” as well as to “sensitive personal data.”

As Mats argued, and I would reiterate, and the Christian dating website/4chan incident illustrates dramatically, losing people’s passwords has the potential for immense harm. Defacing Facebook profiles can cause serious embarrassment and possibly even wreck careers, but if the attacker then gets access to your e-mail account, they can obtain or request new passwords for even more sensitive websites such as your bank, your credit cards, and so on.

It seems obvious to me that storing plain text passwords in a database most certainly does not “ensure a level of security appropriate to the harm that might result from such unauthorised or unlawful processing or accidental loss” as required by the law. The state of technological development provides us with a much better solution — a one-way salted hash, which is computationally infeasible to reverse engineer — and since there are still perfectly adequate solutions to the login recovery problem, the cost of doing so is negligible.

I’d be interested to hear from anyone who specialises in the legal issues surrounding computer security whether my understanding of the Data Protection Act is correct here. Do you concur with my conclusions? Or do you think that the law need to be made more explicit on this matter?

14
Jan

The top 25 most dangerous programming errors

(Via BBC News and Coding Horror): The 2009 CWE/SANS Top 25 Most Dangerous Programming Errors is a list of the most significant programming errors that can lead to serious software vulnerabilities, published by the US National Security Agency. Everyone working with code in any capacity whatsoever, at any level, needs to know this stuff cold. Everyone who manages them needs to make sure that they do. And everyone who recruits them needs to ask about this stuff at interview time. There’s really no excuse for hiring people who think that it’s okay to construct SQL commands by smashing strings together willy-nilly with user input.

I was rather disappointed to see that it isn’t explicit enough on the issue of plain text passwords in your user database, nor is there any mention of the increasingly popular password anti-pattern of asking users for their Gmail passwords so you can import their contact list. Both of these are particularly insidious because in addition to being frighteningly dangerous from the point of view of identity theft and phishing, they are frequently demanded by bosses and clients who either don’t see why they should be a problem or are willing to take on the quite unacceptable risks that they introduce.

10
Jun

Easy login recovery without compromising security

I’ve noticed recently that some websites have a very elegant solution to the problem of login recovery. If you forget your password, rather than sending you an e-mail with either your existing password or a new one, they send you a link that you can click on, which takes you straight to a page that logs you in automatically and allows you to choose a new password.

This works particularly well because it fixes the problems of both the “password reset” and “password reminder” approaches. Password reminders are bad because they require you to store the users’ passwords in plain text in the database, but password resets are also bad because they are completely user-unfriendly.

Not long ago we deployed a website for a client that used the ASP.NET membership provider for authentication and generating passwords. Unfortunately, we had to change it, because the ASP.NET membership provider generates seriously ugly passwords that look like “aFi$#3-Il1=+2x{zZ14^” or something, prompting at least one user to send in an e-mail that said this:

I tried starting again from scratch and this time I was assigned a 21-character (!) password – the sort of thing you would expect to use if you were trying to get into Fort Knox … I find your site definitely “user-unfriendly”. What can I do?

This is why some teams settle for password reminders, even though they may be aware of the security risks. It’s also one thing that I dislike about the ASP.NET membership provider.

The login link approach gives you the best of both worlds and offers additional advantages on top of each. It bypasses both the login page and the process of navigating to the page that lets you change your password (which many users find confusing), making it much more user friendly than either. Certainly you won’t be asking your users to faff about copying and pasting “aFi$#3-Il1=+2x{zZ14^” from their e-mail client to the login page. Furthermore, because your password is not reset until you actually change it, your old one will continue to work if you manage to dig it out in the meantime. And from a security point of view, you can still store passwords as a salted hash in the database.

15
Nov

Password Reminders Considered Harmful

How does your website handle users who have forgotten their password?

Chances are, you ask for their e-mail address, look them up, extract their password from the database, and e-mail it to them. Nice and simple, and convenient for the end user, and easy to program.

Unfortunately, it is seriously and dangerously flawed.

Almost everyone re-uses login details across multiple web sites. It simply is not realistic to expect them to do otherwise. As a result, if an attacker manages to compromise your user database, they will be able to impersonate your users on potentially thousands of websites, including some that store their credit card details.

Never think you are immune to this. It happened to Reddit, a popular user-generated news site similar to Digg, and it can happen to you. It is very difficult to be 100% sure that your database will never fall into the wrong hands: unless you have enterprise-level security staff, infrastructure, procedures and budget, every single person involved with your data will be a weak link in the chain, from the developers to the DBAs to the dodgy geezer who comes in as a contractor to do the building’s networking. Do you know where all the copies of your data are — even the partial, out of date ones that your developers use for testing? Are you sure there aren’t any hanging around on backup CDs, USB key disks, laptops, or old PCs that you are throwing out?

No, you should never store your users’ passwords directly in a database. Instead, you must use a salted hash: a one-way encryption algorithm which makes it impossible — or at the very least, computationally very expensive and impractical — to reverse engineer them into the original password.

Unfortunately, this means that you can’t send password reminders to your users. Instead, you have to send them a single-use link to a page where they can reset their passwords on confirmation of their e-mail address. Because of this, some people prefer to sacrifice security in favour of convenience here. In fact, if the comments that were left on Jeff Atwood’s blog when he wrote about this subject are anything to go by, sometimes this design decision is imposed on developers, against their recommendations, by their managers.

I think that Mats Helander comes up with the best response to this, when he says that it should be illegal to store passwords in a database in plain text:

Many comments on Jeff [Atwood]’s blog lamented the fact that sometimes your boss will decide for you that passwords should be stored in plaintext (or two-way encrypted using a secret key, which the hacker will of course be able to obtain as readily as your password list, meaning it’s as good as plaintext). One often suggested reason would be a requirement that the system must be able to mail back a user’s forgotten password.

In my opinion, this is one of the very rare cases where I think the law should get involved, protecting the developer from having to compromise my security in order to keep his job. The developer should be able to say “No boss, that would be against the law”.

I couldn’t agree more. Really, the extra complexity introduced by the “reset password” option is very minor, and given the potential consequences of losing your data to an attacker, seriously compromising my security in favour of convenience in this way is inexcusably reckless, especially in a day and age when identity theft is a serious and growing problem.

26
Sep

Is your code held together with bits of string?

Meh.

I hate naive code that sends data to a database by concatenating it into a SQL string.

Unfortunately, there is far too much of it knocking around — no doubt because of the proliferation of rubbishy tutorials that teach beginners that that is the way to do database access.

Take this C# example:

public int InsertEvent(DateTime date, string description)
{
    using (SqlConnection cn = new SqlConnection(connectionString)) {
        cn.Open();
        SqlCommand cmd = new SqlCommand(cn,
            "insert into Events (Date, Description) values "" +
            date.ToString() + "", "" +
            description + "";select @@IDENTITY");
        return (int)cmd.ExecuteScalar();
    }
}

It’s not just the SQL injection vulnerability that makes this code stink like a sewer: it has localisation problems as well.

Here in the UK we write dates as day/month/year, so today would be 26/09/2007. However, on the other side of the pond, they write dates as month/day/year, so today would be 09/26/2007. So if the locale of your ASP.NET application is different from the locale of your database login, you will get either the wrong date or a data conversion error.

On your development computer and your production server you will probably have your locales set up so that it all works correctly. However, it causes problems when you have to set up the application on a new box — for instance, when another developer starts to work on the project. Especially if the other developer is in another country.

Please stop doing this!!!!

Any decent, modern programming language will let you use parametrised queries to keep your SQL and data separate. These also allow you to send dates and times to the database in native, unambiguous datetime format, avoiding any thorny localisation issues, and they all but eliminate SQL injection vulnerabilities.

The only excuse for using string concatenation in this way is that you still have to support PHP 4 which does not give you the option of parametrised SQL queries for MySQL. Even then, if at all possible, you should be upgrading to PHP 5, which does.

27
Jul

I could have told you this would happen…

Automattic releases the WordPress Stats 1.1 plugin, and the next day, it is found to have a SQL injection vulnerability.

Fortunately, the vulnerability has been fixed, but it is this kind of bug that I was talking about earlier today. With a solid, well thought out database access architecture using parametrised queries, SQL injection vulnerabilities like this could be all but eliminated.

If the WordPress guys don’t change their tune about GoPHP5 sometime soon and come up with a firm action plan to rework their application architecture to use PDO and nail these things on the head, I’m looking for another blog engine.

(Updated: added link to the fix)

27
Jul

Some thoughts on WordPress security

I’ve been thinking a bit more about what to do with my blog. More from a technical perspective than anything else, mind you — I have been wondering a bit whether WordPress is the best solution to use for it, and if not, what I should be using instead.

WordPress is very popular and very fully featured, but it has a poor reputation when it comes to security. Stefan Esser, of “Month of PHP Bugs” fame, is particularly critical — a week or so back he gave an interview on BlogSecurity.net about the problems with WordPress, citing architectural problems that make it difficult to write secure code.

I must admit that while there is a lot that WordPress does very well — it is a very full featured application, supported by a lively community — I find its codebase pretty tacky. Some of it isn’t too bad, but the admin section in particular is a right unholy mess, with HTML, PHP code and SQL statements bundled together haphazardly in a monstrous plate of gone wrong spaghetti bolognese on the loo.

Matt Mullenweg is pretty defensive about WordPress security, however. In a blog entry about a month ago, he made the point that (a) all software has bugs and security vulnerabilities, which is true, and (b) that the WordPress developers do a great job of tracking down and fixing bugs and security holes before releasing a new version, which is also true. However, he did not address the point that the overall architecture of WordPress makes the process of tracking down and eliminating bugs — and keeping out whole classes of certain bugs in the first place — unnecessarily difficult.

The fact that Mullenweg has stated his opposition to the long overdue GoPHP5 initiative and the end of life of PHP 4 is also far from reassuring. PHP 4 may still be amazingly popular, but it has some serious shortcomings as a language which make it much more difficult to write robust, secure and easily maintainable code — shortcomings which were addressed in version 5. It has no support for parametrised queries, for instance, forcing developers to adopt the dangerously insecure practice of concatenating SQL code and user input to construct database queries. In an attempt to protect against SQL injection attacks, PHP offers magic quotes — an ugly, naive, broken and widely criticised hack that causes more problems than it solves and doesn’t always work.

What makes this more serious is that these days, writing WordPress plugins and themes is for many people the introduction to the world of software development, and while it does need to be kept simple so that newbies can learn and participate to some extent, it also needs to show the way in terms of good programming practices and robust code, and when you are using a language that limits your ability to do so, it is not good.

So how could WordPress improve in this respect?

First of all, the WordPress core team needs to take PHP 5.2 seriously and sign up to GoPHP5. The new features of PHP 5 are not merely luxuries; they do make it much easier to adopt good programming practices and write robust, easily maintainable code. It would not make it more secure overnight, but it would make it considerably easier to evolve it towards a better, more secure, more robust and more easily maintainable architecture.

Secondly, it needs as complete a suite of unit tests and integration tests as possible. I know that there are moves afoot to add unit testing to some particularly error-prone parts of the application, but the automated tests need to go beyond this and cover as much of the code as is possible. These would not only increase confidence in the code quality dramatically, they would also make it a lot easier to track down and fix bugs that creep in during development. Automated unit and integration testing seems much less common in PHP open source projects than in their counterparts in .NET or Java, and if WordPress takes a solid lead in this respect, it will be a smart move and bring them kudos among serious developers.

This would, however, necessitate some fairly fundamental architectural changes. It is much more difficult to write meaningful unit tests for an application with a monolithic structure where HTML, PHP and SQL code are all wrapped into one than for an application that adopts a three-tier or Model-View-Controller approach. This does not have to be done all at once, and it does not have to become fully object oriented, but WordPress does need to move towards a more structured approach with a better separation of concerns between database access, network communications (such as e-mail and pings), business logic and the UI.

Finally, the upgrade process needs to be made as simple as possible for the end user. I wrote a while back about how we have moved to a scripted, single step process for one of our major projects, which makes the process of applying changes a doddle. WordPress needs to do something similar. It can be, and should be, as simple as pressing a button on your dashboard. Novice users certainly should not need to bother with making backups, FTPing some parts of the application and not others, and so on — it is an error-prone process that can be so daunting for inexperienced users that there are still a lot of blogs out there running WordPress 1.5, wide open to attack.

13
Dec

Secure your contact form!

For the past week and a half a hacker seems to have been trying to use my contact form as a relay for sending spam.

I was first alerted to this at the start of last week when I received a couple of e-mail messages through my contact form that contained a garbled subject line and a message body that appeared to consist mainly of SMTP headers. Checking my website access logs indicated that they were specifying no user agent string and coming from a wide variety of IP addresses, which suggests to me that they were doing some kind of IP address spoofing.

I locked off my blog to POST requests from visitors with no user agent, and added a bit of code to save fuller details of these requests to a text file. One such request gave me this posted data:

UIMessage = thy9762@jamesmckay.net
UISubject = thy9762@jamesmckay.net
UIEmail = thy9762@jamesmckay.net
UIName = floated
Content-Type: text/plain; charset="us-ascii"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
Subject: solicitude of my noble friends got the start of
bcc: charleselegbed@aol.com

53d44f59854c6571b004d87de523ce99
.

What is going on here? The variables UIMessage, UISubject, UIEmail and UIName are (or rather, were) the names of the input fields on my contact form. What this hacker seems to have done is to submit a request to my contact form containing the following information in the “UIName” field:

floated
Content-Type: text/plain; charset="us-ascii"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
Subject: solicitude of my noble friends got the start of
bcc: charleselegbed@aol.com

53d44f59854c6571b004d87de523ce99
.

The net effect of this would be to stick some additional headers into the e-mail — including this bcc at the bottom to charleselegbed@aol.com, whoever he is. A Google search for this e-mail address finds a lot of apparently similarly compromised guestbooks, blog comments and the like, so presumably he’s running some kind of bot.

The messages are coming fairly regularly, about two an hour between 5pm and 8am UTC or so, from a wide variety of IP addresses, which seems to indicate that they are being spoofed. It is possible to spoof your IP address but it does mean that you won’t receive a response from the web server. However, the hacker clearly isn’t interested in the response here: he’s more interested in seeing if his probing e-mail gets delivered, which he will be able to determine from the 32-character string at the top of the message subject. If he does, then the next stage would be to submit another request to your website using the relevant knowledge to send out a whole lot of spam.

I checked my e-mail logs to see if he had attempted this. Sure enough, he had, but his attempts had failed, thanks to a rather convenient size restriction that my ISP places on SMTP headers in e-mail messages.

Armed with this knowledge, I quickly added some code to my contact form to reject any submissions that include a newline character where there shouldn’t be one. I am also checking the sender’s e-mail address a lot more carefully as well, and I’ve renamed the contact form, the input fields on it, and the address to which contact e-mail messages are sent. However, I’m still getting regular requests for the original contact form. Since they are using IP address spoofing, they wouldn’t be receiving the 404 status code, but it’s still a bit odd, given that they won’t have received any probing e-mails for several days now.

The vulnerability particularly seems to affect PHP’s mail() function, which relies on the “additional headers” parameter for things such as setting the “From:” address, the priority, and so on. This parameter is supplied in the form of a string, which is blindly appended to the end of the SMTP headers in your e-mail message. This is in contrast to how it is done in ASP.NET, for instance, where additional headers are much more sensibly specified as a dictionary of key-value pairs.

To avoid problems with this, you need to validate your user input carefully. First, check that anything that is supposed to be a single-lined value actually is a single-lined value, i.e. it doesn’t contain carriage returns (‘r’) or linefeeds (‘n’). Secondly, check to ensure that anything that is supposed to be an e-mail address actually is an e-mail address. The blogging software that I use, WordPress, has this rather useful function:

function is_email($user_email) {
  $chars = "/^([a-z0-9+_]|-|.)+@(([a-z0-9_]|-)+.)+[a-z]{2,6}$/i";
  if(strstr($user_email, '@') && strstr($user_email, '.')) {
    if (preg_match($chars, $user_email)) {
      return true;
    } else {
      return false;
    }
  } else {
    return false;
  }
}

Finally, if you are constructing your e-mail address in the form “name” <email@address>, make sure that you strip out any characters that might confuse it from the name that the user supplies, such as quotation marks, square or angle brackets, and so on.

My initial tests on ASP.NET’s System.Web.Mail classes indicate that they are somewhat more robust, but this probably won’t stop them having a go regardless. This can be a little bit annoying, so it’s best to stick in some more validation anyway. You can never be too careful, after all!