-1

Go removes double quotes in cookies. Is there a way to keep double quotes in cookies in Go?

For example, I'm sending a small JSON message and "SetCookie" strips double quote.

w.SetCookie("my_cookie_name", small_json_message)

More about Cookies:

  • The HTTP RFC defines quoted string values. See https://www.rfc-editor.org/rfc/rfc7230#section-3.2.6

  • The proposed cookie RFC explicitly says double quotes are allowed in cookie values: cookie-value = *cookie-octet / ( DQUOTE *cookie-octet DQUOTE )

  • Go currently has a condition to insert double quote into cookies, so obviously double quotes are allowed.

  • ; is the cookie delimiter.

  • Values with ASCII characters outside the limited ASCII range may be quoted (The RFC calls this the quoted_string) which expands the allowed character set.

  • JSON does not contain the ; character, so for ; to appear in JSON it can only appear in string values. In JSON, string values are already quoted.

  • I've confirmed testing using a simple k:v JSON payload and it works fine on all major browsers with no issues.

  • Cookies are typically generated by server data, not user data. This means well structured, not arbitrary, JSON may be used

JSON easily can conform to the cookie RFC. Additionally, even though it's not an issue with this example of JSON, regarding the hypothetical concern of not conforming to the RFC:

  • A cookie is transmitted as a HTTP headers. Many HTTP headers commonly disregard the RFC. For example, the Sec-Ch-Ua header created by Chrome, includes several "bad" characters.

Sec-Ch-Ua: "Chromium";v="92", " Not A;Brand";v="99", "Google Chrome";v="92"

  • "comma" is "disallowed" and it's used all the time.
  • Even if double quotes were "wrong", which they are not, but if they were, there are lots of in-the-wild examples of cookies containing quotes.

For reference, here's the relevant section of RFC 6265

set-cookie-header = "Set-Cookie:" SP set-cookie-string
 set-cookie-string = cookie-pair *( ";" SP cookie-av )
 cookie-pair       = cookie-name "=" cookie-value
 cookie-name       = token
 cookie-value      = *cookie-octet / ( DQUOTE *cookie-octet DQUOTE )
 cookie-octet      = %x21 / %x23-2B / %x2D-3A / %x3C-5B / %x5D-7E
                       ; US-ASCII characters excluding CTLs,
                       ; whitespace DQUOTE, comma, semicolon,
                       ; and backslash

Where one can see whitespace DQUOTE is disallowed and DQUOTE is allowed.

Zamicol
  • 4,626
  • 1
  • 37
  • 42
  • 1
    `"` is [not allowed](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie) in HTTP cookies. But you can always URL-encode it. – rustyx Jul 29 '21 at 21:34
  • See also https://stackoverflow.com/a/51173053/1923095 Where JSON is stored in cookies. – Zamicol Jul 29 '21 at 22:02
  • The allowed bytes in a cookie value are pretty limited. You just cannot have arbitrary JSON as a cookie value. – Volker Jul 30 '21 at 05:32

2 Answers2

2

HTTP cookies are allowed to have double quotes.

Are you sure? rfc6265 states:

set-cookie-header = "Set-Cookie:" SP set-cookie-string
set-cookie-string = cookie-pair *( ";" SP cookie-av )
cookie-pair       = cookie-name "=" cookie-value
cookie-name       = token
cookie-value      = *cookie-octet / ( DQUOTE *cookie-octet DQUOTE )
cookie-octet      = %x21 / %x23-2B / %x2D-3A / %x3C-5B / %x5D-7E
                       ; US-ASCII characters excluding CTLs,
                       ; whitespace DQUOTE, comma, semicolon,
                       ; and backslash

So it appears that Go is following the specification (the spec previously definesDQUOTE to mean double quote).

See this issue for further information.

Brits
  • 14,829
  • 2
  • 18
  • 31
  • A cookie value is explicitly allowed to have double quotes: `cookie-value = *cookie-octet / ( DQUOTE *cookie-octet DQUOTE )` – Zamicol Jul 29 '21 at 21:39
  • 4
    Quotes may be used to wrap the octet; however, if present, these will generally be stripped when the value is extracted. See [MDN](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie) - "A can optionally be wrapped in double quotes and include any US-ASCII characters excluding control characters, Whitespace, double quotes, comma, semicolon, and backslash." – Brits Jul 29 '21 at 21:43
  • No, it is not stripped, but if it was, stripped by who? The browser and tools like curl preserve quotes. Inside `quoted_string`, quote and backslash simply need to be escaped with a backslash. They can't be included without escaping, but may be included with escaping. – Zamicol Nov 14 '22 at 23:36
  • Sorry - I'm confused. Your original question was asking why the quotes are stripped but now you say "it is not stripped"? In the case of Go `SetCookie` [strips the quotes here](https://cs.opensource.google/go/go/+/refs/tags/go1.19.3:src/net/http/cookie.go;l=403;drc=c55d184151d2a1d313b96d8e835341cd1f0ec0c5). See the issue I linked for the thoughts of some of the authors of the standard library (discussing further here is of minimal value given the statements there). – Brits Nov 15 '22 at 03:32
  • Sorry, see my answer below. https://stackoverflow.com/a/68582863/1923095 The question was "how" not "why". Imho, Go was wrong to strip quotes so cavalierly, just as that same section of code used to be wrong in stripping commas. See https://github.com/Cyphrme/Coze/blob/10897b1a0c6ddbecc1f892759e440f254a625edf/docs/http_headers.md?plain=1#L124 Consider this Chrome HTTP header: `Sec-Ch-Ua: "Chromium";v="92", " Not A;Brand";v="99", "Google Chrome";v="92"` which is considered valid HTTP. – Zamicol Nov 15 '22 at 05:56
  • 1
    "how" not "why" - The how is fairly simple - copy the `http.Cookie` code and alter it to meet your needs. There are a range of specs in this area with conflicting info, and common applications that ignore all of the specs. The Go authors had to make a decision and they decided to remove quotes ([here](https://github.com/golang/go/issues/46443) is another open issue regarding quotes). – Brits Nov 15 '22 at 07:13
  • Fantastic reference. Thank you for the link. – Zamicol Nov 15 '22 at 16:17
-1

Yes. Double quotes are allowed in cookies and other HTTP headers. Double quotes are also used to escape characters that would be otherwise invalid.

Here's a way to manually set a cookie, where w is the http.responseWriter and b is the bytes of the cookie. Max-Age is in seconds and 999999999 is ~31.69 years.

w.Header().Set("Set-Cookie", "your_cookie_name="+string(b)+"; Path=/; Domain=localhost; Secure; Max-Age=999999999; SameSite=Strict")

Since you'll probably use cURL to test sending cookies to the server, here's a useful test:

curl --insecure --cookie 'test1={"test1":"v1"}; test2={"test2":"v2"}'  https://localhost:8081/

Which results in a HTTP header like the following:

GET / HTTP/2.0
Host: localhost:8081
Accept: */*
Cookie: test1={"test1":"v1"}; test2={"test2":"v2"}
User-Agent: curl/7.0.0

Also note, many of the RFC rules are ignored all the time, especially commas. For example, Chrome sets this header:

Sec-Ch-Ua: "Google Chrome";v="107", "Chromium";v="107", "Not=A?Brand";v="24"

Gasp! Is uses commas and other things! It is well established that commas in HTTP headers are okay, even though the RFC appears to say otherwise.

Note that the Chrome header uses spaces, many double quotes, commas, special characters, and semi colon. Chrome here uses double quotes around many values needing escaping, and that's the right way to be compliant with the RFC.

Note that the cookie RFC 6265 is a proposal and has been for 11 years. There are reasons for that. Knowing that cookies are just a HTTP header, look at the accepted HTTP RFC for quoted string semantic for header values:

HTTP RFC 7230 3.2.6.

These characters are included for quoted-string:

HTAB, SP !#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[]^_`abcdefghijklmnopqrstuvwxyz{|}~ %x80-FF

The characters " and / may be included if escaped.

Zamicol
  • 4,626
  • 1
  • 37
  • 42