From 928fd364cf00d228d2d5d8b60d28522c6111ec19 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonel=20C=C3=A2mara?= Date: Thu, 6 Sep 2018 16:16:44 +0100 Subject: [PATCH 1/2] Add SameSite support --- gluon/globals.py | 10 +++++++++- gluon/tests/test_globals.py | 18 ++++++++++++++++++ 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/gluon/globals.py b/gluon/globals.py index 26fba47c..d557294b 100644 --- a/gluon/globals.py +++ b/gluon/globals.py @@ -1075,6 +1075,8 @@ class Session(Storage): scookies['HttpOnly'] = True if self._secure: scookies['secure'] = True + if self._same_site: + scookies['samesite'] = self._same_site def clear_session_cookies(self): request = current.request @@ -1153,6 +1155,12 @@ class Session(Storage): def secure(self): self._secure = True + def samesite(self, mode='Lax'): + if 'samesite' not in Cookie.Morsel._reserved: + # Python version 3.7 and lower needs this + Cookie.Morsel._reserved['samesite'] = 'SameSite' + self._same_site = mode + def forget(self, response=None): self._close(response) self._forget = True @@ -1180,7 +1188,7 @@ class Session(Storage): def _unchanged(self, response): if response.session_new: - internal = ['_last_timestamp', '_secure', '_start_timestamp'] + internal = ['_last_timestamp', '_secure', '_start_timestamp', '_same_site'] for item in self.keys(): if item not in internal: return False diff --git a/gluon/tests/test_globals.py b/gluon/tests/test_globals.py index 666249fa..b8c66dd8 100644 --- a/gluon/tests/test_globals.py +++ b/gluon/tests/test_globals.py @@ -231,6 +231,24 @@ class testResponse(unittest.TestCase): cookie = str(current.response.cookies) self.assertTrue('httponly' not in cookie.lower()) + def test_cookies_samesite(self): + current = setup_clean_session() + current.session._fixup_before_save() + cookie = str(current.response.cookies) + self.assertTrue('samesite' not in cookie.lower()) + + current = setup_clean_session() + current.session.samesite() + current.session._fixup_before_save() + cookie = str(current.response.cookies) + self.assertTrue('samesite=lax' in cookie.lower()) + + current = setup_clean_session() + current.session.samesite('Strict') + current.session._fixup_before_save() + cookie = str(current.response.cookies) + self.assertTrue('samesite=strict' in cookie.lower()) + def test_include_meta(self): response = Response() response.meta[u'web2py'] = 'web2py' From 11b441b77799958436fb8e8b3678aae9b2834892 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonel=20C=C3=A2mara?= Date: Thu, 20 Sep 2018 13:02:09 +0100 Subject: [PATCH 2/2] Make SameSite=Lax the default for all web2py apps --- gluon/globals.py | 11 ++++++++--- gluon/tests/test_globals.py | 15 ++++++++------- 2 files changed, 16 insertions(+), 10 deletions(-) diff --git a/gluon/globals.py b/gluon/globals.py index d557294b..7390a3f9 100644 --- a/gluon/globals.py +++ b/gluon/globals.py @@ -1075,7 +1075,15 @@ class Session(Storage): scookies['HttpOnly'] = True if self._secure: scookies['secure'] = True + if self._same_site is None: + # Using SameSite Lax Mode is the default + # You actually have to call session.samesite(False) if you really + # dont want the extra protection provided by the SameSite header + self._same_site = 'Lax' if self._same_site: + if 'samesite' not in Cookie.Morsel._reserved: + # Python version 3.7 and lower needs this + Cookie.Morsel._reserved['samesite'] = 'SameSite' scookies['samesite'] = self._same_site def clear_session_cookies(self): @@ -1156,9 +1164,6 @@ class Session(Storage): self._secure = True def samesite(self, mode='Lax'): - if 'samesite' not in Cookie.Morsel._reserved: - # Python version 3.7 and lower needs this - Cookie.Morsel._reserved['samesite'] = 'SameSite' self._same_site = mode def forget(self, response=None): diff --git a/gluon/tests/test_globals.py b/gluon/tests/test_globals.py index b8c66dd8..bd78e4e1 100644 --- a/gluon/tests/test_globals.py +++ b/gluon/tests/test_globals.py @@ -232,17 +232,18 @@ class testResponse(unittest.TestCase): self.assertTrue('httponly' not in cookie.lower()) def test_cookies_samesite(self): + # Test Lax is the default mode current = setup_clean_session() current.session._fixup_before_save() cookie = str(current.response.cookies) - self.assertTrue('samesite' not in cookie.lower()) - - current = setup_clean_session() - current.session.samesite() - current.session._fixup_before_save() - cookie = str(current.response.cookies) self.assertTrue('samesite=lax' in cookie.lower()) - + # Test you can disable samesite + current = setup_clean_session() + current.session.samesite(False) + current.session._fixup_before_save() + cookie = str(current.response.cookies) + self.assertTrue('samesite' not in cookie.lower()) + # Test you can change mode current = setup_clean_session() current.session.samesite('Strict') current.session._fixup_before_save()