Search code examples
gocookiesdouble-quotes

Go: how to not remove double quotes on cookies


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 )

  • ; 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. Of course, the payload cannot be arbitrary, and must be constrained to cookies.

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

  • Go currently has a condition to insert double quote into cookies.

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.

For example, from the author of the RFC,

Set-Cookie: foo="bar" results in a cookie Cookie: foo="bar" 3 4


Solution

  • 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
    

    Although not the case here and the above is compliant with the RFC, 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.