Unable to access site cookie after LTI Launch - cookies

I have a small LTI application that integrates with canvas, and after the LTI launch I can't access the cookie. This is failing in Safari (always) and Chrome (sometimes).
I am forcing the SameSite=LAX field of the cookie.
I'm not sure what else I should try.

There have been numerous changes in Chrome (and other browsers) regarding cookies and iframe.. For LTI 1.3 launches this is extra difficult because of how you need to track the state of the launch in the cookie while processing the OIDC flow.
The basics of what is changing is there is now a 'SameSite' cookie policy, where Only cookies set as SameSite=None; Secure will be available in third-party contexts, provided they are being accessed from secure connections. So marking the cookies as Secure and HTTP-Only is a must in addition to the SameSite=None
Also in Safari, the third-party frame will have to request access to the storage API before the cookie will be accessible.
Firefox is using a partitioned approach to the storage, and so the frame will behave as normal unless you then open your application as a new window then the cookie store may or may not follow depending on how the new window was created.
Cookie Status is an excellent resource to track how third party cookies work in the different browsers and what you should change to make it work.

Related

Storing Access Token in httponly Cookie but user can still see it in Network tab of Chrome Dev Tools?

I am using django to create a python backend and am storing the user's access token and refresh token in httponly cookies so I can authenticate requests to my backend.
1) Is this the right way to do this?
2) I know that httponly prevents seeing the cookie using 'document.cookie', but you can still see the cookie by analyzing the network tab in Chrome Dev Tools. Is this fine because only the user can see it (not other people)? Or is this still bad?
I can't answer #1 authoritatively but it sounds fine to me. For #2, httponly is there to protect the cookie from being scraped by malicious code, not to keep the user from being able to find it in the developer tools. Even if it wasn't visible in the Network tab, it would be visible under Application (or Storage in Firefox). This makes sense, because the user should always be able to see (and delete) individual cookies, regardless of how the server defined them.

Safari not including cookies in request, but Safari incognito does?

So with my app I allow our users to set their own custom domiain which points to our hosted app on netlify. This works fine, but now the frontend is obviously talking to an api which lives on a different domain.
On the auth cookie I send back from the api, I have SameSite=None which works on all other browsers except for safari where the request does not include the cookie. However, if I go on Safari in incognito, it does include the cookie on the request? My question is:
Why does this work in safari incognito and not normal?
Is there a way to make this work in normal safari?
Here is a more thorough example:
front end:
customersdomain.com
api:
api.myapp.com
Cookie
x-refresh: <cookie_val>
SameSite: none
HttpOnly: true
Secure: true
expires: 1 month
domain: api.myapp.com
My cors has allow credentials set as well and in the request I have credentials set to include.
In Safari 13.1, in order for third party requests to have access to credentials/cookies, you must use the Storage Access API to request access, via an iframe.
This may affect the workings of your app considerably. Please read WebKit's recent blog post for more information about the latest changes to their Intelligent Tracking Prevention.
Before Safari 13.1, there were some temporary compatibility fixes as detailed here to allow for third party requests to have access to cookies. My guess is that the third party domain was flagged by Safari on your device as being a domain that has the potential to track users, and blocked from having access to cookies by default. The domain will remain blocked for as long as you don't clear the cache on Safari. By using an incognito window, the domain was no longer blocked for that session.
SameSite=None compatibility was added to Safari 13, so this shouldn't have contributed to any of your issues.

How do web apps login you automatically on revisit without exposing the stored cookies or local storage to XSS?

There are a lot of web apps, Facebook, Google, Slack, Quora etc. that re-login you on each visit, however if they use a cookie or the browser's local storage for storing a token or login information, those could be hijacked by a third party script. How do the web apps achieve protection against this?
A script to be able to access a cookie of a certain origin (eg: facebook.com) would have to have been downloaded from the same origin, this is the same origin policy and is enforced by browsers.
Now, as you mention, an exception to this scenario would be when an attacker would manage to inject a script in the target website (XSS) so that it would be executed by another user while accessing that site, in this case the malicious script would have access to those cookies, to protect against this kind of scenarios it was introduced the HttpOnly flag, designed to make selected cookies inaccessible to client side scripts.

Why does Google Analytics/Mixpanel/etc. send cookies to my server?

Let's say I have a website at http://domain.org on which I also have Google Analytics (GA) and Mixpanel (MP) Javascript tracking codes. Both MP and GA store cookies on the user's browser for my entire domain including sub domains (.domain.org).
Because of this every time I do a request to any URL in this entire domain, the cookies for GA and MP are sent along.
New Relic on the other hand store their cookie on the bam.nr-data.net domain.
Why do GA and MP do this? Only in a situation of strange backend hackings one would use the values in these cookies on the backend.
Google Analytics uses first party cookies (by injecting the javascript code that's setting the cookie into the web site source) because 3rd party cookies are often blocked (in many browsers they are blocked by default).
Since they are set under your domain name they are sent to your server. That's pretty much a side effect of the original intent (which is to make the tracking more reliable), your are not supposed to use them in your backend.
When setting up Google Analytics you can use the cookie domain parameter to limit ga cookies to a specific part of your domain/subdomain. You cannot, to the best of my knowledge, make GA use a third party cookie.
On a related note, if your goal is to avoid sending the cookie data with each request, you can tell Google Analytics to use localStorage (instead of cookies) to store the client ID.
Here's a thread on the HTML5Boilerplate repo discussing implementation and the pros and cons of such an approach.
The TL;DR is if you don't have to support IE7 and older, and if you're not tracking across multiple sub-domains, you can use localStorage with no problems.

CORS, withCredentials and third party cookies

I'm trying to do a CORS GET that sends the cookie along with it. I've set all the headers (access-control-allow-origin, access-control-allow-credentials, access-control-allow-headers) in the server and am using withCredentials: true and crossDomain: true in the jquery ajax request. Everything works when I tell my browser to allow third-party cookies. Is there any way to do this without forcing visitors to allow third party cookies? I've even tried redirecting the user and redirecting back, but CORS will refuse to send the cookie along. :/
I've tried doing the CORS request via ajax, as well as via an iframe.
I don't think it is possible. See my (old but relevant) blog post on this.
The only bullet-proof way is to use 1st-party cookies (that is, open window in a top-level window like a separate tab, or redirect current window).
In some cases it is not necessary though. Browsers have slightly different notions of what third-party cookie is, and default behavior is also different. This post has a nice overview on these details. So in some cases you could do tricks to enable (or at least detect) use of cookies on the page.
Other workarounds include putting one server under a subdomain of the other (subdomains are usually not considered 3rd-party), or changing the flow so that the user is authenticated by other means than cookies.
if you set cookie (origin 2 set cookie) you should know third party cookie will be used, but if you only get cookie (only send cookie for origin 2 without setting in response) there is no reason third party cookie play a role.
so i think you set a cookie in origin 2 and because of that force you enable third party cookie.
Note that cookies set in CORS responses are subject to normal
third-party cookie policies. In the example above, the page is loaded
from foo.example but the cookie on line 19 is sent by bar.other, and
would thus not be saved if the user's browser is configured to reject
all third-party cookies.
Cross-Origin Resource Sharing mozilla.org