################################################################################# # Searchable Keywords: two factor authentication apache security token # ################################################################################# Two Factor Authentication Using a Cell Phone as a Token Author: Gary Keen Date: Sept 20 2008 Purpose: The purpose of the 2factor code was to provide simple two factor authentication to a Apache web server using https, htaccess security features of Apache and a cell phone as a token. SECURITY: Two factor authentication is a good thing to have but I will be the first to admit that there are wholes in this and is NOT without risk. Once you enter your password into the site the script goes back and changes your password to another random number after 60 seconds. So you cannot use the same password over again. At least not after 60 seconds. How it works: The first thing I did is install Apache web server. This code was originally built and tested on a Centos 5 Linux system, 700mhz, 512mb memory. Nothing special was done in the configuration of Apache. I created a directory on the system I wanted to protect or only wanted to allow selected users. In this directory I created a .htaccess file. The one that follows is similar to the one I originally used. Step 1) # cat .htaccess AuthType Basic AuthUserFile /etc/httpd/htauth/htpasswd_file AuthGroupFile /etc/httpd/htauth/htgroup AuthName private_web require group private_web order allow,deny allow from all Step 2) Next I created a file that would hold the user names, cell phone numbers and pin numbers of the users in which I would allow access into my protected directory. This file I called cellist and placed it in with the password file that would be used by htpasswd cmd in /etc/httpd/htauth. # cat /etc/httpd/htauth/cellist userid:1234:user.one@tmomail.net userid:5678:user.two@sprint.com userid:9101:userthree@att.net The file is semicolon delimited and will be easy to parse fields from. The first field is the user id that the user of course will know. The second field is the pin number that the user will have to be told and they will have to remember. The third is the Email address of the cell phone we will email once the random half of the password is generated. Step 3) The next step involved putting together a web page that used form format that would call a cgi script. # cat index.html

<FORM action="https://apacheweb/cgi-bin/htpasschg_v4.cgi" method="get"> <P> User name: <INPUT type="text" name="username"><BR> <INPUT type="submit" value="Send"> <INPUT type="reset"> </P> </FORM> <html><head></head><body> Again, nothing fancy and I'm sure there are those out there that could make this more elaborate. This form displays nothing more than a field asking for a user ID, a submit button and a reset button. If the user ID is not in the cellist file listed above the script errors. If you enter nothing in the field and hit the submit button, the script will error out. Get the user name right and hit enter and the above cgi script runs. The initial URL was a https connection(https://webserver/index.html). I used a self signed certificate for proof of concept. The rest of the URLs include https as well. This way nothing goes out in clear. You certainly do not have to use secure http. The cgi script parses the out put of the form ( $QUERY_STRING ) and pulls out the user ID. It also identifies but DOES NOT show on the web page the users pin number and cellphone Email address. # cat htpasschg_v4.cgi #!/bin/sh # # #################################################### # Author: Gary Keen # Date: 9/15/08 # Description: # Change a users htpasswd but include the PIN # that THEY will know and Email the token #. # #################################################### #------------------ Variables ---------------------# echo -e "Content-type: text/html\n\n" echo "" UI=`echo $QUERY_STRING | awk -F"=" '{print $2}'` PASFILE=/etc/httpd/htauth/htpasswd_file MASLIST=/etc/httpd/htauth/cellist HTPASSWD=/usr/bin/htpasswd # #-------------------------------------------------# if [ -z "$UI" ] then echo "Use the back button to return to the login page." echo "Please enter user name" exit 0 else USER=$UI fi #--------- Does the user have an account ---------# cat $MASLIST |grep $USER >/dev/null 2<&1 FOUND=$? if [ $FOUND != 0 ] then echo "You don't have a user account. Try again." exit 0 else USER=$USER fi PIN=`cat $MASLIST | grep $USER |awk -F":" '{print $2}'` MAILADRS=`cat $MASLIST | grep $USER |awk -F":" '{print $3}'` USER=$USER #------------------ Functions --------------------# genrandom () { RANDUM=`/usr/bin/od -A x -t x -N 4 /dev/random |head -1 |awk '{print $2}' |cut -c1-6` # or # RANDUM=`hexdump -C -n 4 -s m -x /dev/random |head -1| awk '{print $2$3$4$5}'|cut -c2-5` # or # Use an actual cipher. I believe there several in the public domain(blowfish,2fish,mars....etc) } # mailout () { echo " $RANDUM " | mail -s "Your security token" $MAILADRS echo "You will be directed to your secured page and your token ID is being Emailed." sleep 1 } # genpasswd () { $HTPASSWD -b $PASFILE $USER $PIN$RANDUM >/dev/null 2<&1 } # #------------------- Go to work ------------------# genrandom genpasswd mailout #-------------------------------------------------# sleep 1 echo "<p>Click <a href="/gosecure.html"> here to be redirected to a list of secured directories. </p>" # or # echo "<p>Click <a href="/restricted"> here to be redirected to a list of secured directories. </p>" echo "</body></html>" #--------------------- EOF ---------------------# Finally) Once the script authenticates you and changes your password in the the htpasswd_file you are Emailed the second part of the password. Your entire password is the combination of your pin number and your random alpha numeric code that is Emailed you. This does assume you have sendmail or some MTA running your host. NOTE: In my case, the Apache process ran as user apache. In order to have the script change the user password. I had to allow group write for group apache. If user apache becomes compromised, your htpasswd_file could be at risk. # ls -l /etc/httpd/htauth -rw-r--r-- 1 root root 33 Sep 15 21:29 cellist -rw-rw-r-- 1 root apache 19 Sep 16 22:09 htgroup -rw-rw-r-- 1 root apache 20 Sep 20 21:59 htpasswd_file The length of the pin as well as the length of the random number is variable. To get a longer pin, all you need to do is edit the cellist file and make the number the length or as complex as you want. To make the random number longer you would have to play with hexdump or octal dump command. I chose the numbers and complexity I did for speed rather than real world security. At the end of the script a html tag calls either the restricted directory or I started playing with another form web page that might list several restricted directories. The one in the script, gosecure.html points to the same restricted directory regardless of which selection you make but I thought it might have merit for future use. Contents of the gosecure.html file. <form method="post" action="https://apacheweb/restricted/"> <select size="10" name="SECURED"> <option>Secured directory one</option> <option>Secured directory two</option> <option>Secured directory three</option> <option>Secured directory four</option> </select> <input type="submit"> </form> Either way you are presented with the login dialog box to access the restricted directory. At which point you can login with user ID and your password is the pin number you know and the random number you had been sent by the server itself to your cell phone. If you find this code useful, it's free to use. I just hope you have the courtesy to grant me some credit for the original idea and coding. Thank you. Getting this 2factor code. #############################################################################