Have you ever wanted to log in to your system from a hotel kiosk or Internet café? That's risky business, but Todd A. Jacobs shows you how to work hard and play safe on public terminals. Todd walks you through the configuration and day-to-day usage of one-time password authentication using OTPW, and even shows you how to integrate it with SSH. Sadly, he offers no advice on what coffee tastes best while connecting safely from a trendy hotspot.
Password authentication contains a lot of assumptions about security and trust. Encrypted SSH tunnels and public key verification are two common ways to ensure that your password is not compromised in transit. But, what if it's the computer you're currently typing on that can't be trusted?
This isn't just a tinfoil-hat scenario for paranoid penguinistas. There are many everyday situations and common locations where you probably should not use your system password, even over a secure tunnel. Examples include:
A public computer in a hotel, library or Internet café.
A coworker's virus-infested computer.
A shared workstation while pair-programming.
Any place someone could watch you type in your password.
What do all these examples have in common? Essentially, that you're trying to connect to a trusted destination from an untrusted source. This is a complete reversal of what most authentication systems were designed to address.
Take public key authentication. SSH public key authentication certainly bypasses the password prompt on the remote host, but it still requires you to trust the local machine with your private key password. In addition, once the key is decrypted with your password, the local system has full access to the sensitive key material inside.
Uh-oh—luckily, there's already a solution for this frequently overlooked problem: one-time passwords.
The combination of SSH and one-time passwords is powerful:
The SSH protocol provides encryption of the login sequence across the network.
A good SSH client allows you to inspect the remote host's public key fingerprint before entering your credentials. This prevents a rogue host from collecting your one-time passwords.
The one-time password system ensures that a password can't be reused. So, even if the password is captured in transit, it's worthless to an attacker once you've logged in with it.
A number of one-time password solutions are available for UNIX-like systems. The two most well-known are S/KEY and OPIE (One-Time Passwords in Everything).
With the recent removal of OPIE from the Debian and Ubuntu repositories, the OTPW one-time password system created by Markus Kuhn provides a viable alternative. Although not a drop-in replacement for OPIE, OTPW offers comparable functionality while providing some interesting features not found in either S/KEY or OPIE.
In particular, OTPW provides:
Two-factor authentication, consisting of a “prefix password” and a set of autogenerated, disposable suffixes. Even if the list of suffixes falls into the wrong hands, brute force is necessary without the prefix password.
Protection against certain race conditions and man-in-the-middle attacks through the use of password locks and triplet challenges.
Shared-filesystem support. Because OTPW checks passwords against a list of hashed values stored in a user's home directory, one password list will work for all systems mounting the same $HOME directory.
Next, I cover installing and using OTPW, with a special focus on integration with OpenSSH.
To make use of OTPW, you need two binaries: otpw-bin and libpam-otpw. With Debian and Ubuntu, installation is as easy as:
sudo apt-get install otpw-bin libpam-otpw
If your distribution does not provide OTPW, you can download the source directly from the author's home page. The source tarball does not use GNU autoconf, so you will need to compile and install the binaries manually in accordance with the author's instructions.
The next step in preparing the system for OTPW is configuration of libpam-otpw. A full treatment of PAM is outside the scope of this article, but I cover the most common use cases here.
Changing your PAM configuration can lock you out of your workstation or server, so it's a good idea to keep your existing terminal open until you're sure that things are working correctly. If you have console access, keep a bootable distribution or rescue disk handy. See the Testing One-Time Password Authentication with SSH sidebar for more information about testing PAM over SSH.
The easiest way to enable OTPW is to put it immediately above pam_unix in your common-auth configuration file:
# /etc/pam.d/common-auth auth sufficient pam_otpw.so session optional pam_otpw.so auth sufficient pam_unix.so nullok_secure auth required pam_deny.so
The order of the PAM libraries is very important. When placing OTPW first, users with an ~/.otpw file are prompted for a one-time password first, allowing fallback to standard system passwords if the OTPW login fails. Users without a ~/.otpw file simply will see the standard password prompt.
If you prefer to reverse the order, prompting for a system password before falling back to one-time passwords, just ensure that pam_deny comes last:
# /etc/pam.d/common-auth auth sufficient pam_unix.so nullok_secure auth sufficient pam_otpw.so session optional pam_otpw.so auth required pam_deny.so
If you're tempted to remove standard system passwords altogether, especially from console logins, please don't. On some systems, most notably Ubuntu systems with ecryptfs-encrypted home directories, recovering from OTPW mishaps is extremely difficult without standard system passwords.
Modifying common-auth is usually the right thing to do on a headless server or console-only system. However, workstations or servers that provide the X Window System present special problems for one-time password systems.
Some tools or applications won't work properly with OTPW because they can't display the challenge to the user. The typical symptom is usually a password dialog that never completes or seems to ignore user input. In times past, gksu and GNOME Display Manager (GDM) had this issue with OPIE. In such cases, the solution is to move OTPW out of common-auth and include it only in specific services.
For example, you can add OTPW authentication to SSH connections while using just the standard password prompt for console or GUI logins. You can do this in three easy steps:
1. Delete any lines from common-auth that reference pam_otpw.so:
# /etc/pam.d/common-auth on Debian Squeeze auth sufficient pam_unix.so nullok_secure auth required pam_deny.so
2. Create a new OTPW include file for PAM:
# /etc/pam.d/otpw auth sufficient pam_otpw.so session optional pam_otpw.so
3. Include OTPW immediately before common-auth in /etc/pam.d/sshd:
# Other stuff ... # Enable OTPW authentication. @include otpw # Standard Un*x authentication. @include common-auth # More stuff ...
In addition to configuring the PAM libraries, OTPW needs the following three settings in the SSH dæmon's configuration file:
# /etc/ssh/sshd_config UsePrivilegeSeparation yes UsePAM yes ChallengeResponseAuthentication yes
These are usually there, but possibly commented out or set to “no”, so modify them accordingly. Next, reload the SSH dæmon after modifying its configuration file:
# Generic Linux sudo /etc/init.d/ssh reload # Debian 6.0.4+ sudo service ssh reload # Ubuntu 11.04+ sudo reload ssh
Once the OTPW PAM module has been configured properly, only users with an ~/.otpw file will be challenged with a one-time password dialog during login. This file contains some metadata about its contents, as well as a list of one-way hashes that will match only a valid response to a challenge.
To create this file, or to re-populate it with new passwords, use the otpw-gen utility. By default, it will create 280 password suffixes, formatted to fit on a single side of US letter-sized (8.5" x 11") paper. Because only the one-way hashes are stored in ~/.otpw, not the passwords themselves, you must capture or print the standard output of this command when the passwords are generated. You will not be able to retrieve the password list after the fact; you'll need to generate new passwords instead.
Here is what it looks like when you run the command for the first time, piping the output to your default printer:
$ otpw-gen | lpr Generating random seed ... If your paper password list is stolen, the thief should not gain access to your account with this information alone. Therefore, you need to memorize and enter below a prefix password. You will have to enter that each time directly before entering the one-time password (on the same line). When you log in, a 3-digit password number will be displayed. It identifies the one-time password on your list that you have to append to the prefix password. If another login to your account is in progress at the same time, several password numbers may be shown and all corresponding passwords have to be appended after the prefix password. Best generate a new password list when you have used up half of the old one. Enter new prefix password: Reenter prefix password: Creating '~/.otpw'. Generating new one-time passwords ...
When generating a new password list, the prompts that appear on standard error are slightly different:
Overwrite existing password list '~/.otpw' (Y/n)? Enter new prefix password: Reenter prefix password: Creating '~/.otpw'. Generating new one-time passwords ...
The first prompt ensures that you don't accidentally over-write your existing password list; the second prompt asks you for a new password. There's nothing stopping you from reusing the same prefix password on each invocation—the random seed makes duplicate hashes unlikely—but best practice is to use a new prefix each time you regenerate the password list.
If you want to generate a password list on a remote host but print to a local printer, you can do this over your SSH connection as long as you trust your localhost:
read -p 'Hostname: ' && { stty -echo ssh "$REPLY" otpw-gen | lpr stty echo }
Note the use of stty to ensure that your prefix password isn't echoed to the screen. As long as your prefix password remains secure, you are no worse off using an untrusted printer than you are if your password list falls into the wrong hands. This is often a valuable security trade-off for frequent travelers.
Finally, to disable OTPW challenges for a given user, just delete the .otpw file in that user's home directory.
Once you have your password list in hand, you're ready to use one-time password authentication for your SSH connection. Assuming that you don't have any identities loaded into your SSH agent, your dialog should look similar to this:
$ ssh localhost Password 015:
The prompt with the digits is the OTPW challenge. To respond, find the matching challenge ID on the password sheet you printed earlier. Next, enter your prefix password followed by the string that follows the challenge ID.
Using “foo” as a prefix password, the following suffix list was generated. Your list and suffixes will be different, even if you use the same prefix password.
OTPW list generated 2012-05-06 13:40 on localhost 000 SWvv JGk5 004 =qfF q2Mv 008 sb5P h94r 012 o5aH +/GD 016 8eLV VxuA 001 xPZR :ceV 005 B=bq =mHN 009 WBSR smty 013 QMZ% +bm8 017 vjFL K4VU 002 Sj%n 9xD3 006 RrNx sJXC 010 Xr6J F+Wv 014 j=LO CMmx 018 Km8c 8Q3K 003 s7g8 NE%v 007 sd=E MTqW 011 fNKT vo84 015 fWI% MB9e 019 z8ui %eQ3 !!! REMEMBER: Enter the PREFIX PASSWORD first !!!
To respond to this challenge successfully, type:
foo fWI% MB9e
at the prompt. The spaces are optional; OTPW ignores them if present.
If you answered the challenge correctly, login will proceed. Otherwise, you will be prompted with the standard system login. At this point, you can enter your standard system password, or press Return to give OTPW another try. After the system-defined number of password attempts (usually three), the login will fail and return you to the command prompt:
$ ssh localhost Password 013: Password: Password 013: Password: Password 013: Password: Permission denied (publickey,password,keyboard-interactive).
To prevent simultaneous logins, or when SSH is interrupted during OTPW authentication, OTPW may lock a password. When a password is locked, your next login attempt will present a triplet challenge that requires one prefix and three suffixes to respond:
$ ssh localhost Password 004/011/005:
Given the same password list as before, enter your triplet response as a single line, with or without spaces. The following shows how the response is composed (note that the first line below is just an informational aid; you would type only the second line below, without the pipe characters):
prefix | suffix 004 | suffix 011 | suffix 005 foo | =qfF q2Mv | fNKT vo84 | B=bq =mHN
Once you have successfully responded to a triplet challenge, login will proceed and the ~/.otpw.lock symlink should be removed, and your next challenge will again be a single challenge ID number.
In some cases, the lock is not removed properly. If you continue to be prompted for a triplet, you can remove the lockfile manually:
rm ~/.otpw.lock
Users with encrypted home directories that are not already mounted before login will need to take a few additional steps. See the OTPW and Encrypted Home Directories sidebar for an example.
If your password list is exhausted, you will no longer be able to use OTPW to log in until a new list is generated. Likewise, if your password list doesn't contain at least three unused responses, you will not be able to use OTPW to log in when ~/.otpw.lock exists, because there are not enough challenge IDs to issue a triplet.
In addition, some of the security of OTPW comes from the randomness of the remaining challenges. The use of triplets in particular can exhaust your unused passwords rapidly, so it's a good idea to regenerate the password list whenever you fall below a minimum amount.
The OTPW author recommends regenerating the password list when less than half the original passwords remain unused, but doesn't define a minimum bound for number of passwords required for adequate randomness of challenges. A small number of unused passwords makes you more vulnerable to brute-force attacks, since there are fewer challenges to present.
The pam_otpw.so PAM module is supposed to inform the user when unused passwords fall below half of those generated. However, the PAM session functionality doesn't seem to work on Debian or Ubuntu. In addition, even if it worked, the module doesn't establish a floor to ensure sufficient randomness of challenges.
The otwp-stats.sh script shown in Listing 1 provides this missing functionality. It also allows you to define a sensible minimum for unused passwords by adjusting the MIN_PASSWORDS variable at the top of the script.
Add otwp-stats.sh to your ~/.profile (or other shell startup script) to provide feedback at login:
# Only run script when logging in via SSH. [ -n "$SSH_CONNECTION" ] && ~/bin/otpw-stats.sh
OTPW provides a one-time password implementation that compares favorably against OPIE and S/KEY. It is easy to integrate with SSH on most Linux systems, and remains possible to use on Ubuntu systems with encrypted home directories.