# HG changeset patch # User Thierry Florac # Date 1506603764 -7200 # Node ID e3f804db3e6f9b8911a15763b4a4b4f8f5d4b57f # Parent 8e65d6c0d95ad3a5d4d520bc79c863fbffd00a4d Added CSRF token cookie in every server response, with validation in every POST or AJAX request diff -r 8e65d6c0d95a -r e3f804db3e6f src/pyams_security/csrf.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/pyams_security/csrf.py Thu Sep 28 15:02:44 2017 +0200 @@ -0,0 +1,51 @@ +# +# Copyright (c) 2008-2015 Thierry Florac +# All Rights Reserved. +# +# This software is subject to the provisions of the Zope Public License, +# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. +# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +# FOR A PARTICULAR PURPOSE. +# + +__docformat__ = 'restructuredtext' + + +# import standard library + +# import interfaces +from pyramid.interfaces import INewRequest, INewResponse + +# import packages +from pyramid.events import subscriber +from pyramid.exceptions import BadCSRFToken +from pyramid.session import check_csrf_origin +from pyramid.util import strings_differ + + +CSRF_TOKEN_COOKIE_NAME = 'csrf_token' + + +@subscriber(INewRequest) +def handle_new_request(event): + """Handle any request with CSRF token cookie""" + request = event.request + if (request.method == 'POST') or request.is_xhr: + check_csrf_origin(request) + post_token = request.cookies.get(CSRF_TOKEN_COOKIE_NAME) + session_token = request.session.get_csrf_token() + if (not post_token) or strings_differ(post_token, session_token): + raise BadCSRFToken('Invalid CSRF token') + + +@subscriber(INewResponse) +def handle_new_response(event): + """Handle new response to manage CSRF token cookie""" + request = event.request + if not request.path.startswith('/--static--/'): + token = request.session.get_csrf_token() + event.response.set_cookie(CSRF_TOKEN_COOKIE_NAME, token, + secure=request.scheme == 'https', + httponly=True)