7.2. Authentication Methods
This section discusses three widely deployed authentication methods:
The first two are built into the HTTP protocol and defined in RFC 2617, "HTTP Authentication: Basic and Digest Access Authentication" (http://www.ietf.org/rfc/rfc2617.txt). Form-based authentication is a way of moving the authentication problem from a web server to the application.
Other authentication methods exist (Windows NT challenge/response authentication and the Kerberos-based Negotiate protocol), but they are proprietary to Microsoft and of limited interest to Apache administrators.
7.2.1. Basic Authentication
Authentication methods built into HTTP use headers to send and receive authentication-related information. When a client attempts to access a protected resource the server responds with a challenge. The response is assigned a 401 HTTP status code, which means that authentication is required. (HTTP uses the word "authorization" in this context but ignore that for a moment.) In addition to the response code, the server sends a response header WWW-Authenticate, which includes information about the required authentication scheme and the authentication realm. The realm is a case-insensitive string that uniquely identifies (within the web site) the protected area. Here is an example of an attempt to access a protected resource and the response returned from the server:
$ telnet www.apachesecurity.net 80 Trying 18.104.22.168... Connected to www.apachesecurity.net. Escape character is '^]'. GET /review/ HTTP/1.0 Host: www.apachesecurity.net HTTP/1.1 401 Authorization Required Date: Thu, 09 Sep 2004 09:55:07 GMT WWW-Authenticate: Basic realm="Book Review" Connection: close Content-Type: text/html
The first HTTP 401 response returned when a client attempts to access a protected resource is normally not displayed to the user. The browser reacts to such a response by displaying a pop-up window, asking the user to type in the login credentials. After the user enters her username and password, the original request is attempted again, this time with more information.
$ telnet www.apachesecurity.net 80 Trying 22.214.171.124... Connected to www.apachesecurity.net. Escape character is '^]'. GET /review/ HTTP/1.0 Host: www.apachesecurity.net Authorization: Basic aXZhbnI6c2VjcmV0 HTTP/1.1 200 OK Date: Thu, 09 Sep 2004 10:07:05 GMT Connection: close Content-Type: text/html
The browser has added an Authorization request header, which contains the credentials collected from the user. The first part of the header value contains the authentication scheme (Basic in this case), and the second part contains a base-64 encoded combination of the username and the password. The aXZhbnI6c2VjcmV0 string from the header decodes to ivanr:secret. (To experiment with base-64 encoding, use the online encoder/decoder at http://makcoder.sourceforge.net/demo/base64.php.) Provided valid credentials were supplied, the web server proceeds with the request normally, as if authentication was not necessary.
Nothing in the HTTP protocol suggests a web server should remember past authentication requests, regardless of if they were successful. As long as the credentials are missing or incorrect, the web server will keep responding with status 401. This is where some browsers behave differently than others. Mozilla will keep prompting for credentials indefinitely. Internet Explorer, on the other hand, gives up after three times and displays the 401 page it got from the server. Being "logged in" is only an illusion provided by browsers. After one request is successfully authenticated, browsers continue to send the login credentials until the session is over (i.e., the user closes the browser).
Basic authentication is not an ideal authentication protocol. It has a number of disadvantages:
7.2.2. Digest Authentication
The major purpose of Digest authentication is to allow authentication to take place without sending user credentials to the server in plaintext. Instead, the server sends the client a challenge. The client responds to the challenge by computing a hash of the challenge and the password, and sends the hash back to the server. The server uses the response to determine if the client possesses the correct password.
The increased security of Digest authentication makes it more complex, so I am not going to describe it here in detail. As with Basic authentication, it is documented in RFC 2617, which makes for interesting reading. The following is an example of a request successfully authenticated using Digest authentication:
$ telnet www.apachesecurity.net 80 Trying 126.96.36.199... Connected to www.apachesecurity.net. Escape character is '^]'. GET /review/ HTTP/1.1 Host: www.apachesecurity.net Authorization: Digest username="ivanr", realm="Book Review", nonce="OgmPjb/jAwA=7c5a49c2ed9416dba1b04b5307d6d935f74a859d", uri="/review/", algorithm=MD5, response="3c430d26043cc306e0282635929d57cb", qop=auth, nc=00000004, cnonce="c3bcee9534c051a0" HTTP/1.1 200 OK Authentication-Info: rspauth="e18e79490b380eb645a3af0ff5abf0e4", cnonce="c3bcee9534c051a0", nc=00000004, qop=auth Connection: close Content-Type: text/html
Though Digest authentication succeeds in its goal, its adoption on the server side and on the client side was (is) very slow, most likely because it was never deemed significantly better than Basic authentication. It took years for browsers to start supporting it fully. In Apache, the mod_auth_digest module used for Digest authentication (described later) is still marked "experimental." Consequently, it is rarely used today.
Digest authentication suffers from several weaknesses:
Engaging in secure, authenticated communication when using an unencrypted channel is impossible. Once you add SSL to the server (see Chapter 4), it corrects most of the problems people have had with Basic authentication. If using SSL is not an option, then deployment of Digest authentication is highly recommended. There are many freely available tools that allow almost anyone (since no technical knowledge is required) to automatically collect Basic authentication passwords from the traffic flowing on the network. But I haven't seen any tools that automate the process of performing a replay attack when Digest authentication is used. The use of Digest authentication at least raises the bar to require technical skills on the part of the attacker.
There is one Digest authentication feature that is very interesting: server authentication. As of RFC 2617 (which obsoletes RFC 2609), clients can use Digest authentication to verify that the server does know their password. Sounds like a widespread use of Digest authentication could help the fight against numerous phishing attacks that take place on the Internet today (see Chapter 10).
7.2.3. Form-Based Authentication
In addition to the previously mentioned problems with HTTP-based authentication, there are further issues:
Since applications must invest significant resources for handling sessions and authorization anyway, it makes sense to shift the rest of the responsibility their way. This is what form-based authentication does. As a bonus, the boundary between programmers' and system administrators' responsibilities is better defined.
Form-based authentication is not a protocol since every application is free to implement access control any way it chooses (except in the Java camp, where form-based authentication is a part of the Servlets specification). In response to a request from a user who has not yet authenticated herself, the application sends a form (hence the name form-based) such as the one created by the following HTML:
<form action="/login.php" method="POST"> <input type="text" name="username"><br> <input type="password" name="password"><br> <input type="submit" value="Submit"><br> </form>
The user is expected to fill in appropriate username and password values and select the Submit button. The script login.php then examines the username and password parameters and decides whether to let the user in or send her back to the login form.
HTTP-based authentication does not necessarily need to be implemented on the web server level. Applications can use it for their purposes. However, since that approach has limitations, most applications implement their own authentication schemes. This is unfortunate because most developers are not security experts, and they often design inadequate access control schemes, which lead to insecure applications.
Authentication features built into Apache (described below) are known to be secure because they have stood the test of time. Users (and potential intruders) are not allowed to interact with an application if they do not authenticate themselves first. This can be a great security advantage. When authentication takes place at the application level (instead of the web-server level), the intruder has already passed one security layer (that of the web server). Applications are often given far less testing than the web server and potentially contain more security issues. Some files in the application, for example, may not be protected at all. Images are almost never protected. Often applications contain large amounts of code that are executed prior to authentication. The chances of an intruder finding a hole are much higher when application-level authentication is used.