forked from orbit-oss/flask
Merge pull request #2607 from FadhelC/SameSite-cookie-feature
Added support for cookie SameSite attribute
This commit is contained in:
commit
e21abd9da5
6 changed files with 67 additions and 7 deletions
|
|
@ -208,6 +208,16 @@ The following configuration values are used internally by Flask:
|
|||
|
||||
Default: ``False``
|
||||
|
||||
.. py:data:: SESSION_COOKIE_SAMESITE
|
||||
|
||||
Restrict how cookies are sent with requests from external sites. Can
|
||||
be set to ``'Lax'`` (recommended) or ``'Strict'``.
|
||||
See :ref:`security-cookie`.
|
||||
|
||||
Default: ``None``
|
||||
|
||||
.. versionadded:: 1.0
|
||||
|
||||
.. py:data:: PERMANENT_SESSION_LIFETIME
|
||||
|
||||
If ``session.permanent`` is true, the cookie's expiration will be set this
|
||||
|
|
@ -361,13 +371,15 @@ The following configuration values are used internally by Flask:
|
|||
``LOGGER_HANDLER_POLICY``, ``EXPLAIN_TEMPLATE_LOADING``
|
||||
|
||||
.. versionchanged:: 1.0
|
||||
|
||||
``LOGGER_NAME`` and ``LOGGER_HANDLER_POLICY`` were removed. See
|
||||
:ref:`logging` for information about configuration.
|
||||
|
||||
Added :data:`ENV` to reflect the :envvar:`FLASK_ENV` environment
|
||||
variable.
|
||||
|
||||
Added :data:`SESSION_COOKIE_SAMESITE` to control the session
|
||||
cookie's ``SameSite`` option.
|
||||
|
||||
|
||||
Configuring from Files
|
||||
----------------------
|
||||
|
|
@ -635,4 +647,3 @@ Example usage for both::
|
|||
# or via open_instance_resource:
|
||||
with app.open_instance_resource('application.cfg') as f:
|
||||
config = f.read()
|
||||
|
||||
|
|
|
|||
|
|
@ -184,6 +184,9 @@ contains the same data. ::
|
|||
|
||||
- https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-XSS-Protection
|
||||
|
||||
|
||||
.. _security-cookie:
|
||||
|
||||
Set-Cookie options
|
||||
~~~~~~~~~~~~~~~~~~
|
||||
|
||||
|
|
@ -194,17 +197,21 @@ They can be set on other cookies too.
|
|||
- ``Secure`` limits cookies to HTTPS traffic only.
|
||||
- ``HttpOnly`` protects the contents of cookies from being read with
|
||||
JavaScript.
|
||||
- ``SameSite`` ensures that cookies can only be requested from the same
|
||||
domain that created them. It is not supported by Flask yet.
|
||||
- ``SameSite`` restricts how cookies are sent with requests from
|
||||
external sites. Can be set to ``'Lax'`` (recommended) or ``'Strict'``.
|
||||
``Lax`` prevents sending cookies with CSRF-prone requests from
|
||||
external sites, such as submitting a form. ``Strict`` prevents sending
|
||||
cookies with all external requests, including following regular links.
|
||||
|
||||
::
|
||||
|
||||
app.config.update(
|
||||
SESSION_COOKIE_SECURE=True,
|
||||
SESSION_COOKIE_HTTPONLY=True,
|
||||
SESSION_COOKIE_SAMESITE='Lax',
|
||||
)
|
||||
|
||||
response.set_cookie('username', 'flask', secure=True, httponly=True)
|
||||
response.set_cookie('username', 'flask', secure=True, httponly=True, samesite='Lax')
|
||||
|
||||
Specifying ``Expires`` or ``Max-Age`` options, will remove the cookie after
|
||||
the given time, or the current time plus the age, respectively. If neither
|
||||
|
|
@ -237,6 +244,9 @@ values (or any values that need secure signatures).
|
|||
- https://developer.mozilla.org/en-US/docs/Web/HTTP/Cookies
|
||||
- https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie
|
||||
|
||||
.. _samesite_support: https://caniuse.com/#feat=same-site-cookie-attribute
|
||||
|
||||
|
||||
HTTP Public Key Pinning (HPKP)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
|
|
|
|||
|
|
@ -284,6 +284,7 @@ class Flask(_PackageBoundObject):
|
|||
'SESSION_COOKIE_PATH': None,
|
||||
'SESSION_COOKIE_HTTPONLY': True,
|
||||
'SESSION_COOKIE_SECURE': False,
|
||||
'SESSION_COOKIE_SAMESITE': None,
|
||||
'SESSION_REFRESH_EACH_REQUEST': True,
|
||||
'MAX_CONTENT_LENGTH': None,
|
||||
'SEND_FILE_MAX_AGE_DEFAULT': timedelta(hours=12),
|
||||
|
|
|
|||
|
|
@ -249,6 +249,13 @@ class SessionInterface(object):
|
|||
"""
|
||||
return app.config['SESSION_COOKIE_SECURE']
|
||||
|
||||
def get_cookie_samesite(self, app):
|
||||
"""Return ``'Strict'`` or ``'Lax'`` if the cookie should use the
|
||||
``SameSite`` attribute. This currently just returns the value of
|
||||
the :data:`SESSION_COOKIE_SAMESITE` setting.
|
||||
"""
|
||||
return app.config['SESSION_COOKIE_SAMESITE']
|
||||
|
||||
def get_expiration_time(self, app, session):
|
||||
"""A helper method that returns an expiration date for the session
|
||||
or ``None`` if the session is linked to the browser session. The
|
||||
|
|
@ -362,6 +369,7 @@ class SecureCookieSessionInterface(SessionInterface):
|
|||
|
||||
httponly = self.get_cookie_httponly(app)
|
||||
secure = self.get_cookie_secure(app)
|
||||
samesite = self.get_cookie_samesite(app)
|
||||
expires = self.get_expiration_time(app, session)
|
||||
val = self.get_signing_serializer(app).dumps(dict(session))
|
||||
response.set_cookie(
|
||||
|
|
@ -371,5 +379,6 @@ class SecureCookieSessionInterface(SessionInterface):
|
|||
httponly=httponly,
|
||||
domain=domain,
|
||||
path=path,
|
||||
secure=secure
|
||||
secure=secure,
|
||||
samesite=samesite
|
||||
)
|
||||
|
|
|
|||
|
|
@ -319,6 +319,7 @@ def test_session_using_session_settings(app, client):
|
|||
SESSION_COOKIE_DOMAIN='.example.com',
|
||||
SESSION_COOKIE_HTTPONLY=False,
|
||||
SESSION_COOKIE_SECURE=True,
|
||||
SESSION_COOKIE_SAMESITE='Lax',
|
||||
SESSION_COOKIE_PATH='/'
|
||||
)
|
||||
|
||||
|
|
@ -333,6 +334,34 @@ def test_session_using_session_settings(app, client):
|
|||
assert 'path=/' in cookie
|
||||
assert 'secure' in cookie
|
||||
assert 'httponly' not in cookie
|
||||
assert 'samesite' in cookie
|
||||
|
||||
|
||||
def test_session_using_samesite_attribute(app, client):
|
||||
@app.route('/')
|
||||
def index():
|
||||
flask.session['testing'] = 42
|
||||
return 'Hello World'
|
||||
|
||||
app.config.update(SESSION_COOKIE_SAMESITE='invalid')
|
||||
|
||||
with pytest.raises(ValueError):
|
||||
client.get('/')
|
||||
|
||||
app.config.update(SESSION_COOKIE_SAMESITE=None)
|
||||
rv = client.get('/')
|
||||
cookie = rv.headers['set-cookie'].lower()
|
||||
assert 'samesite' not in cookie
|
||||
|
||||
app.config.update(SESSION_COOKIE_SAMESITE='Strict')
|
||||
rv = client.get('/')
|
||||
cookie = rv.headers['set-cookie'].lower()
|
||||
assert 'samesite=strict' in cookie
|
||||
|
||||
app.config.update(SESSION_COOKIE_SAMESITE='Lax')
|
||||
rv = client.get('/')
|
||||
cookie = rv.headers['set-cookie'].lower()
|
||||
assert 'samesite=lax' in cookie
|
||||
|
||||
|
||||
def test_session_localhost_warning(recwarn, app, client):
|
||||
|
|
|
|||
2
tox.ini
2
tox.ini
|
|
@ -16,7 +16,7 @@ deps =
|
|||
blinker
|
||||
python-dotenv
|
||||
|
||||
lowest: Werkzeug==0.9
|
||||
lowest: Werkzeug==0.14
|
||||
lowest: Jinja2==2.4
|
||||
lowest: itsdangerous==0.21
|
||||
lowest: Click==4.0
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue