RFC 2069
An Extension to HTTP : Digest Access Authentication
Introduction โจ
Who, what, when ๐
This doc is from the Network Working Group, and the lineup is iconic: J. Franks from Northwestern University, P. Hallam-Baker from CERN, J. Hostetler and E. Sink from Spyglass, Inc., P. Leach from Microsoft Corporation, A. Luotonen from Netscape Communications Corporation, and L. Stewart from Open Market, Inc. ๐ It's RFC 2069, it's on the Standards Track, it was published in January 1997, and it's titled "An Extension to HTTP : Digest Access Authentication." The header doesn't list anything it obsoletes or updates, so there's no drama there. ๐ธ
Status of This Memo ๐
This is an Internet standards track protocol for the Internet community, and the authors are asking for discussion and suggestions for improvements ๐ซถ If you want to know where it stands in the standardization process, check the current edition of the "Internet Official Protocol Standards" (STD 1). Distribution is unlimited, so share away! ๐ฆ
Abstract ๐
So "HTTP/1.0" has a Basic Access Authentication scheme, and honestly? Not a secure move. The user name and password get sent over the network as clear text ๐ญ That's the big problem, and it needs a new scheme to fix it. Enter Digest Access Authentication โจ Like Basic, Digest checks that both sides know a shared secret (a password), but the big glow-up is that the password never has to go over the wire in the clear. ๐ And just like most auth protocols, the real risks usually live in the policies and procedures around the thing, not in the core protocol itself ๐
Table of Contents
INTRODUCTION...................................................... 2
1.1 PURPOSE .................................................... 2
1.2 OVERALL OPERATION .......................................... 3
1.3 REPRESENTATION OF DIGEST VALUES ............................ 3
1.4 LIMITATIONS ................................................ 3
2. DIGEST ACCESS AUTHENTICATION SCHEME............................ 3
2.1 SPECIFICATION OF DIGEST HEADERS ............................. 3
2.1.1 THE WWW-AUTHENTICATE RESPONSE HEADER ..................... 4
2.1.2 THE AUTHORIZATION REQUEST HEADER ......................... 6
2.1.3 THE AUTHENTICATION-INFO HEADER ........................... 9
2.2 DIGEST OPERATION ............................................ 10
2.3 SECURITY PROTOCOL NEGOTIATION ............................... 10
2.4 EXAMPLE ..................................................... 11
2.5 PROXY-AUTHENTICATION AND PROXY-AUTHORIZATION ................ 11
3. SECURITY CONSIDERATIONS........................................ 12
3.1 COMPARISON WITH BASIC AUTHENTICATION ........................ 13
3.2 REPLAY ATTACKS .............................................. 13
3.3 MAN IN THE MIDDLE ........................................... 14
3.4 SPOOFING BY COUNTERFEIT SERVERS ............................. 15
3.5 STORING PASSWORDS ........................................... 15
3.6 SUMMARY ..................................................... 16
4. ACKNOWLEDGMENTS............................................... 16
5. REFERENCES..................................................... 16
6. AUTHORS' ADDRESSES............................................. 17
Introduction โจ
1.1. Purpose ๐ญ
So "HTTP/1.0" includes a Basic Access Authentication scheme [1]. Basic isn't considered secure, because the user name and password are passed over the network in an unencrypted form ๐ฌ Future HTTP versions need a new authentication scheme, and this document is that scheme, called "Digest Access Authentication" ๐
Digest is not the full answer to web security. It doesn't encrypt object content at all. The goal is just a weak access authentication method that dodges the worst flaws of Basic ๐ซถ
It's also proposed that this access authentication scheme be included in the proposed HTTP/1.1 specification ๐ง
1.2. Overall Operation ๐ฆ
Digest is based on the same simple challenge-response idea as Basic. The server challenges with a nonce value, and a valid response has a checksum (by default the MD5 checksum) of the username, the password, the given nonce value, the HTTP method, and the requested URI. So the password is never sent in the clear ๐ Just like Basic, the username and password need to be set up ahead of time somehow, and this document doesn't cover how ๐
1.3. Representation of digest values ๐ธ
A header is optional, and it lets the server specify the algorithm used to create the checksum or digest. By default, that's MD5, and MD5 is the only algorithm described in this document ๐
Here's the formatting tea โ An MD5 digest is 128 bits, and it gets represented as 32 ASCII printable characters. You convert the bits from most significant to least significant, four bits at a time, into their ASCII version. Each group of four bits becomes its hexadecimal character from 0123456789abcdef. So binary 0000 is '0', 0001 is '1', and it keeps going up to 1111 being 'f' โจ
1.4. Limitations ๐
Real talk: this scheme has a lot of known limitations. It's meant as a replacement for basic authentication and nothing more ๐
It's a password-based system, and on the server side it has all the same problems any password system has. Specifically, this protocol doesn't handle the initial secure setup between user and server to establish the user's password ๐
Users and implementors should know this protocol isn't as secure as Kerberos, and it isn't as secure as any client-side private-key scheme either. BUT it's still better than nothing, better than what people commonly use with telnet and ftp, and better than Basic authentication ๐ซถ Not perfect, but it's a glow-up ๐
2. Digest Access Authentication Scheme ๐
2.1. Specification of Digest Headers ๐
Digest is conceptually similar to Basic. The modified WWW-Authenticate header line and the Authorization header line are specified below, using the extended BNF defined in the HTTP/1.1 specification, section 2.1. On top of that, there's a brand new header called Authentication-info ๐
2.1.1 The WWW-Authenticate Response Header โจ
okay so bestie, this is the server going "hold up, who even are you? ๐ " ๐ If a server gets a request for an access-protected object and there's no acceptable Authorization header, it fires back a "401 Unauthorized" status code plus a WWW-Authenticate header ๐ฆ Here's the layout:
WWW-Authenticate = "WWW-Authenticate" ":" "Digest"
digest-challenge
digest-challenge = 1#( realm | [ domain ] | nonce |
[ digest-opaque ] |[ stale ] | [ algorithm ] )
realm = "realm" "=" realm-value
realm-value = quoted-string
domain = "domain" "=" <"> 1#URI <">
nonce = "nonce" "=" nonce-value
nonce-value = quoted-string
opaque = "opaque" "=" quoted-string
stale = "stale" "=" ( "true" | "false" )
algorithm = "algorithm" "=" ( "MD5" | token )
Now let's talk about what each parameter actually means ๐ธ
realm This is the string that gets shown to users so they know which username and password to use ๐ It should contain at least the name of the host doing the authentication, and it might also say which group of users can get in. The example they give is "registered_users@gotham.news.com" ๐ฆ The realm is a "quoted-string" as specified in section 2.2 of the HTTP/1.1 specification [2].
domain This is a comma-separated list of URIs, the same way it works for HTTP/1.0 ๐ The idea is that the client can use it to figure out the set of URIs that should get the same authentication info. The URIs in this list can live on different servers, which is kinda iconic โจ If this keyword is left out or empty, the client should assume the domain is every URI on the responding server.
nonce This is a server-specified data string that may be uniquely generated every single time a 401 response goes out ๐ฒ It's recommended that this string be base64 or hexadecimal data. Since the string gets passed in the header lines as a quoted string, the double-quote character is not allowed, so no sneaking those in ๐
The contents of the nonce are implementation dependent, and the quality of the implementation depends on making a good choice here ๐ A recommended nonce would include:
H(client-IP ":" time-stamp ":" private-key )
where client-IP is the dotted quad IP address of the client making the request, time-stamp is a server-generated time value, and private-key is data known only to the server ๐ With a nonce of this form, the server would normally recalculate the nonce after receiving the client's authentication header, and it would reject the request if the result didn't match the nonce from that header. This is how the server can limit reuse of a nonce to the IP address it was issued to, and also limit how long the nonce stays valid โฐ More on the rationale for building nonces is in section 3.2 below.
An implementation might choose not to accept a previously used nonce or a previously used digest, to protect against a replay attack ๐ก๏ธ Or it might use one-time nonces or digests for POST or PUT requests, and a time-stamp for GET requests. For more details on the issues involved, see section 3. of this document ๐
The nonce is opaque to the client ๐ซถ
opaque This is a string of data, specified by the server, that the client should send back unchanged ๐ It's recommended that this string be base64 or hexadecimal data. This field is a "quoted-string" as specified in section 2.2 of the HTTP/1.1 specification [2].
stale This is a flag that says the client's previous request was rejected because the nonce value was stale ๐ฅ If stale is TRUE (in upper or lower case), the client may just want to retry the request with a new encrypted response, without making the user type in a new username and password again ๐ The server should only set stale to true if it gets a request where the nonce is invalid but the digest for that nonce is valid. That combo tells the server the client knows the correct username and password ๐ฅ
algorithm This is a string naming a pair of algorithms: one used to produce the digest and one used to produce a checksum ๐งฎ If it's not present, it's assumed to be "MD5". In this document, the string you get by applying the digest algorithm to the data "data" with the secret "secret" is written as KD(secret, data), and the string you get by applying the checksum algorithm to the data "data" is written as H(data) ๐
For the "MD5" algorithm:
H(data) = MD5(data)
and
KD(secret, data) = H(concat(secret, ":", data))
i.e., the digest is the MD5 of the secret, concatenated with a colon, concatenated with the data ๐
2.1.2 The Authorization Request Header ๐ฆ
The client is expected to retry the request, this time passing an Authorization header line, which is defined as follows ๐
Authorization = "Authorization" ":" "Digest" digest-response
digest-response = 1#( username | realm | nonce | digest-uri |
response | [ digest ] | [ algorithm ] |
opaque )
username = "username" "=" username-value
username-value = quoted-string
digest-uri = "uri" "=" digest-uri-value
digest-uri-value = request-uri ; As specified by HTTP/1.1
response = "response" "=" response-digest
digest = "digest" "=" entity-digest
response-digest = <"> *LHEX <">
entity-digest = <"> *LHEX <">
LHEX = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" |
"8" | "9" | "a" | "b" | "c" | "d" | "e" | "f"
The definitions of response-digest and entity-digest above show the encoding for their values. The following definitions show how the value gets computed ๐ง
response-digest =
<"> < KD ( H(A1), unquoted nonce-value ":" H(A2) > <">
A1 = unquoted username-value ":" unquoted realm-value
":" password
password = < user's password >
A2 = Method ":" digest-uri-value
The "username-value" field is a "quoted-string" as specified in section 2.2 of the HTTP/1.1 specification [2]. However, the surrounding quotation marks are removed when forming the string A1 โ๏ธ So if the Authorization header includes these fields:
username="Mufasa", realm="myhost@testrealm.com"
and the user Mufasa has the password "CircleOfLife", then H(A1) would be H(Mufasa:myhost@testrealm.com:CircleOfLife), with no quotation marks in the digested string ๐
No white space is allowed in any of the strings the digest function H() is applied to, unless that white space exists in the quoted strings or entity body that make up the string being digested ๐
โโ๏ธ For example, the string A1 in the illustration above must be Mufasa:myhost@testrealm.com:CircleOfLife with no white space on either side of the colons. Likewise, the other strings digested by H() must not have white space on either side of the colons that delimit their fields, unless that white space was in the quoted strings or entity body being digested.
"Method" is the HTTP request method as specified in section 5.1 of [2]. The "request-uri" value is the Request-URI from the request line, as specified in section 5.1 of [2] ๐ It may be "*", an "absoluteURL" or an "abs_path" as specified in section 5.1.2 of [2], but it MUST agree with the Request-URI. In particular, it MUST be an "absoluteURL" if the Request-URI is an "absoluteURL" ๐
The authenticating server must make sure that the document designated by the "uri" parameter is the same as the document it serves ๐ต๏ธโโ๏ธ Duplicating information from the request URL in this field is there to deal with the possibility that an intermediate proxy alters the client's request. That altered (but presumably semantically equivalent) request would not produce the same digest as the one the client calculated ๐
The optional "digest" field contains a digest of the entity body and some of the associated entity headers ๐ This digest can be useful in both request and response transactions. In a request, it can help insure the integrity of POST data or data being PUT to the server. In a response, it insures the integrity of the served document ๐ The value of the "digest" field is an <entity-digest>, defined as follows:
entity-digest = <"> KD (H(A1), unquoted nonce-value ":" Method ":"
date ":" entity-info ":" H(entity-body)) <">
; format is <"> *LHEX <">
date = = rfc1123-date ; see section 3.3.1 of [2]
entity-info = H(
digest-uri-value ":"
media-type ":" ; Content-type, see section 3.7 of [2]
*DIGIT ":" ; Content length, see 10.12 of [2]
content-coding ":" ; Content-encoding, see 3.5 of [2]
last-modified ":" ; last modified date, see 10.25 of [2]
expires ; expiration date; see 10.19 of [2]
)
last-modified = rfc1123-date ; see section 3.3.1 of [2]
expires = rfc1123-date
The entity-info elements bring in the values of the URI used to request the entity, plus the associated entity headers Content-type, Content-length, Content-encoding, Last-modified, and Expires ๐จ These headers are all end-to-end headers (see section 13.5.1 of [2]) that must not be modified by proxy caches. The "entity-body" is as specified by section 10.13 of [2] or RFC 1864 ๐ฆ
Note that not every entity will have an associated URI or all of these headers ๐ฅบ For example, an entity that is the data of a POST request will typically not have a digest-uri-value, or Last-modified or Expires headers. If an entity doesn't have a digest-uri-value or a header matching one of the entity-info fields, that field is left empty in the computation of entity-info. All the colons specified above are still present, though ๐ For example, the entity-info for POST data with content-type "text/plain", no content-encoding, and a length of 255 bytes would be:
H(:text/plain:255:::)
Similarly, a request may not have a "Date" header. In that case, the date field of the entity-digest should be empty ๐
In the entity-info and entity-digest computations, there must be no white space between "words" and "tspecials", and exactly one blank between "words", except for the blank after the comma in "rfc1123-date" (see section 2.2 of [2]) ๐
Implementors should be aware of how authenticated transactions interact with proxy caches ๐จ The HTTP/1.1 protocol specifies that when a shared cache (see section 13.10 of [2]) has received a request containing an Authorization header and a response from relaying that request, it MUST NOT return that response as a reply to any other request, unless one of two Cache-control (see section 14.9 of [2]) directives was present in the response. If the original response included the "must-revalidate" Cache-control directive, the cache MAY use the entity of that response in replying to a subsequent request, but it MUST first revalidate it with the origin server, using the request headers from the new request so the origin server can authenticate the new request ๐ Alternatively, if the original response included the "public" Cache-control directive, the response entity MAY be returned in reply to any subsequent request ๐
2.1.3 The AuthenticationInfo Header โจ
okay so when authentication SUCCEEDS ๐ฅณ, the Server MAY optionally send an Authentication-info header to say something useful, like an entity digest or a brand new nonce for the next round. it has two fields, digest and nextnonce, and BOTH are optional bestie ๐
AuthenticationInfo = "Authentication-info" ":"
1#( digest | nextnonce )
nextnonce = "nextnonce" "=" nonce-value
digest = "digest" "=" entity-digest
the digest field lets the client check that the response body didn't get messed with on the way over ๐ต๏ธโโ๏ธ the server would probably only send this when it actually has the document and can compute the digest. it would probably skip this header for CGI output, tbh ๐ the value of "digest" is an <entity-digest>, computed the way we talked about above ๐ง
the nextnonce field is the nonce the server wants the client to use for the NEXT authentication response. remember either field is optional!! the server can send the Authentication-info header with ONLY nextnonce, which is how it does one-time nonces ๐ฆ and if nextnonce shows up, the client is strongly encouraged to use it in the next WWW-Authenticate header. if the client doesn't, the server might ask it to re-authenticate with stale=TRUE. ngl that's a whole plot twist ๐ญ
2.2 Digest Operation ๐
when the server gets an Authorization header, it MAY check that it's valid by looking up the known password for the submitted username ๐ then the server MUST run the same MD5 operation the client ran and compare the result to the given response-digest. it's giving detective energy fr ๐ต๏ธโโ๏ธ
the HTTP server doesn't actually need to know the user's clear text password ๐คซ as long as H(A1) is available to the server, the validity of an Authorization header MAY be verified. iconic, honestly ๐
a client MAY remember the username, password and nonce values, so future requests inside the specified <domain> can include the Authorization header preemptively ๐ the server MAY accept the old Authorization header info even if the nonce isn't fresh anymore. or it could send back a 401 with a new nonce, and the client retries the request. when the server adds stale=TRUE to that response, it's basically saying "retry with the new nonce, no need to bug the user for a username and password again" ๐
the opaque data is for carrying state info around ๐ example: a server might be in charge of authenticating content that actually lives on a different server. the first 401 response could include a domain field with the URI on that second server, plus the opaque field for state info. the client retries, and then the server MAY reply with a 301/302 redirect pointing at the URI on the second server. the client follows the redirect and passes the same Authorization header, including the <opaque> data the second server might need โจ
just like with the basic scheme, proxies MUST be completely transparent in the Digest access authentication scheme ๐ซถ meaning they MUST forward the WWW-Authenticate, Authentication-info and Authorization headers untouched. if a proxy wants to authenticate a client BEFORE the request goes to the server, it can do that with the Proxy-Authenticate and Proxy-Authorization headers from section 2.5 below ๐ธ
2.3 Security Protocol Negotiation ๐ฆ
it's really useful for a server to know which security schemes a client can handle ๐
if this proposal gets accepted as a required part of the HTTP/1.1 specification, a server MAY assume Digest support when a client says it's HTTP/1.1 compliant โ
it's possible a server might want to REQUIRE Digest as its authentication method, even if it doesn't know the client supports it ๐ฌ a client is encouraged to fail gracefully if the server asks for any authentication scheme it can't handle. graceful failing is a whole aesthetic ๐
2.4 Example ๐
this example assumes someone is requesting an access-protected document ๐ the URI of the document is http://www.nowhere.org/dir/index.html. both client and server know the username for this document is "Mufasa" and the password is "CircleOfLife" ๐ (the lion king reference is not an accident, periodt ๐ฆ)
the first time the client asks for the document, there's no Authorization header, so the server responds with:
HTTP/1.1 401 Unauthorized
WWW-Authenticate: Digest realm="testrealm@host.com",
nonce="dcd98b7102dd2f0e8b11d0f600bfb0c093",
opaque="5ccc069c403ebaf9f0171e9517f40e41"
the client MAY prompt the user for the username and password. after that it sends a new request with this Authorization header:
Authorization: Digest username="Mufasa",
realm="testrealm@host.com",
nonce="dcd98b7102dd2f0e8b11d0f600bfb0c093",
uri="/dir/index.html",
response="e966c932a9242554e42c8ee200cec7f6",
opaque="5ccc069c403ebaf9f0171e9517f40e41"
2.5 Proxy-Authentication and Proxy-Authorization ๐
the digest scheme MAY also be used to authenticate users to proxies, proxies to proxies, or proxies to end servers, using the Proxy-Authenticate and Proxy-Authorization headers ๐ง these are instances of the general Proxy-Authenticate and Proxy-Authorization headers from sections 10.30 and 10.31 of the HTTP/1.1 specification [2], and their behavior is subject to the restrictions described there ๐ the proxy auth transactions are basically the same vibe as the ones we already covered ๐
upon receiving a request that needs authentication, the proxy/server MUST issue the "HTTP/1.1 401 Unauthorized" header, followed by a "Proxy-Authenticate" header of this form:
Proxy-Authentication = "Proxy-Authentication" ":" "Digest"
digest-challenge
where digest-challenge is as defined above in section 2.1. the client/proxy MUST then re-issue the request with a Proxy-Authenticate header of this form:
Proxy-Authorization = "Proxy-Authorization" ":"
digest-response
where digest-response is as defined above in section 2.1. when authentication succeeds, the Server MAY optionally provide a Proxy-Authentication-info header of this form:
Proxy-Authentication-info = "Proxy-Authentication-info" ":" nextnonce
where nextnonce has the same semantics as the nextnonce field in the Authentication-info header described above in section 2.1 โจ
here's a plot twist ๐ a client could be asked to authenticate itself to BOTH a proxy AND an end-server. it might get an "HTTP/1.1 401 Unauthorized" header followed by both a WWW-Authenticate and a Proxy-Authenticate header. however, it can NEVER receive more than one Proxy-Authenticate header, since those headers are only for immediate connections and MUST NOT be passed on by proxies ๐ if the client gets both headers, it MUST respond with both the Authorization and Proxy-Authorization headers as described above, which will likely involve different combos of username, password, nonce, etc. it's a lot, but we can handle it ๐ช
3. Security Considerations ๐ฅ
okay real talk bestie, Digest Authentication does NOT provide a strong authentication mechanism ๐ญ that was never the goal. it's meant to replace something much weaker and even more dangerous: Basic Authentication ๐ an important design constraint was that the new scheme be free of patent and export restrictions ๐
most needs for secure HTTP transactions can't be met by Digest Authentication ๐ซ for those, SSL or SHTTP are more appropriate protocols. digest authentication can't be used for any transaction that requires encrypted content. still, there are plenty of functions where digest authentication is both useful and appropriate ๐
3.1 Comparison with Basic Authentication ๐
both Digest and Basic Authentication are very much on the weak end of the security strength spectrum ๐ฌ but comparing them shows why it's useful, even necessary, to replace Basic with Digest.
the biggest threat to these kinds of transactions is network snooping ๐ for example, online access to a database that's only for paying subscribers. with Basic authentication, an eavesdropper can get the user's password ๐ฑ that lets them into everything in the database, and, honestly worse, into anything else the user protects with the same password. it's a whole disaster ๐
with Digest Authentication, the eavesdropper only gets access to the transaction in question, NOT the user's password ๐ซถ the info they gain WOULD allow a replay attack, but only with a request for the same document, and even that might be difficult ๐ง security is giving "one-hit wonder" energy and I'm here for it โจ
3.2. Replay Attacks ๐
Okay so a replay attack against digest auth is usually pointless for a simple GET request ๐ Like, the eavesdropper already saw the only doc they could get with a replay, because the URI of the requested doc gets digested into the client response and the server will only deliver that doc. Compare that to Basic Authentication, where once the eavesdropper has the user's password, every doc protected by it is open to them ๐ A GET with form data could only be "replayed" with the identical data. Still, it could be a problem if it made a CGI script do something on the server ๐
So for some purposes, you really do need to protect against replay attacks ๐ก๏ธ A good digest implementation can do that in a few different ways. The server-created nonce value is implementation dependent, but if it contains a digest of the client IP, a time-stamp, and a private server key (as recommended above), then a replay attack is not simple. The attacker has to convince the server that the request is coming from a false IP address, and has to make the server deliver the doc to an IP address that's different from the one the server thinks it's sending to. The attack can only work in the period before the time-stamp expires. Digesting the client IP and time-stamp into the nonce means you can have an implementation that doesn't keep state between transactions, which is so clean โจ
For apps where no possibility of replay attack can be tolerated, the server can use one-time response digests that won't be honored for a second use. This means the server has to remember which digests have been used until the nonce time-stamp (and so the digest built with it) has expired, which is extra overhead, but it effectively protects against replays ๐ช Instead of keeping a list of the values of used digests, a server would hash these values and require re-authentication whenever a hash collision occurs.
โ ๏ธ POST and PUT requests need special attention! A successful replay could result in counterfeit form data or a counterfeit version of a PUT file. The use of one-time digests or one-time nonces is recommended. It is also recommended that the optional <digest> be implemented for use with POST or PUT requests to assure the integrity of the posted data. Alternatively, a server may choose to allow digest authentication only with GET requests. Responsible server implementors will document the risks described here as they pertain to a given implementation ๐ซถ
3.3. Man in the Middle ๐ต๏ธโโ๏ธ
Both Basic and Digest authentication are vulnerable to "man in the middle" attacks, for example from a hostile or compromised proxy. Obviously this brings all the problems of eavesdropping, but it could also give the attacker some extra threats ๐ค
A simple but effective attack would be to replace the Digest challenge with a Basic challenge, which tricks the client into revealing their password ๐ To protect against this, clients should remember if a site has used Digest authentication in the past, and warn the user if the site stops using it. It might also be a good idea for the browser to be configured to demand Digest authentication in general, or from specific sites ๐
Or, a hostile proxy might spoof the client into making a request the attacker wanted instead of one the client wanted. Of course, this is still much harder than a comparable attack against Basic Authentication ๐
There are several attacks on the "digest" field in the Authentication-info header. A simple but effective one is just removing the field, so the client can't use it to detect modifications to the response entity. Sensitive applications may wish to allow configuration that requires the digest field to be present when appropriate. More subtly, the attacker can alter any of the entity-headers that aren't incorporated in the computation of the digest. The attacker can alter most of the request headers in the client's request, and can alter any response header in the origin-server's reply, except those headers whose values are incorporated into the "digest" field ๐ง
Alteration of Accept* or User-Agent request headers can only result in a denial of service attack that returns content in an unacceptable media type or language ๐ Alteration of cache control headers can also only result in denial of service. Alteration of Host will be detected, if the full URL is in the response-digest ๐ฏ Alteration of Referer or From is not important, as these are only hints ๐ซ
3.4. Spoofing by Counterfeit Servers ๐ญ
Basic Authentication is vulnerable to spoofing by counterfeit servers ๐ฌ If a user can be led to believe she's connecting to a host containing information protected by a password she knows, when in fact she's connecting to a hostile server, then the hostile server can request a password, store it away for later use, and feign an error. This type of attack is more difficult with Digest Authentication, but the client must know to demand that Digest authentication be used, perhaps using some of the techniques described above to counter "man-in-the-middle" attacks ๐
3.5. Storing passwords ๐๏ธ
Digest authentication requires that the authenticating agent (usually the server) store some data derived from the user's name and password in a "password file" associated with a given realm. Normally this might contain pairs consisting of username and H(A1), where H(A1) is the digested value of the username, realm, and password as described above ๐
The security implications of this are that if this password file is compromised, an attacker gains immediate access to documents on the server using this realm ๐ฑ Unlike, say, a standard UNIX password file, this information doesn't need to be decrypted in order to access documents in the server realm associated with this file. On the other hand, decryption (or, more likely, a brute force attack) would be necessary to obtain the user's password. This is the reason the realm is part of the digested data stored in the password file. It means that if one digest authentication password file is compromised, it does not automatically compromise others with the same username and password (though it does expose them to brute force attack) ๐ง
There are two important security consequences of this. First, the password file must be protected as if it contained unencrypted passwords, because for the purpose of accessing documents in its realm, it effectively does ๐จ
A second consequence is that the realm string should be unique among all realms which any single user is likely to use. In particular, a realm string should include the name of the host doing the authentication. The inability of the client to authenticate the server is a weakness of Digest Authentication ๐ฅฒ
3.6. Summary ๐
By modern cryptographic standards, Digest Authentication is weak. But for a large range of purposes it's valuable as a replacement for Basic Authentication ๐ธ It remedies many, but not all, weaknesses of Basic Authentication. Its strength may vary depending on the implementation. In particular, the structure of the nonce (which depends on the server implementation) may affect the ease of mounting a replay attack. A range of server options is appropriate, since for example some implementations may be willing to accept the server overhead of one-time nonces or digests to eliminate the possibility of replay, while others may be satisfied with a nonce like the one recommended above, restricted to a single IP address and with a limited lifetime ๐ฆ
๐ The bottom line is that any compliant implementation will be relatively weak by cryptographic standards, but any compliant implementation will be far superior to Basic Authentication. Iconic. Periodt. ๐
4. Acknowledgments ๐ซถ
In addition to the authors, valuable discussion instrumental in creating this document has come from Peter J. Churchyard, Ned Freed, and David M. Kristol ๐
5. References ๐
[1] Berners-Lee, T., Fielding, R., and H. Frystyk, "Hypertext Transfer Protocol -- HTTP/1.0", RFC 1945, May 1996.
[2] Berners-Lee, T., Fielding, R., and H. Frystyk, "Hypertext Transfer Protocol -- HTTP/1.1" RFC 2068, January 1997.
[3] Rivest, R., "The MD5 Message-Digest Algorithm", RFC 1321, April 1992.
6. Authors' Addresses ๐
John Franks
Professor of Mathematics
Department of Mathematics
Northwestern University
Evanston, IL 60208-2730, USA
EMail: john@math.nwu.edu
Phillip M. Hallam-Baker
European Union Fellow
CERN
Geneva
Switzerland
EMail: hallam@w3.org
Jeffery L. Hostetler
Senior Software Engineer
Spyglass, Inc.
3200 Farber Drive
Champaign, IL 61821, USA
EMail: jeff@spyglass.com
Paul J. Leach
Microsoft Corporation
1 Microsoft Way
Redmond, WA 98052, USA
EMail: paulle@microsoft.com
Ari Luotonen
Member of Technical Staff
Netscape Communications Corporation
501 East Middlefield Road
Mountain View, CA 94043, USA
EMail: luotonen@netscape.com
Eric W. Sink
Senior Software Engineer
Spyglass, Inc.
3200 Farber Drive
Champaign, IL 61821, USA
EMail: eric@spyglass.com
Lawrence C. Stewart
Open Market, Inc.
215 First Street
Cambridge, MA 02142, USA
EMail: stewart@OpenMarket.com
๐ฆ where this page comes from
- ietf: rfc2069 1997-01
- ๐ girlified by claude-haiku-5-5 on : a language model's rewrite of the original, under its terms