diff --git a/doc/CHANGES.rst b/doc/CHANGES.rst index 477ad29f1f..b13bdcbb90 100644 --- a/doc/CHANGES.rst +++ b/doc/CHANGES.rst @@ -18,6 +18,9 @@ http://docs.zope.org/zope2/ - Removed docstrings from some methods to avoid publishing them. From Products.PloneHotfix20160419. [maurits] +- Add support to SameSite cookie in ``ZPublisher.HTTPResponse``: + https://tools.ietf.org/html/draft-west-first-party-cookies-07 + 2.13.24 (2016-02-29) -------------------- diff --git a/src/ZPublisher/HTTPResponse.py b/src/ZPublisher/HTTPResponse.py index da6b2cb221..002737d15d 100644 --- a/src/ZPublisher/HTTPResponse.py +++ b/src/ZPublisher/HTTPResponse.py @@ -903,6 +903,12 @@ def _cookie_list(self): # and block read/write access via JavaScript elif name == 'http_only' and v: cookie = '%s; HTTPOnly' % cookie + # Some browsers recognize the SameSite cookie attribute + # and do not send the cookie along with cross-site requests + # providing some protection against CSRF attacks + # https://tools.ietf.org/html/draft-west-first-party-cookies-07 + elif name == 'same_site': + cookie = '%s; SameSite=%s' % (cookie, v) cookie_list.append(('Set-Cookie', cookie)) # Should really check size of cookies here! diff --git a/src/ZPublisher/tests/testHTTPResponse.py b/src/ZPublisher/tests/testHTTPResponse.py index 4b94eb52d0..42946973a8 100644 --- a/src/ZPublisher/tests/testHTTPResponse.py +++ b/src/ZPublisher/tests/testHTTPResponse.py @@ -319,6 +319,19 @@ def test_setCookie_w_httponly_false_value(self): self.assertEqual(len(cookie_list), 1) self.assertEqual(cookie_list[0], ('Set-Cookie', 'foo="bar"')) + def test_setCookie_w_same_site(self): + response = self._makeOne() + response.setCookie('foo', 'bar', same_site='Strict') + cookie = response.cookies.get('foo', None) + self.assertEqual(len(cookie), 3) + self.assertEqual(cookie.get('value'), 'bar') + self.assertEqual(cookie.get('same_site'), 'Strict') + self.assertEqual(cookie.get('quoted'), True) + cookies = response._cookie_list() + self.assertEqual(len(cookies), 1) + self.assertEqual(cookies[0], + ('Set-Cookie', 'foo="bar"; SameSite=Strict')) + def test_setCookie_unquoted(self): response = self._makeOne() response.setCookie('foo', 'bar', quoted=False)