Django 2.1 default of samesite=Lax for Session and CSRF cookies cause issues on Safari 12

1506 views
Skip to first unread message

Flávio Junior

unread,
Mar 13, 2019, 4:48:07 PM3/13/19
to Django developers (Contributions to Django itself)
Hi folks,
after upgrading to Django 2.1, we noticed many occurrences of 403 CSRF errors for Safari 12 users.
After days debugging the problem, we've pinpointed the issue to the Webkit Bug 188165: https://bugs.webkit.org/show_bug.cgi?id=188165

In simple terms, Safari 12 implementation of samesite=Lax cookies is wrong.
It causes issues in many common request flows, like the OpenIdConnect flow for ASP.NET Core 2.1.

For Django, the issue might be considered even worse. If the user comes from a cross-site redirection (like a tracker link from an email provider), Safari doesn't send samesite=lax cookies on the request. This causes multiple issues. We've been able to identify those three, but maybe there are more:
- User will not be logged in if SESSION_COOKIE_SAMESITE = 'Lax'. That behavior is only expected if 'Strict', AFAIK.
- User will not be able to make AJAX POST requests if CSRF_COOKIE_SAMESITE = 'Lax', because JS code won't be able to read the CSRF cookie.
- POSTs on other open tabs/windows will fail if CSRF_COOKIE_SAMESITE = 'Lax', because Safari triggered a CSRF cookie update after the first request without cookies.

Those issues do not happen on Chrome, nor Firefox.
Full Django project example of the problem above is available here: ​https://github.com/vintasoftware/safari-samesite-cookie-issue

Since Safari 12 is the current stable version and it's widely deployed on iOS devices, I believe the Django default for CSRF_COOKIE_SAMESITE and SESSION_COOKIE_SAMESITE should be None, not Lax.

Upgrading to Django 2.1 caused this issue to us and frustrated many users. I think a more conservative default is necessary here to avoid breaking common use cases like visiting a web app page logged in after receiving a transactional or scheduled email.
If you do not wish to change the defaults, IMHO at least a warning should be placed on the documentation. For comparison, Microsoft issued a security advisory describing the bug on ASP.NEThttps://github.com/aspnet/Announcements/issues/318
Please let me know your thoughts, I can help with a PR if needed.

Florian Apolloner

unread,
Mar 15, 2019, 6:09:51 AM3/15/19
to Django developers (Contributions to Django itself)
I am wondering if this also results in https://code.djangoproject.com/ticket/29975 or if this is just a result of their tracking protection. All in all it would be great to know what Safari actually does… (sadly I do not own a Mac :/) I'll dig through #30250 soon.

> - User will not be logged in if SESSION_COOKIE_SAMESITE = 'Lax'. That behavior is only expected if 'Strict', AFAIK.

So this is a Safari bug?

> - User will not be able to make AJAX POST requests if CSRF_COOKIE_SAMESITE = 'Lax', because JS code won't be able to read the CSRF cookie.

I have to reread the specs, but shouldn't httponly yes/no control whether JS can read the data?

Cheers,
Florian

Flávio Junior

unread,
Mar 15, 2019, 9:56:16 AM3/15/19
to Django developers (Contributions to Django itself)
Hi Florian, thanks for your response.

> So this is a Safari bug?

Yes. Lax doesn't work as intended in Safari 12. Bug was confirmed here: https://bugs.webkit.org/show_bug.cgi?id=188165#c37 (comment 37)
Apple also says the newest beta versions of iOS/Mac should fix the issue: https://bugs.webkit.org/show_bug.cgi?id=188165#c43 (comment 43)
I didn't test this yet. Current stable version is still broken, I've confirmed yesterday.

> shouldn't httponly yes/no control whether JS can read the data?

Yes. But, on Django, the default is httponly false for CSRF cookie.
So even without httponly, Safari doesn't allow JS to read the CSRF cookie. Safari also doesn't send the session cookie nor the CSRF cookie during the request (if it comes from a cross-site source, like an email tracker redirection). 
You can reproduce with this Django code: https://github.com/vintasoftware/safari-samesite-cookie-issue 

> sadly I do not own a Mac

If you wish, I can provide you a BrowserStack account, so you can test on Safari from your browser.
Please reach me at flavio at vinta.com.br and I'll send you the credentials.

> I am wondering if this also results in https://code.djangoproject.com/ticket/29975 or if this is just a result of their tracking protection

Yes, I think it's the same problem. I don't think this is a result of the "Protection Against First Party Bounce Trackers" because the issue don't happens if SESSION_COOKIE_SAMESITE = None and CSRF_COOKIE_SAMESITE = None, which is the behavior of Django < 2.1.
This is an issue with Django 2.1 defaults + Safari 12 + cross-site redirection.
That's why I suggested a change on defaults, or at least some clear warning.

Happy to answer more questions or to help any core developer to reproduce the issue.

Cheers,
Flávio.

Florian Apolloner

unread,
Mar 15, 2019, 10:38:17 AM3/15/19
to Django developers (Contributions to Django itself)
Hi Flavio,


On Friday, March 15, 2019 at 2:56:16 PM UTC+1, Flávio Junior wrote:
> shouldn't httponly yes/no control whether JS can read the data?

Yes. But, on Django, the default is httponly false for CSRF cookie.
So even without httponly, Safari doesn't allow JS to read the CSRF cookie. Safari also doesn't send the session cookie nor the CSRF cookie during the request (if it comes from a cross-site source, like an email tracker redirection). 

Oh sorry I was being unclear here. What I wanted to say/ask is whether you had set httponly because I couldn't imagine the SameSite policy to affect that. Thanks for clearing that up.

 
> I am wondering if this also results in https://code.djangoproject.com/ticket/29975 or if this is just a result of their tracking protection

Yes, I think it's the same problem. I don't think this is a result of the "Protection Against First Party Bounce Trackers" because the issue don't happens if SESSION_COOKIE_SAMESITE = None and CSRF_COOKIE_SAMESITE = None, which is the behavior of Django < 2.1.
This is an issue with Django 2.1 defaults + Safari 12 + cross-site redirection.
That's why I suggested a change on defaults, or at least some clear warning.

Interesting, it would certainly be nice if I/someone could verify this. If setting the policy from lax to none also fixes the password reset issue, then I am mostly in favor of a "warning" somewhere for now. I do not think that a simple default change is a good idea in the long run. I'll mail you later for credentials (If I don't find some lying around in the company).

As for the beta versions, is it possibly that you would only update safari or would you have to update your whole iOS/macOS? Ie could you test with https://developer.apple.com/safari/technology-preview/ if the issue is gone again on your mac?

Cheers,
Florian

Mat Gadd

unread,
Mar 18, 2019, 7:26:36 AM3/18/19
to django-d...@googlegroups.com
As the author of 29975, I figured I'd weigh in here.

I've set our site to use SESSION_COOKIE_SAMESITE = None and CSRF_COOKIE_SAMESITE = None and tested password reset links with and without click tracking (in additional to Gmail's tracking), and it certainly appears to fix the issue with Safari on macOS and iOS for me.

Weirdly, it appears that Gmail isn't inserting click tracking for the plain password reset link, but when I use my own URL shortener, I can also see the google.com redirect in play. It may just be dev tools behaving strangely, or perhaps Google have tried to avoid adding their tracker for password reset links. Who knows!

--
You received this message because you are subscribed to the Google Groups "Django developers (Contributions to Django itself)" group.
To unsubscribe from this group and stop receiving emails from it, send an email to django-develop...@googlegroups.com.
To post to this group, send email to django-d...@googlegroups.com.
Visit this group at https://groups.google.com/group/django-developers.
To view this discussion on the web visit https://groups.google.com/d/msgid/django-developers/70770663-f56c-4c9c-b75b-961a1d6df964%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

René Fleschenberg

unread,
Mar 18, 2019, 1:36:02 PM3/18/19
to django-d...@googlegroups.com
Hi.

On 3/18/19 12:26 PM, Mat Gadd wrote:
> Weirdly, it appears that Gmail isn't inserting click tracking for the
> plain password reset link, but when I use my own URL shortener, I can
> also see the google.com <http://google.com> redirect in play. It may
> just be dev tools behaving strangely, or perhaps Google have tried to
> avoid adding their tracker for password reset links. Who knows!

I did not take the time to analyze this as thoroughly as I should have,
but from a cursory look, it seemed to me that Gmail rewrites the links
using Javascript, and only when you click on them. Could that explain
why your observations?

--
René

Mat Gadd

unread,
Mar 18, 2019, 1:38:13 PM3/18/19
to django-d...@googlegroups.com
You're correct that is how they rewrite the URLs, but I did know that and expect that to be the case.
> --
> You received this message because you are subscribed to the Google Groups "Django developers (Contributions to Django itself)" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to django-develop...@googlegroups.com.
> To post to this group, send email to django-d...@googlegroups.com.
> Visit this group at https://groups.google.com/group/django-developers.
> To view this discussion on the web visit https://groups.google.com/d/msgid/django-developers/0e45692d-1974-25ff-c938-f4770f8ee786%40fleschenberg.net.

Flávio Junior

unread,
Mar 18, 2019, 5:50:17 PM3/18/19
to Django developers (Contributions to Django itself)
Hey Mat, thanks for the input. Good to know SESSION_COOKIE_SAMESITE = None and CSRF_COOKIE_SAMESITE = None solved the issue 29975. Do you want to post there this solution? I can do it to.
I've updated safari-samesite-cookie-issue to better reproduce the session issue too.

Florian, I didn't know about Safari Technology Preview, thanks! Installed it in my Mac Mojave 10.14.3. Tested again my safari-samesite-cookie-issue project. Issue seems solved.
My Safari is "Release 77 (Safari 12.2, WebKit 14608.1.7.3)".

Good to know it's a matter of time until this issue is solved in the wild. But I still think it's a serious problem: it caused us a major disruption in production because our transactions are very email-based, and therefore rely on third-party redirects.

What are the next steps?
A warning at the docs for these settings?
Happy to help if necessary.

Florian Apolloner

unread,
Mar 19, 2019, 4:58:01 AM3/19/19
to Django developers (Contributions to Django itself)


On Monday, March 18, 2019 at 10:50:17 PM UTC+1, Flávio Junior wrote:
What are the next steps?
A warning at the docs for these settings? 

I guess that is the big question. We'd have to remove the warning "soonish" again I guess once safari is fixed (after all one wants the added security benefit). Maybe a blog post?

Flávio Junior

unread,
Mar 28, 2019, 6:37:21 PM3/28/19
to Django developers (Contributions to Django itself)
So new iOS and Mac minor versions were launched, but issue is still there.
Created a new bug ticket on Webkit and they're being able to reproduce better the problem: https://bugs.webkit.org/show_bug.cgi?id=196375
Hope they can reach a solution soon!

Florian, you mean a blog post on Django's blog or anywhere else?

Florian Apolloner

unread,
Mar 29, 2019, 3:42:34 AM3/29/19
to Django developers (Contributions to Django itself)


On Thursday, March 28, 2019 at 11:37:21 PM UTC+1, Flávio Junior wrote:
So new iOS and Mac minor versions were launched, but issue is still there.
Created a new bug ticket on Webkit and they're being able to reproduce better the problem: https://bugs.webkit.org/show_bug.cgi?id=196375
Hope they can reach a solution soon!

Ah great, seems the messed up backporting?

Florian, you mean a blog post on Django's blog or anywhere else?

Yes, Django's blog as that would give it some reachability. I just do not have the time to write one myself currently.

Florian Apolloner

unread,
Mar 29, 2019, 4:29:37 AM3/29/19
to Django developers (Contributions to Django itself)
I have just checked and the Django blog uses restructured text (or raw html) for the blog post. So if someone feels like writing a blogpost (I'll take care of formatting and posting) that would be most welcome and amazing! (Sorry for not being able to do it myself).

Cheers,
Florian
Reply all
Reply to author
Forward
0 new messages