Skip to content

Commit

Permalink
Use 'Secure' Attribute with Sensitive Cookie in HTTPS Session #209
Browse files Browse the repository at this point in the history
  • Loading branch information
ikus060 committed Sep 12, 2022
1 parent d4dcb80 commit f2de237
Show file tree
Hide file tree
Showing 4 changed files with 43 additions and 12 deletions.
10 changes: 9 additions & 1 deletion README.md
Expand Up @@ -107,9 +107,17 @@ Professional support for Rdiffweb is available by contacting [IKUS Soft](https:/

# Changelog

## 2.4.2 (2022-09-08)

This releases include a security fix. If you are using an earlier version, you should upgrade to this release immediately.

* Use 'Secure' Attribute with Sensitive Cookie in HTTPS Session. [CVE-2022-3174](https://nvd.nist.gov/vuln/detail/CVE-2022-3174) #209

## 2.4.1 (2022-09-08)

* Add Clickjacking Defense
This releases include a security fix. If you are using an earlier version, you should upgrade to this release immediately.

* Add Clickjacking Defense [CVE-2022-3167](https://nvd.nist.gov/vuln/detail/CVE-2022-3167)
* Drop Ubuntu Hirsute & Impish (End-of-life)

## 2.4.0 (2022-06-21)
Expand Down
Expand Up @@ -22,26 +22,42 @@
import rdiffweb.test


class CsrfTest(rdiffweb.test.WebCase):
class SecureHeadersTest(rdiffweb.test.WebCase):

login = True

def test_samesite_lax(self):
def test_cookie_samesite_lax(self):
# Given a request made to rdiffweb
# When receiving the response
self.getPage('/')
# Then the header contains Set-Cookie with SameSite=Lax
cookie = self.assertHeader('Set-Cookie')
self.assertIn('SameSite=Lax', cookie)

def test_samesite_lax_without_session(self):
def test_cookie_samesite_lax_without_session(self):
# Given not a client sending no cookie
self.cookies = None
# When a query is made to a static path (without session)
self.getPage('/static/blue.css')
# Then Set-Cookie is not defined.
self.assertNoHeader('Set-Cookie')

def test_cookie_with_https(self):
# Given an https request made to rdiffweb
self.getPage('/', headers=[('X-Forwarded-Proto', 'https')])
# When receiving the response
# Then the header contains Set-Cookie with Secure
cookie = self.assertHeader('Set-Cookie')
self.assertIn('Secure', cookie)

def test_cookie_with_http(self):
# Given an https request made to rdiffweb
self.getPage('/')
# When receiving the response
# Then the header contains Set-Cookie with Secure
cookie = self.assertHeader('Set-Cookie')
self.assertNotIn('Secure', cookie)

def test_get_with_wrong_origin(self):
# Given a GET request made to rdiffweb
# When the request is made using a different origin
Expand Down
4 changes: 2 additions & 2 deletions rdiffweb/rdw_app.py
Expand Up @@ -38,7 +38,7 @@
import rdiffweb.tools.i18n
import rdiffweb.tools.proxy
import rdiffweb.tools.ratelimit
import rdiffweb.tools.security
import rdiffweb.tools.secure_headers
from rdiffweb.controller import Controller
from rdiffweb.controller.api import ApiPage
from rdiffweb.controller.dispatch import static # noqa
Expand All @@ -63,6 +63,7 @@


@cherrypy.tools.proxy()
@cherrypy.tools.secure_headers()
class Root(LocationsPage):
def __init__(self):
self.login = LoginPage()
Expand Down Expand Up @@ -170,7 +171,6 @@ def __init__(self, cfg):
'tools.auth_form.on': True,
'tools.currentuser.on': True,
'tools.currentuser.userobj': lambda username: self.store.get_user(username),
'tools.csrf.on': True,
'tools.i18n.on': True,
'tools.i18n.default': 'en_US',
'tools.i18n.mo_dir': pkg_resources.resource_filename('rdiffweb', 'locales'), # @UndefinedVariable
Expand Down
19 changes: 13 additions & 6 deletions rdiffweb/tools/security.py → rdiffweb/tools/secure_headers.py
Expand Up @@ -32,12 +32,13 @@
http.cookies.Morsel._reserved['samesite'] = 'SameSite'


class CsrfAuth(HandlerTool):
class SecureHeaders(HandlerTool):
"""
This tool provide CSRF mitigation.
* Define X-Frame-Options = DENY
* Define Cookies SameSite=Lax
* Define Cookies Secure when https is detected
* Validate `Origin` and `Referer` on POST, PUT, PATCH, DELETE
Ref.:
Expand All @@ -46,7 +47,7 @@ class CsrfAuth(HandlerTool):
"""

def __init__(self):
HandlerTool.__init__(self, self.run, name='csrf')
HandlerTool.__init__(self, self.run, name='secure_headers')
# Make sure to run before authform (priority 71)
self._priority = 71

Expand All @@ -58,12 +59,18 @@ def _set_headers(self):
response = cherrypy.serving.response
# Define X-Frame-Options to avoid Clickjacking
response.headers['X-Frame-Options'] = 'DENY'
# Awaiting bug fix in cherrypy
# https://github.com/cherrypy/cherrypy/issues/1767
# Force SameSite to Lax

# Enforce security on cookies
cookie = response.cookie.get('session_id', None)
if cookie:
# Awaiting bug fix in cherrypy
# https://github.com/cherrypy/cherrypy/issues/1767
# Force SameSite to Lax
cookie['samesite'] = 'Lax'
# Check if https is enabled
https = cherrypy.request.base.startswith('https')
if https:
cookie['secure'] = 1

def run(self):
if cherrypy.request.method in ['POST', 'PUT', 'PATCH', 'DELETE']:
Expand All @@ -73,4 +80,4 @@ def run(self):
raise cherrypy.HTTPError(403, 'Unexpected Origin header')


cherrypy.tools.csrf = CsrfAuth()
cherrypy.tools.secure_headers = SecureHeaders()

0 comments on commit f2de237

Please sign in to comment.