SSH Time-Based One-Time Passwords
“I do not alway log in remotely through unsafe machines, but when I do, I do it as securely as possible.”
In order to keep my systems safe, even in case the passwords had been overheard/peeped/logged, I use 2-step authentication.
You should too.
I prefer Time-Based One-Time Passwords instead of the one that increments the counter. There are quite a few implementations of this idea available. Reading through I have chosen to go with OATH which is industry-wide effort to provide such solutions basing on open standards.
I alway carry my phone with me, so it was natural candidate to serves me as token generator. I have installed and FOSS app, FreeOTP, that generates the tokens.
Also, since it’s all time based, I made sure that clocks on the devices are synced up - I am using carrier synchronization on my phone and NTP clients are running on the servers.
You should install oath-toolkit, which is provides some components and libraries we are going to use, including PAM module to handle the authentication.
portmaster security/oath-toolkit dnf install oath-toolkit pacman -S oath-toolkit
Or however it’s done in your religion.
/etc/pam.d/ you should find files corresponding to logging in method, such
I added auth module as requisite (see
man pam.conf for details) on
top of ssh one.
auth requisite /usr/local/lib/security/pam_oath.so usersfile=/etc/users.oath
On FreeBSD I had to specify full path to the module.
On most Linux distributions, if oath-toolkit is installed through package
pam_oath.so instead of full path should be sufficient.
You can go with required instead of requisite if you don’t want to reveal whether the OTP was correct straight away.
From now on you will be asked for OTP first, and then for you’ll have to provide your regular password.
The usersfile I pointed OATH module to is
Fedora caveat: use
/etc/liboath/ directory, due to selinux permissions.
Example provided in documentation is very brief:
HOTP root - 00
Too brief, I would say. It took me some research (actually reading through source code) to make sense of the syntax.
White spaces are threated as delimiter, and fields are:
- first is auth method,
- second is user name
- third would be used if we would like to have additional password
provided along with the token (since in this case PAM will ask us for
the regular password just after token, we are okay with none using value
- fourth field is the secret used to generate tokens, in hexadecimal format.
- fields after that would contain last password used (so it can’t be reused straight away) as well as the counter regular HOTP
I recommend using SHA1 of a random data as a secret:
head -c 2048 /dev/urandom | openssl sha1
HOTP is sequentional 6 digit key by default. I had trouble finding in documentation way to use Time-Based Tokens so I read usersfile parsing code which gave me idea how to do this.
For sequential token:
HOTP = HOTP/E = HOTP/E/6
For 30s Time-Based Token:
HOTP/T30 = HOTP/T30/6
6 stands for token length. There is also
T60 variant. Valid
token lengths are 6, 7 and 8.
In my case I have something in the lines of:
HOTP/T30 ivyl - bbad0952f0a72626e216e206d121e314c3ee1700
Usersfile should not be readable or writable by non-root, so just do
chmod go-rw /etc/users.oath
Make sure that following options are present in you
ChallengeResponseAuthentication yes PasswordAuthentication yes
Otherwise the OTP challenge won’t appear while logging in.
The Token App
I use FreeOTP. The secret should be base32 encoded (instead of
simple hexadecimal dump)… You can use
oathtool provided with the
oath-toolkit to do the conversion.
oathtool -v $(read foo; echo $foo)
And paste the hexadecimal secret.
I recommend digging into code of oath-toolkit. Especially the PAM module. PAM simplicity is astonishing.
- 20161119 - general overhaul