Double Protection

Two-factor authentication is a system in which two different factors are used in combination to authenticate a user. Two factors, as opposed to one factor, will deliver a higher level of authentication assurance. The combined factors could consist of:

The first option is the easy choice. Passwords are used everyday for a multitude of purposes. The third option is usually some sort of biometric – not a good choice for the web environment. "Something the user possesses" is the best second factor for authentication. Almost all web-based, two-factor authentication solutions available today involve some form of hardware token, such as the RSA SecurID. Distributing these tokens to users is neither cost effective nor scalable in price. A company might be able to afford tokens for 1,000 users, but one good blog post and they could find themselves with 30,000 new users overnight. Requiring users to obtain a hardware token on their own is too much work for the vast majority of users. In addition, tokens have to be synced with special server software, which can often require a proprietary license.

A less expensive and more scalable alternative for two-factor authentication on the web is a one-time password (OTP) system. The November 2008 issue of Linux Magazine offered an introduction to OTPs [1] that focused primarily on workstation authentication; however, tasks like checking a bank account from an untrusted network scream for some form of two-factor authentication, and an OTP system is often a practical solution. In this article, I describe how to add the security of OTPs to your website.

OTP on the Web

RFC 2289 [2] defines an OTP system derived from Bellcore S/KEY technology (RFC 1760). If implemented correctly, it provides a cost-effective, two-factor authentication solution for websites. Imagine that a help desk technician with administrative privileges for a website hits an administrative page that generates a wallet-sized list of 30 OTP number/key pairs. The list is then hand delivered to the user. This password list now becomes something the user possesses – the second factor – and because it was never transmitted electronically, it provides an added level of security. If the site doesn't mind electronic transmission within its trusted domains, the admin might fax or even email the list to the user. From a cafe in Amsterdam, for example, the user can now enter a conventional username and password. If this initial authentication is successful, the server poses a challenge that requires a response with the correct corresponding OTP. After this login, the OTP is immediately invalidated for future use, which means it will never be used for a replay attack. For the next login, the user will enter the next OTP on the password list.

By forcing the user to authenticate through a pair of dissimilar mechanisms, two-factor authentication provides a much more secure alternative for web login. This basic scenario leads to endless variations. For instance, a user could associate a cell phone number with the account; then, when logging in, the system could send the OTP in a text message. Or, a user could generate OTP passwords from a program running on a PDA. An added advantage of this scenario is that the implementation can give the OTP a temporal component so that it times out after 60 seconds, much like the RSA SecurID, although this would require the user synchronizing the PDA application with the server.

OTP Tools

A plethora of OTP libraries exist for SSH, console, and network logins, with plenty of OTP libraries for more exotic tools like SquirrelMail and PalmPilots, but finding open source libraries for OTP authentication in a web environment is difficult. One RFC 2289--compliant OTP system that has been tested and released under the GPL is the OTPauth PHP library [3]. OTPauth, which uses the SHA1 hashing algorithm, has been employed successfully by a site with several hundred users for over two years. Another PHP library, otp, is available from SourceForge [4]. The otp developers hope to have a demo up and running soon.

Various Java tools assist with the task of constructing and validating OTPs [5], but I am not aware of a complete web library (e.g., something that integrates a full challenge/response implementation into a j2ee application).

The Google AuthSub library [6] allows authentication with Google applications via secure tokens. Although AuthSub is not a strictly RFC 2289--compliant OTP solution, it does allow secure, one-time token-style authentication for Google applications. It will be interesting to see whether Google continues to develop this solution or migrates completely to OAuth. A handful of other software packages provides a customized OTP solution exclusively for their software, such as a plugin for the Joomla CMS [7].

Here, I describe how to set up an OTP system with the open source OTPauth library. The other tools operate on similar principles. If you are interested in exploring one of the alternatives, see the documentation at the project website.

A Look at Self-Service OTP

Imagine a bank that wants to encourage good security practices but cannot insist on universal two-factor authentication without scaring away half of its customers. The bank wants a system that supports the OTP option for early adopters without endangering the business model by forcing constraints on the unwilling.

The solution must provide the means for a user to visit a preferences page and specify that the program require two-factor authentication when logging on to the account from a computer other than that currently being used. The user then generates a personal, wallet-sized list of 30 OTP number/key pairs from the user preferences page. The next time the user accesses the account from an untrusted location, say a friend's house, the user will be asked to provide an OTP along with the conventional username and password.

The first step is to provide basic authentication with a username and password. Great libraries and standard methodologies provide basic authentication, whether you want to use .htaccess files with Apache, validate off of a database at the application layer, or let Apache validate the user with mod_auth_mysql. Because I like to provide security controls at multiple layers, I will use the architecture shown in Figure 1.

The authentication database is stored separately from the enterprise database and holds the username, password, and OTP information. Listing 1 shows MySQL CREATE statements that contain all the information needed for the entire authentication database, which mod_auth_mysql checks for the username and password. First you need to download mod_auth_mysql or get it from your package manager [8]. Once you have it installed, configure it by adding the lines from Listing 2 to your httpd.conf file. Remember to customize the settings for your website.

Now you can add code at the application layer to check for OTP authentication. The user will never get to the application without entering the correct username and password, but once done, you need to make sure a two-factor authentication option is available. First, the application must determine whether the user has enabled OTP authentication for the account. If so, the application needs to compare the current IP address and/or hostname with those listed on the user account as trusted. If the user has not enabled OTP authentication or is coming from a trusted address, then the application allows access to the web page(s) requested. The sample code in Listing 3 could be included in your application pages at the top (in which case, it is executed first) or moved to a function.

When the user is redirected to the otp_auth site, your OTP library handles the OTP challenge/response. Listing 4 shows a basic page that presents the challenge to the user and validates the response to the challenge. This page is intentionally sparse because my application is not yet convinced that this person is authentic. By not providing all my normal libraries or JavaScript, or even the look and feel of my site, I narrow the attack vectors on this page. The use of a good OTP library simplifies this application logic to a trivial amount of code with function calls like valid_otp() and get_otp_seq(). The code in Listing 4 produces a display similar to that shown in Figure 2.

Finally, don't forget to provide your users with tools for enabling OTP on their accounts, generating their OTPs, and managing their trusted lists. Listing 5 is for a very lightweight page to generate a spreadsheet of OTPs, but make sure that when a user enables OTP for an account, it isn't logged out before generating the OTP list first!

Be prepared to have a mechanism for resetting OTP lists. This could be a responsive phone/email/irc support channel or an automated page, but either way, the user will need to provide proof of identity with something else like a security question. Also, don't forget your additional security checks – none of the code samples listed here validate input data, for example.

The biggest risk with any security system would be implementing an architecture coding mistake. The technical risk is getting hacked; the business risk is getting sued. To protect yourself, you could write extensive test cases and have a third party review the software, or you could choose an existing implementation proven or peer-accepted as correct.

Architecturally, secure programming requires a number of considerations, many unique to the existing infrastructure of the system. The two most important are: 1) separate your authentication database from your enterprise database(s) and 2) separate the username/password authentication from the OTP authentication as much as possible. You want each authentication element to be clean and almost stand alone. If you handle username and password authentication in the same code library as the OTP authentication, you risk contaminating the entire authentication process with cross-code bugs.

Another technical vulnerability in any OTP system is the man-in-the-middle (MITM) attack vector. If hackers can masquerade as a website to the user while masquerading as a user to the website, there is very little they cannot do. Even with SSL, the MITM simply makes separate SSL connections and decides what to send to user and website. Network monitoring can prevent this type of attack: As the attacker continues to operate, patterns of errors emerge.

RFC 2289 allows hashing algorithm variations in OTP generation and authorization routines. Be sure that a strong hashing algorithm is in use because an intruder that gains access to your authorization database and hashes the stored tokens with an insecure algorithm such as MD5 could generate an infinite list of tokens. At least, you should use SHA1, although it is not highly secure. SHA256 is a better solution but is not available in as many languages, which means relying on and validating a third-party library or writing your own. The RFC also mentions an interesting race condition (see the "Race Condition" box), so make sure your library is fully compliant.

Another concern is social engineering the help desk staff or users. Sadly, most solutions to that problem are non-technical. Most systems with help desk staff are susceptible, including commercial hardware token-based authentication systems, so good models to establish identity already exist. Training or a Terms of Service (TOS) agreement might be advantageous. In practice, most places with enough security requirements to warrant the use of OTP already require yearly online security training. This training or TOS also should prohibit the storage of OTP lists with regular usernames and passwords.

Race Condition

One race condition exists for the OTP system. An attacker who is listening with a keystroke logger while a user is authenticating might be able to listen to just enough of the OTP to enable a brute force attack just before the user finishes typing, allowing the attacker to log on as the user before the user finishes authenticating the session. Interestingly, RFC 2289 actually has a provision for this race condition and requires that it be guarded against in order for the implementation to claim full compliance. The defense outlined in Section 9.0 of the RFC is to deny multiple simultaneous sessions. In other words, once a user initiates the authentication sequence, all other attempts to authenticate with that user should be blocked until the authentication process is complete. This could lead to a denial of service attack, so some sort of authentication timeout is necessary.