User Authentication A security policy is typically defined in terms of the users of the system. An authentication mechanism is needed to counter one user masquerading as another. An authentication mechanism requires a user to prove that they are who they claim to be. This proof can come from: What the user knows e.g. passwords, pins What the user has e.g. a key, a badge What the user is e.g. fingerprint, retinal characteristics Where the user is e.g. at a particular terminal Some Authentication Threats Password guessing: Shoulder surfing, eavesdropping on network traffic. Inconvenience: hard to remember, have to carry authentication tokens, using same password for different accounts. Denial of Service: attacker behaviour (attempting to masquerade as target) results in account being locked out. Social Engineering: phishing. Physical keystroke loggers, login-spoof, Trojan Horse program, pharming (redirecting website traffic to a bogus website). HTTP Request with Basic Authentication Information If the user attempts to visit a URL that requires authentication (without providing username/password) then the response is: HTTP/1.1 401 Authorization Required Date: Fri, 08 Oct 2010 08:02:04 GMT Server: Apache WWW-Authenticate: Basic realm="EnterPassword" Content-Length: 460 Content-Type: text/html; charset=iso-8859-1 This instructs the browser to request a username/password. 1 The username and password is passed in a header in the HTTP request: GET http://localhost/ HTTP/1.1 Host: localhost Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Accept-Language: en-us,en;q=0.5 Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7 Keep-Alive: 115 Proxy-Connection: keep-alive Authorization: Basic aG9tZXI6c2ltcHNvbg== User-Agent: Paros/3.2.13 This is not Particularly Secure The authentication header provides the username and password encoded using Base64. For example, the string homer is converted to aG9tZXI, in Base64. In the example above, the Base64 encoding of the username and password is sent from the browser to the server as plaintext over the HTTP protocol. This means that a malicious user who can eavesdrop on this connection can discover the encoded username and password and simply decode using Base64 and then masquerade as the user. This basic HTTP authentication is adequate as weak form of authentication. However, if stronger authentication is required then the connection should at least be made to the server over a secure channel using HTTPS (which we will look at later). Configuring the Web Server for HTTP Authentication The web-server file .htacess is used to specify who may access documents under the directory that includes this file .htaccess. For example, placing the following .htaccess in my directory /Applications/MAMP/htdocs/lab01 means that only authenticated user homer may access documents in this directory. AuthUserFile /Applications/MAMP/private/.htpasswd AuthGroupFile /dev/null AuthName EnterPassword AuthType Basic require user homer 2 The .htpasswd file specifies the user’s password. homer:j7IaPh9DCn/Wg The password is given in an ‘encrypted’ form (one-way hash) so that anyone who manages to read the .htpasswd file cannot determine homer’s password. However, just to be safe (defense in depth) we should not store the .htpasswd file in the web document path. Aside. In *nix, you can use the shell command htpasswd to ‘encrypt’ a password. For example, htpasswd -nb homer doh! generates the entry homer:jMbnDzxStXI9E. Other Types of HTTP Authentication HTTP also supports challenge-response based authentication. The browser proves that it knows the password to the server without having to reveal it. Msg1 : Browser ! Server : hello Msg2 : Server ! Browser : challenge N Msg3 : Browser ! Server : response h(N : username : password) where h() is a special form of encryption (one-way hash function). So long as the server generates a different challenge for every authentication attack then an eavesdropper listening in on the exchange cannot discover the password (requires breaking the encryption) nor can it carry out a replay attack since every authentication exchange is different. HTTP provides NTLM and Digest as challenge-response protocols. However, due to a number of factors, these protocols are not much more effective than Basic. In practice, complex web-applications implement their own authentication mechanisms. Authenticating with Digest A user attempts to visit a website which is configured to use challenge-response authentication. The response is: HTTP/1.1 401 Authorization Required Date: Fri, 08 Oct 2010 09:14:18 GMT Server: Apache WWW-Authenticate: Digest realm="EnterPassword", 3 nonce="gXpwbxeSBAA=4d0a4e5c20fa710a5cd920170b521f5141503755", algorithm=MD5, qop="auth" Content-Length: 460 Content-Type: text/html; charset=iso-8859-1 The browser obtains the user-id and password from the user and this is the response. GET http://localhost/ HTTP/1.1 Host: localhost Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Accept-Language: en-us,en;q=0.5 Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7 Keep-Alive: 115 Proxy-Connection: keep-alive Authorization: Digest username="homer", realm="EnterPassword", nonce="gXpwbxeSBAA=4d0a4e5c20fa710a5cd920170b521f5141503755", uri="/", algorithm=MD5, response="43cf12bd3f8ae897174783e9d6e9dfea", qop=auth, nc=00000001, cnonce="6730aae57c007a05" User-Agent: Paros/3.2.13 Group Based Access Control Policies You can organize the users who may access the website/page according to groups and then allow access based on these groups. AuthUserFile /Applications/MAMP/private/.htpasswd AuthGroupFile /Applications/MAMP/private/.htgroup AuthName EnterPassword AuthType Basic require group cs3511 and the .htgroup file defines the groups. cs3511: homer monty bart Assuming that the passwords for these users are in the .htpasswd file. Blocking Access Based on IP You can block access to your website/page by specifying access controls by IP address. For example, block access from 123.45.6.7 and from the system csa.cit.ie. order allow,deny deny from 123.45.6.7 deny from csa.cit.ie allow from all 4 Using an IP address is a weak form of access control since it is possible for the visiting system to spoof its IP address. A Simple Web Login Mechanism Suppose that only registered users are permitted access to the foobar.com website. In order to login (be authenticated) a user must provide a user name and password to the login form at foobar.com/login.html The following is a (poor) example of how this authentication might be implemented at the server. A database table contains the names of authorized users and their corresponding passwords. The login script checks whether the provided username/password appear in the table. A session to the main website page is created for an authenticated user. The Database Table CREATE TABLE passwordTable ( ‘username‘ varchar(8) NOT NULL, ‘password‘ varchar(8) NOT NULL, PRIMARY KEY (‘username‘) ); Note that specifying username as primary key ensures that it is not possible to have two users with the same name. The Login Form <form action="http://foobar.com/login.php" method="POST"> <p> Username: <input type="text" name="myusername" /></p> <p> Password: <input type="password" name="mypassword" /></p> <p> <input type="submit" /></p> </form> Note that input type="password" prevents a shoulder-surfing attack bydisplaying each typed password character as •. The request is sent via HTTP and the userid and password are sent asplaintext and could be discovered by a attacker eavesdropping on the connection. The Login Script: Connecting To The Database 5 <?php $host="localhost"; // Host name $user="..."; // Mysql username $password="..."; // Mysql password $dbname="CS3511"; // Database name $tbl_name="passwordTable"; // Table name $dbconnection = mysql_connect( $host, $user, $password ); if ( ! $dbconnection ) { output_problem_page(); die(); } // Try to select database $dbselection = mysql_select_db( $dbname ); if ( ! $dbselection ) { output_problem_page(); die(); } ?> The Login Script: Continued, Check Username / Password // DANGER: these **should** be filtered, among other things... $myusername=$_POST[’myusername’]; $mypassword=$_POST[’mypassword’]; $sql="SELECT * FROM $tbl_name WHERE username=’$myusername’ and password=’$mypassword’"; $result=mysql_query($sql); $count=mysql_num_rows($result) if($count==1){ session_start(); header("location:main_page.php"); } else { echo "Wrong Username or Password"; } (we’ll look at how to correctly filter the input and set up the session later) Attacking the Login Script Password Guessing. A malicious user could try ‘likely’ passwords for a given user. This assumes that the attacker knows a valid username. On failure, script should not reveal whether or not username is valid. 6 Dictionary Attack. A malicious user could write an attacking script that tries all possible words from a dictionary as the password for a given user. Passwords should not be words from a dictionary. Brute Force Attack. A malicious user could write an attacking script that tries all possible 8character strings as passwords. This is a large number of tests that may be impractical over a network; however, the malicious user could reduce the search space by trying, for example, just lowercase letters. User should be required to pick long passwords that are a mix of upper/lower case letters, digits, etc. A simple throttling mechanism could be added to the code whereby a login attempt fails if it made within 15 seconds (for example) of a previous failure. Protecting Stored Passwords The web-server stores the username/password pairs in the database table passwordTable. This means that anyone (eg, administrator) who has access to the database can lookup a user’s password. This is not considered good practice. The administrator of the web-site may be able deduce (same?) the passwords you use on other web-sites for which the administrator has no authority. If the web-site is compromised then an attacker will be able to discover user passwords. Remember the principle of least privilege. We would like some way to be able to avoid storing the password while at the same time being able to test whether a user-supplied password is valid. We will use a cryptographic one-way hash function. One Way Hash Function A function h maps arbitrary length value x to fixed length value y such that: Hard to reverse. Given value y not feasible to find x with y = h(x). Collision freeness. Hard to find values x, x′ such that h(x) = h(x′). 7 Unpredictability. The hash value h(x) does not give any information about any part of its operand x. Protecting the Password Database Using One-Way Hash Function Rather than store a user password as cleartext in the database table we store the one-way hash of the password. An attacker who obtains a copy of the database table will not be able to determine the password, as doing so would mean reversing a one-way hash function When checking a submitted password, the login.php script simply hashes the password provided and checks that against the database. ... $myusername=$_POST[’myusername’]; $mypassword=sha1($_POST[’mypassword’]); $sql="SELECT * FROM $tbl_name WHERE username=’$myusername’ and password=’$mypassword’"; $result=mysql_query($sql); ... Finding Passwords from Hash Functions If the attacker has managed to obtain a copy of the (hashed) password database then how might s/he figure out a user’s password? Recall the property: Collision freeness. Hard to find values x, x′ such that h(x) = h(x′). (We’ll see later that this is very important for digital signatures.) If I have a specific x and h(x) and I’m searching for another y such that h(y) = h(x) then the effort required will be about 2n for an n bit hash value. However, if I don’t care about what values x and y are found that have the relationship h(x) = h(y) then we have a good chance of finding some pair 2n/2 due to the Birthday Paradox. For example, we have good chance of finding a pair of messages m and m′ such that md5(m) = md5(m′) with just 264 tests, making it vulnerable to brute-force attack. However, MD5 suffers a serious design flaw which means a collision can be found within 28 operations and recently collisions were found in SHA1 in 263 operations. Currently, SHA256 and SHA512 are considered safe. 8 Pre-computation Dictionary Attack on the (Hashed) Password Table Attacker builds table of dictionary words and corresponding hash values. password aardvark boy ...... hash(password) $1$ac23b37db0039dda62896bb21f312755 $1$653805544e622bacc4cc028613a1358a Attacker merges (join) this table against passwordTable in hope of matching a poorly chosen password. The cost of storing and building a dictionary table is small and the attacker can use multiple dictionaries. Use dictionaries for different languages, Klingon, lines from songs, etc. The attacker can also find users with the same password. This dictionary attack is an example of a pre-computation attack: most of the effort goes into building the dictionary, while the seach/merge is relatively cheap and the dictionary can be re-used. Using Salt to Defend Against Dictionary Attacks Strategy: make it impractical to build a dictionary table. When a password is chosen by the user, a random salt value is generated and hashed with the password. The password table stores the username, the chosen salt and a hash of the salt and password. If the salt is large then building the dictionary table beomes costly. word aardvark aardvark .. boy boy .. salt 0 1 .. 0 1 .. h(saltˆword) $1$29b43ef4c7e4b84ff9f25ea158f46818 $1$263818db1dc48169633a51e04fa0bf98 ..... $1$fc0f90e9b32b460b569c6d27291bc3ba $1$ef90e3e32b460b569c6d2723234aeba ........ Authenticating with HTTP For HTTP authentication the web-server stores a list of userid/passwords. The hash of the password is stored so that an attacker cannot discover a user’s password from the .htpasswd file. 9 The htpasswd tool can be used to generate the correct userid/salt/hashed password entry for Basic HTTP authentication. This generates a random salt value and the htpasswd entry for the given userid and password: userid : salt.md5(salt.password) When a user authenticates under HTTP Basic authentication then the web-server retrieves the user’s entry in the password file, obtains the salt, re-computes md5(salt.password) given the password passed from the browser and compares the result with the stored hash. If Digest HTTP authentication is used then the user/password must be stored differently since the web-server needs to ‘know’ the user’s password in order to check the validity of the user’s response. The htdigest tool can be used to generate the entry for the password file in this case. One Way Hash Function in PHP One way hash functions are also called Message Digests. PHP provides function that implement md5 (V.4 onwards) and sha1 (V.4.3 onwards). When a user first picks a password, a random salt should be generated and the hash of the salt and password stored in the password database. ... $mypassword=$_POST[mypassword]; $salt= openssl_random_pseudo_bytes(2,True); $hpasswd= $sha1($salt.$password); //store the userid, hpassword *and* the salt This uses a secure random (True) salt string of length 2. When the user logs in, the login script looks up the user’s salt, recomputes the hashed salted password and compares the result against the stored value $hpasswd. 10