RFC 2109
HTTP State Management Mechanism
RFC 2109: HTTP State Management Mechanism ๐ช
okay bestie, this one is the spec that taught HTTP to remember things ๐ง๐. The title block says it's from the Network Working Group, Request for Comments 2109, and it's on the Standards Track ๐. The authors are D. Kristol (Bell Laboratories, Lucent Technologies) and L. Montulli (Netscape Communications), and it's dated February 1997 ๐ธ. The title block doesn't list anything it obsoletes or updates, so it's solo-standing ๐ .
Status of This Memo
This document specifies an Internet standards track protocol for the Internet community, and requests discussion and suggestions for improvements. Please refer to the current edition of the "Internet Official Protocol Standards" (STD 1) for the standardization state and status of this protocol. Distribution of this memo is unlimited. ๐โจ
1. ABSTRACT ๐ฆ
This doc is about making a stateful session on top of HTTP requests and responses ๐
. It introduces two new headers, Cookie and Set-Cookie, which carry state info back and forth between origin servers and user agents ๐ช. Netscape already had a cookie proposal, and this method is different from it, but it can still play nicely with HTTP/1.0 user agents that use Netscape's way ๐ซถ. (Check the HISTORICAL section for the tea โ.)
2. TERMINOLOGY ๐
The terms user agent, client, server, proxy, and origin server mean the same thing as they do in the HTTP/1.0 specification, so no new drama there ๐.
Fully-qualified host name (FQHN) means either the fully-qualified domain name (FQDN) of a host (a completely specified domain name ending in a top-level domain such as .com or .uk), or the numeric Internet Protocol (IP) address of a host ๐. The FQDN is the preferred one, and using numeric IP addresses is strongly discouraged ๐.
The terms request-host and request-URI refer to the values the client would send to the server as, respectively, the host (but not port) and abs_path portions of the absoluteURI (http_URL) of the HTTP request line ๐. Heads up: request-host must be a FQHN ๐.
Host names can be given either as an IP address or a FQHN string ๐. Sometimes we need to compare one host name with another, and here's the check. Host A's name domain-matches host B's if:
- both host names are IP addresses and their host name strings match exactly; or
- both host names are FQDN strings and their host name strings match exactly; or
- A is a FQDN string and has the form NB, where N is a non-empty name string, B has the form .B', and B' is a FQDN string. (So, x.y.com domain-matches .y.com but not y.com.)
Domain-matching is not commutative ๐. a.b.c.com domain-matches .c.com, but not the reverse ๐ฅ.
Because Netscape's original implementation used the term, this doc says cookie for the state info that passes between an origin server and a user agent and gets stored by the user agent ๐.
3. STATE AND SESSIONS ๐ง
This section is all about making stateful sessions with HTTP requests and responses โจ. Right now HTTP servers answer each client request without connecting it to any previous or later request ๐ญ. This technique lets clients and servers that want to swap state info wrap their HTTP requests and responses in a bigger context, which the doc calls a "session" ๐ . A session could be a "shopping cart" where selections get collected before checkout ๐, or a magazine browsing system where your previous reading changes what gets shown to you ๐.
There are, of course, lots of possible contexts and therefore lots of possible kinds of session ๐. The designers' idea of sessions created by exchanging cookies has these key attributes:
- Each session has a beginning and an end.
- Each session is relatively short-lived.
- Either the user agent or the origin server may terminate a session.
- The session is implicit in the exchange of state information.
4. OUTLINE ๐บ๏ธ
Here's the plan: an origin server sends state info to the user agent, and the user agent sends that state info back to the origin server ๐. The big goal is minimal impact on HTTP and on user agents ๐. Only origin servers that actually need to keep sessions would feel a real impact, and that impact can mostly stay inside Common Gateway Interface (CGI) programs, unless the server has fancier state management support ๐ง. (See Implementation Considerations, below. ๐)
4.1. Syntax: General ๐งฉ
The two state management headers, Set-Cookie and Cookie, share some syntax stuff involving attribute-value pairs ๐. The grammar below borrows the notation, and the tokens DIGIT (decimal digits) and token (informally, a sequence of non-special, non-white space characters), from the HTTP/1.1 specification [RFC 2068] ๐.
av-pairs = av-pair *(";" av-pair)
av-pair = attr ["=" value] ; optional value
attr = token
value = word
word = token | quoted-string
Attributes (names), which is attr, are case-insensitive ๐. White space is allowed between tokens ๐ซง. Even though the syntax above shows value as optional, most attrs need one ๐ค.
NOTE: The syntax above allows whitespace between the attribute and the = sign. ๐
4.2. Origin Server Role ๐
4.2.1. General โจ
The origin server starts a session if it wants to ๐ธ. (Quick note: "session" here doesn't mean a persistent network connection. It means a logical session built from HTTP requests and responses. Whether there's a persistent connection or not should have no effect on cookie-derived sessions ๐.) To start one, the origin server sends back an extra response header to the client, Set-Cookie. (The details come later ๐.)
A user agent sends a Cookie request header (see below) to the origin server if it decides to keep a session going ๐. The origin server can ignore that header or use it to figure out the current state of the session ๐ต๏ธโโ๏ธ. It can send back a Set-Cookie response header with the same or different info, or it can send no Set-Cookie header at all ๐. The origin server ends a session by sending the client a Set-Cookie header with Max-Age=0 ๐.
Servers can return Set-Cookie response headers with any response ๐. User agents should send Cookie request headers with every request, subject to the other rules detailed below ๐ซถ.
An origin server can include multiple Set-Cookie headers in one response ๐
. Heads up: an intervening gateway could fold multiple such headers into a single header ๐.
4.2.2. Set-Cookie Syntax ๐ช
Here's the grammar for the Set-Cookie response header ๐:
set-cookie = "Set-Cookie:" cookies
cookies = 1#cookie
cookie = NAME "=" VALUE *(";" cookie-av)
NAME = attr
VALUE = value
cookie-av = "Comment" "=" value
| "Domain" "=" value
| "Max-Age" "=" value
| "Path" "=" value
| "Secure"
| "Version" "=" 1*DIGIT
Informally, the Set-Cookie response header is the token Set-Cookie:, followed by a comma-separated list of one or more cookies ๐ง. Each cookie starts with a NAME=VALUE pair, followed by zero or more semi-colon-separated attribute-value pairs ๐. The attribute-value pair syntax was shown earlier, and the specific attributes and what their values mean comes next โจ. The NAME=VALUE attribute-value pair must come first in each cookie ๐. The others, if present, can show up in any order ๐. If an attribute appears more than once in a cookie, the behavior is undefined ๐.
NAME=VALUE ๐ Required. The name of the state information ("cookie") is NAME, and its value is VALUE. NAMEs that begin with $ are reserved for other uses and must not be used by applications ๐ โโ๏ธ.
The VALUE is opaque to the user agent and can be anything the origin server chooses to send, possibly in a server-selected printable ASCII encoding ๐. "Opaque" means the content is only of interest and relevance to the origin server ๐. The content may, in fact, be readable by anyone who looks at the Set-Cookie header ๐ญ.
Comment=comment ๐ Optional. Because cookies can contain private info about a user, the Cookie attribute lets an origin server document its intended use of a cookie ๐ต๏ธ. The user can inspect that info to decide whether to start or continue a session with this cookie ๐ซถ.
Domain=domain ๐ Optional. The Domain attribute specifies the domain for which the cookie is valid. An explicitly specified domain must always start with a dot ๐
.
Max-Age=delta-seconds โณ Optional. The Max-Age attribute defines the lifetime of the cookie, in seconds. The delta-seconds value is a decimal non-negative integer. After delta-seconds seconds elapse, the client should discard the cookie. A value of zero means the cookie should be discarded immediately ๐.
Path=path ๐ค๏ธ Optional. The Path attribute specifies the subset of URLs to which this cookie applies ๐ฆ.
Secure ๐ Optional. The Secure attribute (with no value) directs the user agent to use only (unspecified) secure means to contact the origin server whenever it sends back this cookie ๐ซถ.
The user agent (possibly under the user's control) may decide what level of security it considers appropriate for "secure" cookies ๐. The Secure attribute should be considered security advice from the server to the user agent, indicating that it is in the session's interest to protect the cookie contents ๐จ.
Version=version ๐ธ Required. The Version attribute, a decimal integer, identifies which version of the state management specification the cookie conforms to. For this specification, Version=1 applies ๐.
4.2.3. Controlling Caching ๐ง
okay so origin servers have to be cognizant of caching, and that goes for both the returned resource AND the Set-Cookie header ๐ caching public documents is desirable, bestie. ๐ธ like if your server wants a public "front door" page to act as a sentinel for the start of a session, the page should be stored in caches "pre-expired" so the origin server keeps getting to see the further requests โจ "Private documents," the ones with info strictly private to a session, should not be cached in shared caches ๐
if the cookie is meant for one user, the Set-cookie header should not be cached ๐ but a Set-cookie header meant to be shared by multiple users may be cached, no cap ๐ซถ
the origin server should send these extra HTTP/1.1 response headers depending on the situation:
- to suppress caching of the Set-Cookie header:
Cache-control: no-cache="set-cookie"๐ โโ๏ธ
and then ONE of these:
- to suppress caching of a private document in shared caches:
Cache-control: private๐ - to allow caching of a document but require it be validated before it gets returned to the client:
Cache-control: must-revalidate๐ - to allow caching of a document but require that proxy caches (not user agent caches) validate it before returning it to the client:
Cache-control: proxy-revalidate๐ก๏ธ - to allow caching of a document and request that it be validated before returning it to the client (by "pre-expiring" it):
Cache-control: max-age=0. not all caches will revalidate the document in every case, so don't get too comfy ๐
HTTP/1.1 servers must send Expires: old-date (where old-date is a date long in the past) on responses containing Set-Cookie response headers, UNLESS they know for certain (by out of band means) that there are no downsteam HTTP/1.0 proxies ๐ฐ๏ธ HTTP/1.1 servers may send other Cache-Control directives that permit caching by HTTP/1.1 proxies on top of the Expires: old-date directive. the Cache-Control directive will override the Expires: old-date for HTTP/1.1 proxies, so it's giving priority, periodt ๐
4.3. User Agent Role ๐ฆ
4.3.1. Interpreting Set-Cookie ๐
the user agent keeps separate track of state info that arrives via Set-Cookie response headers from each origin server (as distinguished by name or IP address and port) ๐๏ธ and it applies these defaults for optional attributes that are missing:
Version Defaults to "old cookie" behavior as originally specified by
Netscape. See the HISTORICAL section.
Domain Defaults to the request-host. (Note that there is no dot at
the beginning of request-host.)
Max-Age The default behavior is to discard the cookie when the user
agent exits.
Path Defaults to the path of the request URL that generated the
Set-Cookie response, up to, but not including, the
right-most /.
Secure If absent, the user agent may send the cookie over an
insecure channel.
4.3.2. Rejecting Cookies ๐ซ
to prevent possible security or privacy violations, a user agent rejects a cookie (it shall not store its information) if any of the following is true ๐
- the value for the Path attribute is not a prefix of the request-URI.
- the value for the Domain attribute contains no embedded dots or does not start with a dot.
- the value for the request-host does not domain-match the Domain attribute.
- the request-host is a FQDN (not IP address) and has the form HD, where D is the value of the Domain attribute, and H is a string that contains one or more dots.
examples, because we love a receipt ๐งพ
- a Set-Cookie from request-host
y.x.foo.comforDomain=.foo.comwould be rejected, because H isy.xand contains a dot. ๐ โโ๏ธ - a Set-Cookie from request-host
x.foo.comforDomain=.foo.comwould be accepted. โจ - a Set-Cookie with
Domain=.comorDomain=.com.will always be rejected, because there is no embedded dot. ๐ - a Set-Cookie with
Domain=ajax.comwill be rejected because the value for Domain does not begin with a dot. ๐ญ
4.3.3. Cookie Management ๐งน
if a user agent gets a Set-Cookie response header whose NAME is the same as a pre-existing cookie, AND whose Domain and Path attribute values exactly (string) match those of a pre-existing cookie, the new cookie supersedes the old ๐ however, if the Set-Cookie has a value for Max-Age of zero, the (old and new) cookie is discarded ๐๏ธ otherwise cookies accumulate until they expire (resources permitting), at which point they get discarded ๐ฐ๏ธ
user agents have finite space to store cookies, so they may also discard older cookies to make room for newer ones, using, for example, a least-recently-used algorithm, along with constraints on the maximum number of cookies that each origin server may set ๐ง
if a Set-Cookie response header includes a Comment attribute, the user agent should store that info in a human-readable form with the cookie, and should display the comment text as part of a cookie inspection user interface ๐
user agents should allow the user to control cookie destruction ๐ an infrequently-used cookie may work as a "preferences file" for network applications, and a user may want to keep it even if it's the least-recently-used cookie ๐ one possible implementation would be an interface that allows permanent storage of a cookie through a checkbox (or, conversely, its immediate destruction) โ๏ธ
privacy considerations dictate that the user have considerable control over cookie management. the PRIVACY section has more info ๐ซถ
4.3.4. Sending Cookies to the Origin Server ๐ฎ
when it sends a request to an origin server, the user agent sends a Cookie request header to the origin server if it has cookies that are applicable to the request, based on:
- the request-host;
- the request-URI;
- the cookie's age.
the syntax for the header is:
cookie = "Cookie:" cookie-version
1*((";" | ",") cookie-value)
cookie-value = NAME "=" VALUE [";" path] [";" domain]
cookie-version = "$Version" "=" value
NAME = attr
VALUE = value
path = "$Path" "=" value
domain = "$Domain" "=" value
the value of the cookie-version attribute must be the value from the Version attribute, if any, of the corresponding Set-Cookie response header. otherwise the value for cookie-version is 0. the value for the path attribute must be the value from the Path attribute, if any, of the corresponding Set-Cookie response header. otherwise the attribute should be omitted from the Cookie request header. the value for the domain attribute must be the value from the Domain attribute, if any, of the corresponding Set-Cookie response header. otherwise the attribute should be omitted from the Cookie request header ๐
note that there is no Comment attribute in the Cookie request header corresponding to the one in the Set-Cookie response header. the user agent does not return the comment info to the origin server ๐ค
the following rules apply to choosing applicable cookie-values from among all the cookies the user agent has ๐ฏ
- Domain Selection: the origin server's fully-qualified host name must domain-match the Domain attribute of the cookie.
- Path Selection: the Path attribute of the cookie must match a prefix of the request-URI.
- Max-Age Selection: cookies that have expired should have been discarded and thus are not forwarded to an origin server. โฐ
if multiple cookies satisfy the criteria above, they are ordered in the Cookie header such that those with more specific Path attributes precede those with less specific. ordering with respect to other attributes (e.g., Domain) is unspecified ๐คทโโ๏ธ
Note: for backward compatibility, the separator in the Cookie header is semi-colon (;) everywhere. a server should also accept comma (,) as the separator between cookie-values for future compatibility ๐ฎ
4.3.5. Sending Cookies in Unverifiable Transactions ๐ต๏ธ
users must have control over sessions in order to ensure privacy. (see PRIVACY section below.) to simplify implementation and to prevent an extra layer of complexity where adequate safeguards already exist, though, this document distinguishes between transactions that are verifiable and those that are unverifiable ๐งฉ a transaction is verifiable if the user has the option to review the request-URI before it's used in the transaction. a transaction is unverifiable if the user does not have that option. unverifiable transactions typically come up when a user agent automatically requests inlined or embedded entities, or when it resolves redirection (3xx) responses from an origin server ๐ typically the origin transaction (the one the user initiates) is verifiable, and that transaction may directly or indirectly induce the user agent to make unverifiable transactions ๐ซ
when it makes an unverifiable transaction, a user agent must enable a session only if a cookie with a domain attribute D was sent or received in its origin transaction, such that the host name in the Request-URI of the unverifiable transaction domain-matches D. ๐ฆ
this restriction stops a malicious service author from using unverifiable transactions to induce a user agent to start or continue a session with a server in a different domain. starting or continuing such sessions could go against the user's privacy expectations, and could also be a security problem ๐ฑ
user agents may offer configurable options that let the user agent, or any autonomous programs that the user agent executes, ignore the rule above, as long as these override options default to "off" ๐๏ธ
plenty of current user agents already have a review option that would make many links verifiable ๐ for instance, some user agents display the URL that would be referenced for a particular link when the mouse pointer hovers over that link, so the user can decide whether to visit that site before the browser does it for them ๐ฑ๏ธ (though not implemented on current user agents, a similar technique could be used for a button that submits a form. the user agent could display the action to be taken if the user selected that button.) however, even this wouldn't make ALL links verifiable. for example, links to automatically loaded images wouldn't normally be subject to "mouse pointer" verification ๐ธ
many user agents also let a user view the HTML source of a document, or save the source to an external file where another application can view it. while that does give a crude review mechanism, some users might not consider it acceptable for this purpose ๐ค
4.4. How an Origin Server Interprets the Cookie Header ๐
okay so a user agent sends back most of the stuff from the Set-Cookie header to the origin server whenever the Path attribute matches a new request ๐ when the origin server gets a Cookie header, it should treat cookies whose NAME starts with $ specially, like an attribute for the cookie right next to it โจ the value for that NAME applies to the lexically (left-to-right) most recent cookie whose name doesn't have the $ prefix. if there's no previous cookie, the value applies to the cookie mechanism as a whole ๐ซถ here's an example:
Cookie: $Version="1"; Customer="WILE_E_COYOTE";
$Path="/acme"
$Version applies to the cookie mechanism as a whole (and it gives the version number for the cookie mechanism) ๐ฅ $Path is an attribute whose value (/acme) defines the Path attribute that was used when the Customer cookie was defined in a Set-Cookie response header ๐
4.5. Caching Proxy Role ๐ฆ
one reason to keep state info separate from both a URL and the document content is so caching can scale ๐ธ to support cookies, a caching proxy must obey these rules that are already in the HTTP specification ๐ง
- Honor requests from the cache, if possible, based on cache validity rules.
- Pass along a Cookie request header in any request that the proxy must make of another server.
- Return the response to the client. Include any Set-Cookie response header.
- Cache the received response subject to the control of the usual headers, such as
Expires,Cache-control: no-cache, andCache-control: private, - Cache the Set-Cookie subject to the control of the usual header,
Cache-control: no-cache="set-cookie". (The Set-Cookie header should usually not be cached.)
proxies must not introduce Set-Cookie (Cookie) headers of their own in proxy responses (requests) ๐
5. EXAMPLES โจ
5.1. Example 1 ๐
most of the request and response headers got cut for this one, so just assume the user agent has no stored cookies ๐
1. User Agent -> Server
POST /acme/login HTTP/1.1
[form data]
User identifies self via a form.
2. Server -> User Agent
HTTP/1.1 200 OK
Set-Cookie: Customer="WILE_E_COYOTE"; Version="1"; Path="/acme"
Cookie reflects user's identity.
3. User Agent -> Server
POST /acme/pickitem HTTP/1.1
Cookie: $Version="1"; Customer="WILE_E_COYOTE"; $Path="/acme"
[form data]
User selects an item for "shopping basket."
4. Server -> User Agent
HTTP/1.1 200 OK
Set-Cookie: Part_Number="Rocket_Launcher_0001"; Version="1";
Path="/acme"
Shopping basket contains an item.
5. User Agent -> Server
POST /acme/shipping HTTP/1.1
Cookie: $Version="1";
Customer="WILE_E_COYOTE"; $Path="/acme";
Part_Number="Rocket_Launcher_0001"; $Path="/acme"
[form data]
User selects shipping method from form.
6. Server -> User Agent
HTTP/1.1 200 OK
Set-Cookie: Shipping="FedEx"; Version="1"; Path="/acme"
New cookie reflects shipping method.
7. User Agent -> Server
POST /acme/process HTTP/1.1
Cookie: $Version="1";
Customer="WILE_E_COYOTE"; $Path="/acme";
Part_Number="Rocket_Launcher_0001"; $Path="/acme";
Shipping="FedEx"; $Path="/acme"
[form data]
User chooses to process order.
8. Server -> User Agent
HTTP/1.1 200 OK
Transaction is complete.
the user agent keeps making requests to the origin server, and after each one it gets a brand new cookie ๐ all the cookies share the same Path attribute and the (default) domain. because every request URL starts with /acme, which matches the Path attribute, each request carries all the cookies received so far ๐
5.2. Example 2 ๐
this one shows how the Path attribute works. all the request and response header details got cut, so assume the user agent has no stored cookies ๐ฆ
imagine the user agent already got these response headers from earlier requests:
Set-Cookie: Part_Number="Rocket_Launcher_0001"; Version="1";
Path="/acme"
and
Set-Cookie: Part_Number="Riding_Rocket_0023"; Version="1";
Path="/acme/ammo"
a later request from the user agent to the (same) server for URLs like /acme/ammo/... would include this request header:
Cookie: $Version="1";
Part_Number="Riding_Rocket_0023"; $Path="/acme/ammo";
Part_Number="Rocket_Launcher_0001"; $Path="/acme"
notice that the NAME=VALUE pair for the cookie with the more specific Path attribute,/acme/ammo, shows up before the one with the less specific Path attribute,/acme๐ also notice that the same cookie name shows up more than once ๐
a later request from the user agent to the (same) server for a URL like /acme/parts/ would include this request header:
Cookie: $Version="1"; Part_Number="Rocket_Launcher_0001"; $Path="/acme"
here, the second cookie's Path attribute, /acme/ammo, isn't a prefix of the request URL, /acme/parts/, so that cookie doesn't get forwarded to the server ๐
โโ๏ธ
6. IMPLEMENTATION CONSIDERATIONS ๐ ๏ธ
here we speculate on likely or desirable details for an origin server that implements state management ๐ฎ
6.1. Set-Cookie Content ๐ฐ
an origin server's content should probably be split into disjoint application areas, and some of those need state info ๐ง the application areas can be told apart by their request URLs. the Set-Cookie header can cover those areas by setting the Path attribute for each one ๐
the session info can obviously be clear or encoded text that describes state. but if it grows too large, it gets unwieldy ๐ญ so an implementor might choose for the session info to be a key to a server-side resource. of course, using a database brings some problems that this state management specification was meant to avoid, namely:
- keeping real state on the server side;
- how and when to garbage-collect the database entry, in case the user agent ends the session by, for example, exiting.
6.2. Stateless Pages ๐ท
caching is good for the scalability of the WWW, so it's important to reduce the number of documents that have state embedded in them inherently โจ for example, if a shopping-basket-style app always shows a user's current basket contents on each page, those pages can't be cached, because each user's basket contents would be different ๐งบ on the other hand, if each page just has a link that lets the user "Look at My Shopping Basket", the page can be cached ๐
6.3. Implementation Limits ๐งฎ
practical user agent implementations have limits on the number and size of cookies they can store. in general, user agents' cookie support should have no fixed limits ๐ซ they should strive to store as many frequently-used cookies as possible. furthermore, general-use user agents should provide each of the following minimum capabilities individually, although not necessarily simultaneously:
- at least 300 cookies
- at least 4096 bytes per cookie (as measured by the size of the characters that comprise the cookie non-terminal in the syntax description of the Set-Cookie header)
- at least 20 cookies per unique host or domain name
user agents created for specific purposes or for limited-capacity devices should provide at least 20 cookies of 4096 bytes, so the user can interact with a session-based origin server ๐งโโ๏ธ
the information in a Set-Cookie response header must be retained in its entirety. if there's inadequate space to store the cookie for some reason, it must be discarded, not truncated ๐ซโ๏ธ
applications should use as few and as small cookies as possible, and they should cope gracefully with the loss of a cookie ๐ซง
6.3.1. Denial of Service Attacks ๐
user agents may choose to set an upper bound on the number of cookies stored from a given host or domain name, or on the size of the cookie info. otherwise a malicious server could try to flood a user agent with lots of cookies, or large cookies, on successive responses, which would force out cookies the user agent got from other servers ๐ค however, the minima specified above should still be supported ๐ก๏ธ
7. PRIVACY ๐
7.1. User Agent Control ๐ฆ
an origin server could create a Set-Cookie header to track the path of a user through the server. users may object to this as an intrusive pile of info, even if their identity isn't evident ๐ (identity might become evident if a user later fills out a form that has identifying info.) this state management specification therefore requires that a user agent give the user control over that possible intrusion, although the interface for that control is left unspecified ๐๏ธ however, the control mechanisms provided shall at least allow the user:
- to completely disable the sending and saving of cookies.
- to determine whether a stateful session is in progress.
- to control the saving of a cookie on the basis of the cookie's Domain attribute.
that control could be provided by, for example, mechanisms:
- to notify the user when the user agent is about to send a cookie to the origin server, offering the option not to begin a session.
- to display a visual indication that a stateful session is in progress.
- to let the user decide which cookies, if any, should be saved when the user closes a window or ends a user agent session.
- to let the user examine the contents of a cookie at any time.
a user agent usually begins execution with no remembered state info. it should be possible to configure a user agent never to send Cookie headers, in which case it can never sustain state with an origin server. (the user agent would then behave like one that doesn't know how to handle Set-Cookie response headers ๐ฅฒ)
when the user agent stops running, it should let the user discard all state info. alternatively, the user agent may ask the user whether state info should be kept; the default should be "no". if the user chooses to keep state info, it would be restored the next time the user agent runs ๐
NOTE: user agents should probably be cautious about using files to store cookies long-term. if a user runs more than one instance of the user agent, the cookies could get commingled or otherwise messed up ๐ฌ
7.2. Protocol Design ๐งฉ
the restrictions on the value of the Domain attribute, and the rules about unverifiable transactions, are meant to cut down on the ways cookies can "leak" to the "wrong" site ๐จ the intent is to restrict cookies to one host, or a closely related set of hosts. so a request-host is limited in what values it can set for Domain. we consider it acceptable for hosts host1.foo.com and host2.foo.com to share cookies, but not a.com and b.com ๐
โโ๏ธ
similarly, a server can only set a Path for cookies that are related to the request-URI ๐
8. SECURITY CONSIDERATIONS ๐
8.1. Clear Text ๐
Okay, bestie, this one is a little scary. The information in the Set-Cookie and Cookie headers is unprotected, so anyone can read it and anyone in the middle can mess with it ๐ญ Two things happen because of that:
- Any sensitive information carried in them is exposed to intruders. ๐
- A malicious intermediary could alter the headers as they travel in either direction, with unpredictable results. ๐
So the vibe check is: personal or financial info should only be sent over a secure channel ๐. For less sensitive stuff, or when the header content is a database key, the origin server should be vigilant so a bad Cookie value can't cause failures. Protect your babies! ๐ซถ
8.2. Cookie Spoofing ๐ต๏ธโโ๏ธ
Proper app design can stop spoofing attacks from related domains, and this little scenario is giving villain arc energy ๐ญ Picture this:
- User agent makes a request to
victim.cracker.edu, gets back cookiesession_id="1234", and sets the default domainvictim.cracker.edu. - User agent makes a request to
spoof.cracker.edu, gets back cookiesession-id="1111", withDomain=".cracker.edu". - User agent makes a request to
victim.cracker.eduagain, and passes:
Cookie: $Version="1";
session_id="1234";
session_id="1111"; $Domain=".cracker.edu"
The server at victim.cracker.edu should notice that the second cookie wasn't one it originated, because its Domain attribute isn't for itself, and then ignore it. Caught you lacking, spoofer! ๐
โโ๏ธ๐
8.3. Unexpected Cookie Sharing ๐
A user agent should make every attempt to stop session info from being shared between hosts in different domains. This is a major privacy red flag ๐ฉ Embedded or inlined objects can cause seriously bad privacy problems if they're used to share cookies between totally unrelated hosts. For example, a malicious server could stash cookie info for a.com inside a URI for a CGI on b.com. User agent implementors are strongly encouraged to block this kind of exchange whenever they can. Shut it down, no notes! ๐โจ
9. OTHER, SIMILAR, PROPOSALS ๐
Okay, so there were three other proposals trying to do similar stuff ๐ This spec is basically a blend of Kristol's State-Info proposal and Netscape's Cookie proposal. Iconic mix ๐
Brian Behlendorf proposed a Session-ID header that the user agent would start and that an origin server could use to track "clicktrails" ๐ It wouldn't carry any origin-server-defined state though. Phillip Hallam-Baker also proposed another client-defined session ID mechanism for similar purposes โจ
Here's the tea โ: session IDs and cookies can both keep stateful sessions going, but they're for different things, so their privacy requirements are different too ๐ A user starts session IDs so servers can track their progress, or tell apart multiple users on a shared machine. Cookies are server-initiated, though, so the cookie mechanism described here gives users control over something that would otherwise happen without them even knowing ๐๏ธ Plus, cookies carry rich, server-selected info, while session IDs are just simple, user-selected info. Totally different energy ๐ง
10. HISTORICAL ๐ฐ๏ธ
10.1. Compatibility With Netscape's Implementation ๐ฆ
HTTP/1.0 clients and servers may use Set-Cookie and Cookie headers that reflect Netscape's original cookie proposal. These notes are about how "old" and "new" cookies inter-operate, so get ready for some throwback lore ๐ผ
10.1.1. Extended Cookie Header ๐
This proposal adds attribute-value pairs to the Cookie request header in a compatible way. An "old" client that gets a "new" cookie will ignore attributes it doesn't understand, and it returns whatever it does understand to the origin server. A "new" client always sends cookies in the new form ๐
An "old" server that gets a "new" cookie will see what it thinks are a bunch of cookies with names starting with $, and it'll ignore them. (The "old" server expects these cookies to be separated by semi-colon, not comma.) A "new" server can spot cookies that passed through an "old" client, because they lack a $Version attribute ๐
10.1.2. Expires and Max-Age โฐ
Netscape's original proposal defined an Expires header that took a date value in a fixed-length variant format, in place of Max-Age:
Wdy, DD-Mon-YY HH:MM:SS GMT
Heads up, this date format has embedded spaces, and "old" cookies didn't have quotes around their values. Clients implementing to this spec should be aware of "old" cookies and Expires ๐ซ
10.1.3. Punctuation โ๏ธ
In Netscape's original proposal, the values in attribute-value pairs didn't accept "-quoted strings. Origin servers should be cautious about sending values that need quotes, unless they know the receiving user agent understands them (i.e., "new" cookies). A ("new") user agent should only use quotes around values in Cookie headers when the cookie's version(s) are all compliant with this specification or later.
Also, in Netscape's original proposal, no whitespace was allowed around the = that separates attribute-value pairs. So be careful with whitespace in new implementations, okay? ๐
10.2. Caching and HTTP/1.0 ๐ง
Some caches, like the ones conforming to HTTP/1.0, will inevitably cache the Set-Cookie header, because there was no way to stop caching headers before HTTP/1.1. This can lead to security problems ๐ฌ Documents an origin server sends along with Set-Cookie headers will usually be either uncachable or "pre-expired". As long as caches obey instructions not to cache documents (following Expires: <a date in the past>, or Pragma: no-cache (HTTP/1.0), or Cache-control: no-cache (HTTP/1.1)), uncachable documents are no problem.
Pre-expired documents, though, may get stored in caches. They need validation (a conditional GET) on each new request, but some cache operators loosen the rules for their caches and sometimes serve expired documents without validating them first. That combo can lead to cookies meant for one user later being sent to another user ๐ญ The Set-Cookie header gets stored in the cache, and even though the document is stale (expired), the cache returns it in response to later requests, including the cached headers. Not cute! ๐ซ
11. ACKNOWLEDGEMENTS ๐ซถ
This document really represents the collective efforts of the following people, in addition to the authors: Roy Fielding, Marc Hedlund, Ted Hardie, Koen Holtman, Shel Kaphan, Rohit Khare. Thank you, queens! ๐๐
12. AUTHORS' ADDRESSES ๐ฌ
David M. Kristol
Bell Laboratories, Lucent Technologies
600 Mountain Ave. Room 2A-227
Murray Hill, NJ 07974
Phone: (908) 582-2250
Fax: (908) 582-5809
EMail: dmk@bell-labs.com
Lou Montulli
Netscape Communications Corp.
501 E. Middlefield Rd.
Mountain View, CA 94043
Phone: (415) 528-2600
EMail: montulli@netscape.com
๐ฆ where this page comes from
- ietf: rfc2109 1997-02
- ๐ girlified by claude-haiku-5-5 on : a language model's rewrite of the original, under its terms