Cookies under Suborigins

Documents are cookie-averse by default in suborigined content
(document.cookie returns the empty string and setting document.cookie does
nothing). Much of our content makes use of Google Analytics and the current
behavior of the analytics script is to silently stop working when cookies
are not working. For us at Google, to achieve broad adoption of Suborigins
in legacy content, it's sufficient to set the 'unsafe-cookies' flag. This
is because, with a few possible exceptions, we do not directly store CSRF
tokens in cookies and the values of JS-accessible cookies are not very
sensitive.

However, for many sites that store CSRF tokens in cookies, the
'unsafe-cookie' will indeed be unsafe. I would for us to consider
alternative designs that would make it easier to adopt Suborigins out of
the box, while still being safe for everyone.

Google Analytics (and I suspect similar products) use cookies to store IDs
for user and session tracking. Analytics, for example, uses the '_ga'
cookie. Nevertheless, to keep existing script working without modification,
it is necessary to permit suborigined content to read and write certain
cookies.

I suspect the reason for using cookies is mainly historical, and
sessionStorage could be used in most cases. However, cookies are
occasionally used is for tracking across subdomains of a TLD and across
HTTP and HTTPS versions of a site, and here, sessionStorage is not a good
replacement.

I briefly looked at the CSRF protection implementation used by Dropbox.
Dropbox stores the CSRF token in a cookie called '__Host-js_csrf' (which is
httponly) as well as a cookie called 't' (which is normally available via
document.cookie). If the suborigned content gets access to the 't' cookie,
it would be able to attack other, non-suborigined, content on the domain.

Dropbox will need to change its CSRF mechanism when adapting applications
for suborigins, though, and I don't think there is a good way to avoid
doing so. It's not safe to reuse the same token among multiple suborigins,
so per-suborigin tokens would have to be used. This simplest way to do this
would probably be to compute tokens as hmac(value=suborigin,
key=site_wide_csrf) and embedding them in HTML.

Considering the three requirements above (compat with legacy tracking
scripts, cross-domain tracking, and compat with CSRF cookies), we can come
up with different designs and see how well they meet the requirements. I've
summarized my findings in the following table. The coumn headings list
requirements and various design ideas are listed in the row headings.



                         | compat w/ legacy | cross-domain | safe w/ legacy
                         | tracking scripts | tracking     | CSRF cookies
=========================+==================+==============+================
No cookies               | No               | No           | Yes
(current implementation) |                  |              |
-------------------------+------------------+--------------+----------------
No cookies restrictions  | Yes              | Yes          | No
-------------------------+------------------+--------------+---------------
Prefixed access only     | No               | No           | No
-------------------------+------------------+--------------+----------------
Transparent prefixes     | Partial*         | No           | Yes
-------------------------+------------------+--------------+----------------
Local cookies            | Partial**        | No           | Yes
-------------------------+------------------+--------------+----------------
Everything but __Host-   | Yes              | Yes          | mostly No
-------------------------+------------------+--------------+----------------
Cookie whitelist         | Yes***           | Yes***       | Yes
-------------------------+------------------+--------------+----------------
Cookie blacklist         | Yes              | Yes          | Yes****

* Yes, but results in cookie inflation and breaks cross-domain tracking.
** Yes, but breaks cross-domain tracking.
*** Yes, but requires configuration.
**** Yes,  but requires and configuration and is dangerous.

Explanation of designs:

No cookies: Document is cookie-averse. Assigning to document.cookie is a
no-op. cookie.document is always blank.

No cookie restrictions: Document gets access to document.cookie as though
it was not suborigined.

Prefixed access only: Document can only get and set cookies whose names
begin with a per-suborigin prefix. Setting document.cookie only works if
the cookie names begins with __Sub_{name}-. document.cookie only exposes
cookies that begin with the same prefix.

Transparent prefixes: Same as above except that prefix are automatically
added when assigning to document.cookie. Reading from document.cookie
returns unprefxed cookies.

Local cookies: document.cookie string is stored in a hidden LocalStorage
field. So assigning to document.cookie works but these cookies are not
included in the Cookie header

Everything but __Host-: Access to cookies is allowed except for __Host-
prefixed cookies.

Cookie whitelist: Cookie access is allowed to cookies whose names are
whitelisted in the Suborigins header. Setting document.cookie is only
allowed if the cookie name is on the whitelist. document.cookie only
exposes cookies whose names are on the whitelist.

Cookie blacklist: Same as above, but with a blacklist.

What does everyone think of these solutions? Are we open to potentially
adopting any of them?

>From the list above, 'local cookies' and 'cookie whitelist' designs meet
most of the requirements. Personally, I think the 'local cookies' solution
would be a useful to have and could be safely enabled by default. The
'cookie whitelist' feature might be useful as well, but is more dangerous
and also requires a whitelist be specified.

-Alex

Received on Tuesday, 9 May 2017 03:39:40 UTC