def check_csrf_token(request, token='csrf_token', header='X-CSRF-Token', raises=True): """ Check the CSRF token in the request's session against the value in ``request.params.get(token)`` or ``request.headers.get(header)``. If a ``token`` keyword is not supplied to this function, the string ``csrf_token`` will be used to look up the token in ``request.params``. If a ``header`` keyword is not supplied to this function, the string ``X-CSRF-Token`` will be used to look up the token in ``request.headers``. If the value supplied by param or by header doesn't match the value supplied by ``request.session.get_csrf_token()``, and ``raises`` is ``True``, this function will raise an :exc:`pyramid.exceptions.BadCSRFToken` exception. If the check does succeed and ``raises`` is ``False``, this function will return ``False``. If the CSRF check is successful, this function will return ``True`` unconditionally. Note that using this function requires that a :term:`session factory` is configured. .. versionadded:: 1.4a2 """ supplied_token = request.params.get(token, request.headers.get(header)) if supplied_token != request.session.get_csrf_token(): if raises: raise BadCSRFToken('check_csrf_token(): Invalid token') return False return True
def check_csrf_token(request, token='csrf_token', header='X-CSRF-Token', raises=True): """ Check the CSRF token returned by the :class:`pyramid.interfaces.ICSRFStoragePolicy` implementation against the value in ``request.POST.get(token)`` (if a POST request) or ``request.headers.get(header)``. If a ``token`` keyword is not supplied to this function, the string ``csrf_token`` will be used to look up the token in ``request.POST``. If a ``header`` keyword is not supplied to this function, the string ``X-CSRF-Token`` will be used to look up the token in ``request.headers``. If the value supplied by post or by header cannot be verified by the :class:`pyramid.interfaces.ICSRFStoragePolicy`, and ``raises`` is ``True``, this function will raise an :exc:`pyramid.exceptions.BadCSRFToken` exception. If the values differ and ``raises`` is ``False``, this function will return ``False``. If the CSRF check is successful, this function will return ``True`` unconditionally. See :ref:`auto_csrf_checking` for information about how to secure your application automatically against CSRF attacks. .. versionadded:: 1.4a2 .. versionchanged:: 1.7a1 A CSRF token passed in the query string of the request is no longer considered valid. It must be passed in either the request body or a header. .. versionchanged:: 1.9 Moved from :mod:`pyramid.session` to :mod:`pyramid.csrf` and updated to use the configured :class:`pyramid.interfaces.ICSRFStoragePolicy` to verify the CSRF token. """ supplied_token = "" # We first check the headers for a csrf token, as that is significantly # cheaper than checking the POST body if header is not None: supplied_token = request.headers.get(header, "") # If this is a POST/PUT/etc request, then we'll check the body to see if it # has a token. We explicitly use request.POST here because CSRF tokens # should never appear in an URL as doing so is a security issue. We also # explicitly check for request.POST here as we do not support sending form # encoded data over anything but a request.POST. if supplied_token == "" and token is not None: supplied_token = request.POST.get(token, "") policy = request.registry.getUtility(ICSRFStoragePolicy) if not policy.check_csrf_token(request, text_(supplied_token)): if raises: raise BadCSRFToken('check_csrf_token(): Invalid token') return False return True
def csrf_valid(self): if check_csrf_token(self.request, raises=False) == False: log.debug('CSRF token did not match.') log.debug('Expected token: {}'.format( self.request.session.get_csrf_token())) log.debug('Got token: {}'.format( self.request.headers['x-csrf-token'] if 'x-csrf-token' in self.request.headers else None)) raise BadCSRFToken()
def check_csrf_token(request, token='csrf_token', header='X-CSRF-Token', raises=True): """ Check the CSRF token in the request's session against the value in ``request.POST.get(token)`` (if a POST request) or ``request.headers.get(header)``. If a ``token`` keyword is not supplied to this function, the string ``csrf_token`` will be used to look up the token in ``request.POST``. If a ``header`` keyword is not supplied to this function, the string ``X-CSRF-Token`` will be used to look up the token in ``request.headers``. If the value supplied by post or by header doesn't match the value supplied by ``request.session.get_csrf_token()``, and ``raises`` is ``True``, this function will raise an :exc:`pyramid.exceptions.BadCSRFToken` exception. If the values differ and ``raises`` is ``False``, this function will return ``False``. If the CSRF check is successful, this function will return ``True`` unconditionally. Note that using this function requires that a :term:`session factory` is configured. See :ref:`auto_csrf_checking` for information about how to secure your application automatically against CSRF attacks. .. versionadded:: 1.4a2 .. versionchanged:: 1.7a1 A CSRF token passed in the query string of the request is no longer considered valid. It must be passed in either the request body or a header. """ supplied_token = "" # If this is a POST/PUT/etc request, then we'll check the body to see if it # has a token. We explicitly use request.POST here because CSRF tokens # should never appear in an URL as doing so is a security issue. We also # explicitly check for request.POST here as we do not support sending form # encoded data over anything but a request.POST. if token is not None: supplied_token = request.POST.get(token, "") # If we were unable to locate a CSRF token in a request body, then we'll # check to see if there are any headers that have a value for us. if supplied_token == "" and header is not None: supplied_token = request.headers.get(header, "") expected_token = request.session.get_csrf_token() if strings_differ(bytes_(expected_token), bytes_(supplied_token)): if raises: raise BadCSRFToken('check_csrf_token(): Invalid token') return False return True
def login_view(request: Request): """Login form. After successful login redirects to the URL in the query or post parameter ``next``. By default redirects to the index page. """ def set_csrf_token(value, max_age=None): def set_cookie(request, response): response.set_cookie('csrf_token', value=value, path=request.path, secure=request.scheme == 'https', httponly=True, samesite='Strict', max_age=max_age) return set_cookie next_url = request.params.get('next') or request.route_url('index') if request.user: return HTTPFound(location=next_url) username = '' failed = False if 'submit' in request.POST: username = request.POST.get('username', '') password = request.POST.get('password', '') csrf_token = request.POST.get('csrf_token', '') expected_csrf_token = request.cookies.get('csrf_token', '') if not hmac.compare_digest(csrf_token, expected_csrf_token): raise BadCSRFToken() user = db.user.authenticate(request.db, username, password) if user: # Important - at the very least generate a new session id at # login/logout to prevent session fixation attacks. request.session.invalidate() request.user = user headers = remember(request, user.user_id) request.add_response_callback(set_csrf_token('', 0)) return HTTPFound(location=next_url, headers=headers) failed = True csrf_token = os.urandom(16).hex() url = request.route_url('login') request.add_response_callback(set_csrf_token(csrf_token)) return dict(username=username, next=next_url, failed=failed, login_url=url, csrf_token=csrf_token)
def like_post_json(context: PostResource, request): """ JSON `like` action. This action is CSRF-safe thanks to: - Accepting only POST requests - Browsers cannot submit JSON from forms (only ``application/x-www-form-urlencoded``) - CORS/SOP prevent scripts on `external pages` from posting unless a CORS policy allows it. - Requires a CSRF-token In addition the user must have permission to perform the action. Abbreviations: - CORS = Cross-Origin Resource Sharing - SOP = Same Origin Policy """ request_body: dict = request.json_body # In case there is a CORS policy in place we also require the CSRF token # to be included in the JSON request. # # We can get the same effect by setting require_csrf=True which will # require the request to include an X-CSRF-Token header. # # Calling pyramid.csrf.check_csrf_token would also achieve the same thing # by checking the X-CSRF-Token header. csrf_token = request_body.get('csrf_token', '') expected_csrf_token = get_csrf_token(request) if not hmac.compare_digest(csrf_token, expected_csrf_token): raise BadCSRFToken() post = db.post.like_post(request.db, context.post.post_id) return post
def validate_csrf_token(self, field): if field.data != field.current_token: raise BadCSRFToken()
def test_response_equivalence(self): from pyramid.exceptions import BadCSRFToken from pyramid.httpexceptions import HTTPBadRequest self.assertTrue(isinstance(BadCSRFToken(), HTTPBadRequest))