I.T. Security and Linux Administration

Mar 15 2012   3:18PM GMT

Two-Factor Authentication in PHP Using SSH

Eric Hansen Eric Hansen Profile: Eric Hansen

For a good couple of years now I’ve wondered if there was a way to write an authentication system in PHP that utilized SSH instead of the widely-breakable database and flatfile methods. After doing some research I found its possible after installing a PHP extension. This guide will detail the methods used to do this, with the intent of hopefully having this a more versatile option.

Before we begin, there are a few things that are needed. The first is obviously PHP, with this guide written for 5.3.6. My system has Suhosin already installed and it causes no issues so you should be fine too if you have those patches installed. The next thing you’ll need is the PECL extension SSH2. There other libraries out there that you can use that people have written but I decided to stick with officially supported releases. You can install this by simply running the following command:

pecl install ssh2

I cannot guarantee this but it is better safe than sorry, your PHP should be compiled with OpenSSH libraries.

Configuration File
I’ve already written all the code for both the configuration and actual authentication, and I’ll provide those links at the bottom of this. But, basically the configuration file will store this information:

  • Host – The FQDN or IP of the SSH server (usually localhost is okay)
  • Port – The port which the host is listening on (standard is 22)
  • Key path – The path to the private key (used for public key authentication only)
  • Fingerprint – The fingerprint, or unique ID, of the host. If the fingerprint doesn’t match the server’s, authentication will be refused regardless
  • Authentication mode – Tells the system whether to use password or public key (default)

Now, if you’re wondering why the fingerprint is so important, here’s a scenario. Let’s say you are using this to authenticate users for a banking system. Someone compromises the server and reroutes incoming port 22 packets to a different server (thus with a different fingerprint). If the fingerprint in the config file does not match the fingerprint of the attacker’s SSH server when the script tries to establish a connection, the connection will die. This ensures that accounts are not compromised and sensitive data is not stolen. We add an extra layer of security to this by enforcing public key by default.

Authentication Class
I’m sure this is what you’re probably wondering, so I’ll address this first. There is a function available (SSH_GetFP()) that lets you get the fingerprint of the server. Here is a list of the functions available and what they do (all prefixed with SSH_):

  • Conn() – Creates a connection to the SSH server based on host & port.
  • Exists() – Determines whether the extension is installed or not.
  • FP() – This does the fingerprint checking of the config file against the server.
  • GetFP() – Function to get the fingerprint of the server (should ONLY be used to get the fingerprint…and never used in production)
  • AuthKey() – Authenticates a user by public key. Takes 3 arguments: username, public key file and the passphrase. If no passphrase is provided the function will fail.
  • AuthPass() – Authenticates a user by password.

Using These Files
After you properly set up the configuration file, do this to get the fingerprint of the server:


$ssh = new Auth_SSH();

Every function calls SSH_Conn() due to a connection resource being needed, so you do not have to call it directly. As long as your host and port are correct, Get_FP() will establish the connection and get the fingerprint for you. Now you just need to add that to your configuration file.

To authenticate a user, its pretty easy. For passwords:

if(!$ssh->SSH_AuthPass(“username”, “password”)){
} else{

To use the public key method, its a little bit trickier. You can either have the person upload their public key to the server or store them on the server along with the private key. My recommendation on this would be to have them upload their public key. To use this method, call it like so:

if(!$ssh->SSH_AuthKey(“username”, “/path/to/pub/key/file.pub”, “passphrase_for_keyfile”)){
} else{

The reason why the passphrase is mandatory is, besides it being good security practice, is that in case someone does compromise the server and steals the public key, they still cannot log in without the passphrase.

Is this a flawless method? No. However, I strongly believe two-factor authentication is the wave of the future (which public key authentication is when provided with a passphrase). The source for these files are open to the public. If you use it, credit is welcome but not mandatory.

Also, you’ll see looking through auth_ssh.php that $this->msg is filled a bit. This is used for debugging purposes. Functions themselves only return true or false (except for SSH_Conn() which returns a resource ID). While I try my best, I cannot guarantee this will work for you, but it does work for me.

auth_ssh.php – https://github.com/SecurityForUs/CodeDump/blob/master/auth_ssh.php
auth_ssh_config.php – https://github.com/SecurityForUs/CodeDump/blob/master/auth_ssh_config.php

 Comment on this Post

There was an error processing your information. Please try again later.
Thanks. We'll let you know when a new response is added.
Send me notifications when other members comment.

Forgot Password

No problem! Submit your e-mail address below. We'll send you an e-mail containing your password.

Your password has been sent to:

Share this item with your network: