Digest authentication is designed to be significantly more secure than Basic. It makes extensive use of cryptographic hash functions and other tricks. Essentially, instead of sending a cleartext password, the user-agent sends a "message digest" of the password, username, and other information. (See RFC 2617 and O'Reilly's HTTP: The Definitive Guide for more information.)
HTTP Digest authentication supports the following auth_param parameters:
auth_param digest program command
auth_param digest children number
auth_param digest realm string
auth_param digest nonce_garbage_interval time-specification
auth_param digest nonce_max_duration time-specification
auth_param digest nonce_max_count number
auth_param digest nonce_strictness on|off
The program, children, and realm parameters are the same as for Basic authentication. All of the unique parameters relate to Digest authentication's use of something called nonce.
A nonce is a special string of data, which changes occasionally. During the authentication process, the server (Squid in this case) provides a nonce value to the client. The client uses the nonce value when generating the digest. Without the nonce data, an attacker could simply intercept and replay the digest values to gain access to Squid.
The nonce_garbage_interval parameter tells Squid how often to clean up the nonce cache. The default value is every 5 minutes. A very busy cache with many Digest authentication clients may benefit from more frequent nonce garbage collection.
The nonce_max_duration parameter specifies how long each nonce value remains valid. When a client attempts to use a nonce value older than the specified time, Squid generates a 401 (Unauthorized) response and sends along a fresh nonce value so the client can re-authenticate. The default value is 30 minutes. Note that any captured Authorization headers can be used in a replay attack until the nonce value expires. Setting the nonce_max_duration too low, however, causes Squid to generate 401 responses more often. Each 401 response essentially wastes the user's time as the client and server renegotiate their authentication credentials.
The nonce_max_count parameter places an upper limit on how many times a nonce value may be used. After the specified number of requests, Squid returns a 401 (Unauthorized) response and a new nonce value. The default is 50 requests.
Nonce counts are another feature designed to prevent replay attacks. Squid sends qop=auth in its 401 responses. This causes user-agents to include a nonce count in their requests, and to use the nonce count when generating the digest itself. Nonce count values must always increase over time. A decreasing nonce count indicates a replay attack. However, the counts may increase, but skip some values, for example: 5,6,8,9. The nonce_strictness parameter determines what Squid does in this case. If set to on, Squid returns a 401 response if a nonce count doesn't equal the previous nonce count plus one. If set to off, Squid allows gaps in the nonce count values.
Here is a complete example:
auth_param digest program /usr/local/squid/libexec/digest_pw auth_param digest children 8 auth_param digest realm Access to Squid auth_param digest nonce_garbage_interval 10 minutes auth_param digest nonce_max_duration 45 minutes auth_param digest nonce_max_count 100 auth_param digest nonce_strictness on acl KnownUsers proxy_auth REQUIRED http_access allow KnownUsers
Next I will discuss the Digest authentication helper programs that come with Squid.
./configure enable-auth=digest enable-digest-auth-helpers=password
This is a simple, reference implementation of Digest authentication for Squid. It demonstrates how to write a Digest-based authentication helper. This code simply reads usernames and passwords from a plaintext file. The format of this file is as follows:
The password file pathname is the single argument to the digest_pw_auth program. For example:
auth_param digest program /usr/local/squid/libexec/digest_pw_auth /usr/local/squid/etc/digest_passwd auth_param digest realm Some Nifty Realm
Squid doesn't provide any tools to maintain a password file in this format. If you choose to use Digest authentication, you must manage the file on your own, perhaps with a text editor or Perl scripts.
If you'd like to write your own Digest authentication helper, you need to understand the communication between Squid and the helper process. The exchange is similar to that for Basic authentication, albeit a little more complicated.
The first difference is that Squid writes the username and realm string, rather than username and password, to the helper process. These strings are quoted and separated by a colon. For example:
"bobby":"Tom Landry Middle School"
The second difference is that the helper process returns an MD5 digest string, rather than OK, if the username is valid. As with Basic authentication, the helper process writes ERR if the user doesn't exist or if the input from Squid is unparseable for some reason.
The helper returns an MD5 digest with the username, realm, and password. The three strings are concatenated together and separated by colons:
Remember that the password isn't sent in the HTTP request. Rather, the helper retrieves the user's password from a database (like the plaintext file used by the password helper). For example, let's say that Bobby's password is CapeRs. The helper process receives the username and realm from Squid, gets the password from its database, and calculates an MD5 checksum of this string:
bobby:Tom Landry Middle School:CapeRs
The Squid source code includes a library function, DigestCalcHA1( ), which implements this calculation. We can test all this in a terminal window to see what the helper returns:
% echo 'bobby:CapeRs' > /tmp/pw % echo bogus_input | digest_pw_auth /tmp/pw ERR % echo "nouser":"some realm" | digest_pw_auth /tmp/pw ERR % echo '"bobby":"Tom Landry Middle School"' | digest_pw_auth /tmp/pw c7ca3efda238c65b2d48684a51baa90e
Squid stores this MD5 checksum and uses it in other parts of the Digest authentication algorithm. Note that the checksum only changes when the user changes his password. In Squid's current Digest implementation, these checksums are kept in memory as long as the user remains active. If the user is inactive for authenticate_ttl seconds, the MD5 checksum may be removed from Squid's memory. Upon the next request from that user, Squid asks the external helper process to calculate it again.