Hacker DirectoryHacker Directory

WEB / WEB-12.01

Adding state to HTTP with cookies

Follow a language preference from Set-Cookie to the Browser jar and the next Cookie header to locate state transmission.

CORE · RED · BLUE · ARTIFACT · PRACTICE

1. Core · Mechanism

Read every scenario without motion

Preference cookie included

  1. The first request has no preference

    The jar starts empty. The browser prepares a request to library.outreason.example/books. Language or view preferences are not authentication results.

    Browser · cookie jar
    Jar: empty
    Application · HTTP handler
    No request yet
    Request · context
    HTTPS · /books · same-site
  2. The first HTTP request arrived

    This request has no preference Cookie field. The application can use its default language and view. An absent cookie is not a transport failure.

    Browser · cookie jar
    Waiting for response
    Application · HTTP handler
    No Cookie → en / comfortable
    Request · context
    First GET received
  3. The response prepares cookie fields

    The application prepares two separate Set-Cookie response fields: hd_language=tr; Path=/ and hd_view=compact; Path=/. These preference values are not a session identity.

    Browser · cookie jar
    Jar still empty
    Application · HTTP handler
    Two Set-Cookie fields ready
    Request · context
    Waiting for response
  4. The cookie response reached the browser

    The browser received headers for its own cookie processing. Set-Cookie is not an ordinary header exposed through frontend fetch response headers.

    Browser · cookie jar
    Headers arrived; storage separate
    Application · HTTP handler
    Set-Cookie response sent
    Request · context
    Response headers received
  5. The jar is local browser state

    In this controlled example the browser accepts both cookies; host-only scope and Path=/ metadata belong to the jar. Acceptance is not a general browser guarantee.

    Browser · cookie jar
    Jar: hd_language / hd_view
    Application · HTTP handler
    No later request yet
    Request · context
    Host-only · Path=/
  6. The later request selects candidates

    The candidates are eligible in this fixture’s same host/path context. The request Cookie field contains only name=value pairs; Path is not copied into it.

    Browser · cookie jar
    Cookie: hd_language=tr; hd_view=compact
    Application · HTTP handler
    Request not received
    Request · context
    Preparing GET /books
  7. The later request is in the application

    The Cookie request field carries names and values. Response attributes are not carried there; the application validates supported preference values and otherwise selects defaults.

    Browser · cookie jar
    Waiting for response
    Application · HTTP handler
    Preference: tr / compact
    Request · context
    GET + Cookie name=value
  8. A preference is not a principal

    The application selects presentation. Cookie inclusion proves neither verified identity nor resource permission; session and authorization models show those later decisions separately.

    Browser · cookie jar
    UI preference can be prepared
    Application · HTTP handler
    tr / compact; no authn established
    Request · context
    This request observation is complete

No preferences

  1. The first request has no preference

    The jar starts empty. The browser prepares a request to library.outreason.example/books. Language or view preferences are not authentication results.

    Browser · cookie jar
    Jar: empty
    Application · HTTP handler
    No request yet
    Request · context
    HTTPS · /books · same-site
  2. The first HTTP request arrived

    This request has no preference Cookie field. The application can use its default language and view. An absent cookie is not a transport failure.

    Browser · cookie jar
    Waiting for response
    Application · HTTP handler
    No Cookie → en / comfortable
    Request · context
    First GET received
  3. The response prepares cookie fields

    The application prepares two separate Set-Cookie response fields: hd_language=tr; Path=/ and hd_view=compact; Path=/. These preference values are not a session identity.

    Browser · cookie jar
    Jar still empty
    Application · HTTP handler
    Two Set-Cookie fields ready
    Request · context
    Waiting for response
  4. The cookie response reached the browser

    The browser received headers for its own cookie processing. Set-Cookie is not an ordinary header exposed through frontend fetch response headers.

    Browser · cookie jar
    Headers arrived; storage separate
    Application · HTTP handler
    Set-Cookie response sent
    Request · context
    Response headers received
  5. The jar is local browser state

    In this controlled example the browser accepts both cookies; host-only scope and Path=/ metadata belong to the jar. Acceptance is not a general browser guarantee.

    Browser · cookie jar
    Jar: hd_language / hd_view
    Application · HTTP handler
    No later request yet
    Request · context
    Host-only · Path=/
  6. The later request selects candidates

    In this alternative fixture the later request has no preferences: the user may have cleared them or browser state may not be carried. The application observes absence on this request without inventing the cause.

    Browser · cookie jar
    Later request: no Cookie
    Application · HTTP handler
    Request not received
    Request · context
    Preparing GET /books
  7. The later request is in the application

    The Cookie request field carries names and values. Response attributes are not carried there; the application validates supported preference values and otherwise selects defaults.

    Browser · cookie jar
    Waiting for response
    Application · HTTP handler
    Default: en / comfortable
    Request · context
    GET + no preference Cookie
  8. A preference is not a principal

    The application selects presentation. Cookie inclusion proves neither verified identity nor resource permission; session and authorization models show those later decisions separately.

    Browser · cookie jar
    UI preference can be prepared
    Application · HTTP handler
    en / comfortable; no authn established
    Request · context
    This request observation is complete

ACTORS · STATE · DATA FLOW

How does the next request remember the page language?

Duru selects Turkish and a compact view in the Atlas library. The next page should retain those choices. HTTP being stateless does not prohibit application memory: the meaning of a request does not depend on the connection that carried an earlier message. Continuity is built from information on later requests and application state.

A cookie is a small Browser-managed name/value record that can support this continuity. hd_language=tr and hd_view=compact are display preferences in our example. No login occurs, and neither value proves a user identity. This separates remembering state from establishing authentication.

Set-Cookie brings the server’s instruction to the Browser

The Application processes Duru’s selection and adds two separate Set-Cookie fields to its response. One contains hd_language=tr; Path=/ and the other hd_view=compact; Path=/. Each describes a separate cookie. Folding the two Set-Cookie fields into one comma-separated list is not a valid general combining method.

While the response travels, the Application has prepared the preference result but the Browser jar has not changed. On arrival, Browser policy determines acceptance, storage or rejection. Sending Set-Cookie and observing a stored cookie are separate steps. WEB-12.02 develops scope and lifetime; this example chooses one host, Path=/ and a Browser policy that allows storage.

Cookie expresses the Browser’s selection for a later request

When Duru opens the book list, the Browser selects eligible records and sends Cookie: hd_language=tr; hd_view=compact. The semicolon separates two name/value pairs. Attributes such as Path=/ from Set-Cookie are not repeated in the request Cookie field.

This does not send the response back. The Browser serializes eligible state from its jar for this request context. A cookie belonging to another site is not automatically included because it exists in the jar. Selection depends on host, path, lifetime and policy; reusing an HTTP connection does not replace that selection.

The server interprets the incoming data again

The Application parses both preferences on the second request. Our model allows tr/en for language and compact/comfortable for view. Valid pairs affect response presentation. Without them, the Application uses its en/comfortable defaults. Both results are explained by the endpoint contract.

A cookie value is client-supplied data. Its earlier issuance by the server does not make every later value inherently trustworthy. We accept a constrained preference here; roles, tenants and book ownership are not established from arbitrary cookie text.

Separate the cookie mechanism from the kind of state it carries

A cookie can hold a preference directly or carry an opaque handle to a server record. In the second design, the large state is not inside the Cookie header; the handle tells the Application which record to evaluate. WEB-13.01 develops that separation for sessions.

Set-Cookie is not the only creation mechanism: eligible cookies can also be created through script APIs. Restrictions such as HttpOnly define separate boundaries. Reading Set-Cookie through frontend response.headers is not a way to observe cookie acceptance; the Browser filters this response header from frontend access.

When does this state disappear?

If Duru clears the cookies, the next request may omit the preference pairs and receive the default view. This does not erase Atlas’s database or all server state. Dropping a Browser preference and changing application records are independent operations.

Explain the next request using three parts: the jar’s candidate records, the transmitted pairs and the limited result derived by the Application. A Turkish page alone does not identify which of these stages occurred.

2. Red · Trust & Impact

Read every scenario without motion

Preference present

  1. The preference request is ready

    The browser preference in this example concerns language and layout. A request that has not reached the handler cannot establish an application decision.

    Browser
    hd_language=tr; hd_view=compact
    Preference handler
    Request not received
    Application decision
    No identity decision
  2. The preference input arrived

    The ordinary preference request reached the handler. Presence or absence of cookie pairs describes this input, rather than an authenticated identity.

    Browser
    Awaiting result
    Preference handler
    Cookie pairs received
    Application decision
    No identity decision
  3. The allowed values were selected

    The application uses languages=[tr,en] and views=[compact,comfortable]. This branch selects tr and compact from these sets.

    Browser
    Awaiting result
    Preference handler
    language=tr; view=compact
    Application decision
    No identity decision
  4. Preferences do not establish authority

    Although language and layout are selected, the artifact establishes no login, role or tenant grant. A preference result cannot substitute for those decisions.

    Browser
    Awaiting result
    Preference handler
    Preference selection complete
    Application decision
    Presentation context only
  5. The presentation response is ready

    The handler prepares the result for language tr and layout compact. This response is neither an authentication document nor approval of a sensitive action.

    Browser
    Awaiting result
    Preference handler
    Preference result prepared
    Application decision
    Presentation context only
  6. The preference result reached the browser

    The browser received the selected presentation result. Cookie presence explains the preference source; it does not become identity evidence.

    Browser
    language=tr; view=compact
    Preference handler
    Response prepared
    Application decision
    No identity decision

Preference absent

  1. The preference request is ready

    The browser preference in this example concerns language and layout. A request that has not reached the handler cannot establish an application decision.

    Browser
    No Cookie
    Preference handler
    Request not received
    Application decision
    No identity decision
  2. The preference input arrived

    The ordinary preference request reached the handler. Presence or absence of cookie pairs describes this input, rather than an authenticated identity.

    Browser
    Awaiting result
    Preference handler
    No Cookie sent
    Application decision
    No identity decision
  3. The allowed values were selected

    The application uses languages=[tr,en] and views=[compact,comfortable]. This branch selects the defaults en and comfortable when input is absent.

    Browser
    Awaiting result
    Preference handler
    language=en; view=comfortable
    Application decision
    No identity decision
  4. Preferences do not establish authority

    Although language and layout are selected, the artifact establishes no login, role or tenant grant. A preference result cannot substitute for those decisions.

    Browser
    Awaiting result
    Preference handler
    Preference selection complete
    Application decision
    Presentation context only
  5. The presentation response is ready

    The handler prepares the result for language en and layout comfortable. This response is neither an authentication document nor approval of a sensitive action.

    Browser
    Awaiting result
    Preference handler
    Preference result prepared
    Application decision
    Presentation context only
  6. The preference result reached the browser

    The browser received the selected presentation result. Using defaults is a normal product branch; absence is not classified as an attack or failed login.

    Browser
    language=en; view=comfortable
    Preference handler
    Response prepared
    Application decision
    No identity decision

ASSUMPTION · BOUNDARY · CONTROL

Do not turn a preference into authority

The normal function is choosing language and layout. Its control restricts incoming values to two small allowed sets. Treating a cookie as an authority document because “the server wrote it earlier” gives client state excessive authority.

A preference-validation defect here can affect presentation or default selection. Using the same mechanism for a role or tenant decision has a different risk and requires server-owned identity and authorization policy. Derive impact from the decision consuming a value, not from the word cookie.

Automatic transmission does not remove application controls

A Browser-generated Cookie header does not prove that the user deliberately approved every request. Cookie state carries context to a subsequent operation; it does not independently establish intent or safety.

We do not portray this benign preference request as an authenticated action. A more sensitive action needs its own boundaries: input validation, identity resolution and resource/action policy. The WEB-11 Browser-security and WEB-14 authorization lessons develop those distinct controls.

3. Blue · Secure development & defense

Read every scenario without motion

Cookie source

  1. A preference observation was selected

    Review starts with record pref-1. It uses cookiePresent and decision-source fields rather than copying raw Cookie values.

    Observation record
    requestId=pref-1; cookiePresent=true
    Branch comparison
    Not correlated
    Review conclusion
    No conclusion
  2. The decision source was read

    The same observation records languageDecision=cookie and viewDecision=cookie. These fields belong to the application example, not a standard HTTP log schema.

    Observation record
    requestId=pref-1; cookiePresent=true
    Branch comparison
    languageDecision=cookie; viewDecision=cookie
    Review conclusion
    No conclusion
  3. The branch expectation was compared

    The artifact with-preferences branch selects tr and compact. Review compares the decision source; browser appearance remains unproven.

    Observation record
    requestId=pref-1; cookiePresent=true
    Branch comparison
    Expected branch matches
    Review conclusion
    No conclusion
  4. The XPath selection was bounded

    The XPath combining the default source with cookiePresent=false selects only pref-2. Not selecting pref-1 does not mean the record is absent.

    Observation record
    requestId=pref-1; cookiePresent=true
    Branch comparison
    XPath: not selected
    Review conclusion
    No conclusion
  5. UI evidence is requested separately

    The observation shows the decision source. If the UI appears in a different language, matching cache, other state-source and rendering observations are needed; this record alone cannot explain the cause.

    Observation record
    requestId=pref-1; cookiePresent=true
    Branch comparison
    Decision source known
    Review conclusion
    UI outcome unknown
  6. The preference conclusion was preserved

    The cookie/default decision can be explained for this branch. Authentication, actual browser cookie acceptance and rendered appearance require separate evidence.

    Observation record
    requestId=pref-1; cookiePresent=true
    Branch comparison
    Decision source: cookie
    Review conclusion
    No identity or UI evidence

Default source

  1. A preference observation was selected

    Review starts with record pref-2. It uses cookiePresent and decision-source fields rather than copying raw Cookie values.

    Observation record
    requestId=pref-2; cookiePresent=false
    Branch comparison
    Not correlated
    Review conclusion
    No conclusion
  2. The decision source was read

    The same observation records languageDecision=default and viewDecision=default. These fields belong to the application example, not a standard HTTP log schema.

    Observation record
    requestId=pref-2; cookiePresent=false
    Branch comparison
    languageDecision=default; viewDecision=default
    Review conclusion
    No conclusion
  3. The branch expectation was compared

    The artifact without-preferences branch selects en and comfortable. Review compares the decision source; browser appearance remains unproven.

    Observation record
    requestId=pref-2; cookiePresent=false
    Branch comparison
    Expected branch matches
    Review conclusion
    No conclusion
  4. The XPath selection was bounded

    The XPath combining the default source with cookiePresent=false selects only pref-2. Selecting pref-2 is not an attack finding.

    Observation record
    requestId=pref-2; cookiePresent=false
    Branch comparison
    XPath: pref-2 selected
    Review conclusion
    No conclusion
  5. UI evidence is requested separately

    The observation shows the decision source. If the UI appears in a different language, matching cache, other state-source and rendering observations are needed; this record alone cannot explain the cause.

    Observation record
    requestId=pref-2; cookiePresent=false
    Branch comparison
    Decision source known
    Review conclusion
    UI outcome unknown
  6. The preference conclusion was preserved

    The cookie/default decision can be explained for this branch. Authentication, actual browser cookie acceptance and rendered appearance require separate evidence.

    Observation record
    requestId=pref-2; cookiePresent=false
    Branch comparison
    Decision source: default
    Review conclusion
    No identity or UI evidence

IMPLEMENTATION · SECURITY CONTROL · VERIFICATION

Distinguish the sent header from the accepted record

Compare two Set-Cookie fields on the response, two records in cookie storage and pairs inside one Cookie field on the later request. These are not three copies of one screen. Policy evaluation separates response arrival from cookie acceptance, and later transmission is a fresh selection.

If a real Browser shows a blocked reason or scope mismatch, do not infer creation from the server response alone. The artifact includes an expected allowed path and a missing-cookie branch; it is neither a real HAR nor a Browser capture.

Observe preference decisions without carrying credentials

Our observation record has requestId, cookiePresent, languageDecision and viewDecision. These are fields in an application-owned example schema. Instead of copying the raw Cookie header into general logs, record only the constrained preference decision needed; the same header may later contain a session credential.

The XPath /observations/preferenceObservation[@cookiePresent="false" and @languageDecision="default"] selects only the default branch in the fixture XML. A benign missing-cookie case is not labelled an error or attack. A Turkish UI alongside a default observation with the same requestId invites investigation of another state source, cache or missing trace; it is not itself evidence of malicious intent.

Explain the control outcome together with its state source

Document allowed preference values, defaults and behavior under Browser privacy settings at the consuming endpoint. Verify the fallback when cookies are removed. Preserve the distinction between preferences and authenticated handles rather than applying one policy to every cookie class.

Success is not that preferences never disappear. The learner should explain whether the same page came from the cookie branch or default branch using headers, the jar and the application decision.

NOW APPLY IT TO THE CASE

Which decision does a cookie language preference carry?

Two small preference values are used in the cookie branch; defaults apply when they are absent. The scene separates preference source from identity and appearance evidence.

Which owner holds the case’s browser data? Explain why presence or deletion of a client value differs from the server-side session outcome.

Open the related case file ↗

READ THE EXAMPLE TOGETHER

The response–jar–request trail of two preference cookies

Select a field and examine what it supports and where the evidence ends.

Read the raw artifact and field explanations
{
  "host": "library.outreason.example",
  "responseFields": [
    "Set-Cookie: hd_language=tr; Path=/",
    "Set-Cookie: hd_view=compact; Path=/"
  ],
  "jarAfterArrival": [
    {
      "name": "hd_language",
      "value": "tr",
      "hostOnly": true,
      "path": "/"
    },
    {
      "name": "hd_view",
      "value": "compact",
      "hostOnly": true,
      "path": "/"
    }
  ],
  "nextRequestFields": [
    "Host: library.outreason.example",
    "Cookie: hd_language=tr; hd_view=compact"
  ],
  "applicationPolicy": {
    "languages": [
      "tr",
      "en"
    ],
    "views": [
      "compact",
      "comfortable"
    ],
    "defaults": {
      "language": "en",
      "view": "comfortable"
    }
  },
  "branches": [
    {
      "id": "with-preferences",
      "cookiePresent": true,
      "language": "tr",
      "view": "compact",
      "languageDecision": "cookie",
      "viewDecision": "cookie"
    },
    {
      "id": "without-preferences",
      "cookiePresent": false,
      "language": "en",
      "view": "comfortable",
      "languageDecision": "default",
      "viewDecision": "default"
    }
  ],
  "observationXML": "<observations><preferenceObservation requestId=\"pref-1\" cookiePresent=\"true\" languageDecision=\"cookie\" viewDecision=\"cookie\"/><preferenceObservation requestId=\"pref-2\" cookiePresent=\"false\" languageDecision=\"default\" viewDecision=\"default\"/></observations>",
  "localXPath": "/observations/preferenceObservation[@cookiePresent=\"false\" and @languageDecision=\"default\"]",
  "expectedSelectedRequestIds": [
    "pref-2"
  ]
}
responseFields
Separate Set-Cookie fields per cookie, not one comma-separated field.
jarAfterArrival
Expected records after arrival and permitted Browser policy, not captured storage.
nextRequestFields
Transmitted name/value pairs without Path attributes.
applicationPolicy / branches
Preference allowlists and defaults, not authentication or book permissions.
observationXML / localXPath
Local selection over our synthetic XML, without network or temporal correlation.

Preferences are inert and secrets-free. The HTTP metadata is not a wire capture; the model does not run a cookie parser, Browser privacy engine or real endpoint. XPath selects only this XML fixture.

Two reality checks

A stateless HTTP site cannot remember an earlier selection.

Stateless protocol semantics do not forbid application state. Later-request data such as cookies and application records can provide continuity.

Set-Cookie and Cookie are two names for the same header.

Set-Cookie instructs Browser storage on a response; Cookie carries selected name/value pairs on a request without repeating attributes.

YOUR TURN

Work through this story.

Predict the outcome, find the evidence boundary, and explain it in your own words.

Which language/view values does the selected application choose when no Cookie is present?

  1. tr/compact; HTTP automatically treats the previous response as user state.
  2. en/comfortable; defaults.
Read the explained answer

en/comfortable; defaults. — The without-preferences branch applies application defaults when cookiePresent=false; HTTP does not independently remember prior choices.

Why are Set-Cookie and Cookie not two names for the same direction?

Selected lesson artifact fields; teaching example

responseFields
["Set-Cookie: hd_language=tr; Path=/","Set-Cookie: hd_view=compact; Path=/"]
nextRequestFields
["Host: library.outreason.example","Cookie: hd_language=tr; hd_view=compact"]
  1. Set-Cookie in a response proposes browser storage; Cookie in a subsequent request carries eligible values.
  2. The browser sends Set-Cookie as a request authorization header.
Read the explained answer

Set-Cookie in a response proposes browser storage; Cookie in a subsequent request carries eligible values. — Two separate Set-Cookie fields carry instructions for storing two preferences. In this example, the Browser creates the records after the response arrives and its cookie policy accepts them. The later request Cookie field carries only eligible name/value pairs.

hd_language=tr was stored in the browser. Why should the server evaluate the value against its languages allowlist?

Read the explained answer

A Cookie is browser-held request data; the application interprets values using its tr/en and compact/comfortable contract. Presence in the jar proves neither user authentication nor accepted business input. The application builds this state layer on top of stateless HTTP semantics.

□ I did not count browser storage as trusted policy.

□ I identified the owner of application defaults/allowlists.

Open the application console · request / response / browser
Also open request, URL, cookie and DOM examples

Sources and scope