Skip to content

Commit

Permalink
log CSRF errors,close #239
Browse files Browse the repository at this point in the history
  • Loading branch information
davidism committed Jan 4, 2017
1 parent 1a124b4 commit b16ba41
Show file tree
Hide file tree
Showing 5 changed files with 61 additions and 9 deletions.
4 changes: 3 additions & 1 deletion docs/changelog.rst
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,12 @@ In development
- Provide ``WTF_CSRF_FIELD_NAME`` to configure the name of the CSRF token.
(`#271`_)
- ``CsrfError`` is renamed to ``CSRFError``. (`#271`_)
- ``validate_csrf`` raises ``wtforms.ValidationError`` with specifc messages
- ``validate_csrf`` raises ``wtforms.ValidationError`` with specific messages
instead of returning ``True`` or ``False``. This breaks anything that was
calling the method directly. (`#239`_, `#271`_)

- CSRF errors are logged as well as raised. (`#239`_)

.. _`#200`: https://github.com/lepture/flask-wtf/issues/200
.. _`#209`: https://github.com/lepture/flask-wtf/pull/209
.. _`#216`: https://github.com/lepture/flask-wtf/issues/216
Expand Down
7 changes: 7 additions & 0 deletions docs/config.rst
Original file line number Diff line number Diff line change
Expand Up @@ -35,3 +35,10 @@ Recaptcha
https://www.google.com/recaptcha/admin/create
``RECAPTCHA_OPTIONS`` **optional** A dict of configuration options.
========================= ==============================================

Logging
-------

CSRF errors are logged at the ``INFO`` level to the ``flask_wtf.csrf`` logger.
You still need to configure logging in your application in order to see these
messages.
19 changes: 13 additions & 6 deletions flask_wtf/csrf.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import warnings
from functools import wraps

import logging
from flask import Blueprint, current_app, request, session
from itsdangerous import BadData, SignatureExpired, URLSafeTimedSerializer
from werkzeug.exceptions import BadRequest
Expand All @@ -13,6 +14,7 @@
from ._compat import FlaskWTFDeprecationWarning, string_types, urlparse

__all__ = ('generate_csrf', 'validate_csrf', 'CsrfProtect')
logger = logging.getLogger(__name__)


def generate_csrf(secret_key=None, token_key=None):
Expand Down Expand Up @@ -133,12 +135,16 @@ def generate_csrf_token(self, csrf_token_field):
)

def validate_csrf_token(self, form, field):
validate_csrf(
field.data,
self.meta.csrf_secret,
self.meta.csrf_time_limit,
self.meta.csrf_field_name
)
try:
validate_csrf(
field.data,
self.meta.csrf_secret,
self.meta.csrf_time_limit,
self.meta.csrf_field_name
)
except ValidationError as e:
logger.info(e.args[0])
raise


class CsrfProtect(object):
Expand Down Expand Up @@ -238,6 +244,7 @@ def protect(self):
try:
validate_csrf(self._get_csrf_token())
except ValidationError as e:
logger.info(e.args[0])
self._error_response(e.args[0])

if request.is_secure and current_app.config['WTF_CSRF_SSL_STRICT']:
Expand Down
31 changes: 31 additions & 0 deletions tests/base.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
from __future__ import with_statement

from contextlib import contextmanager
from unittest import TestCase as _TestCase

import logging
from flask import Flask, jsonify, render_template
from wtforms import HiddenField, StringField, SubmitField
from wtforms.validators import DataRequired
Expand Down Expand Up @@ -40,6 +42,35 @@ class SimpleForm(FlaskForm):
pass


class CaptureHandler(logging.Handler):
def __init__(self):
self.records = []
logging.Handler.__init__(self, logging.DEBUG)

def emit(self, record):
self.records.append(record)

def __iter__(self):
return iter(self.records)

def __len__(self):
return len(self.records)

def __getitem__(self, item):
return self.records[item]


@contextmanager
def capture_logging(logger):
handler = CaptureHandler()

try:
logger.addHandler(handler)
yield handler
finally:
logger.removeHandler(handler)


class TestCase(_TestCase):
def setUp(self):
self.app = self.create_app()
Expand Down
9 changes: 7 additions & 2 deletions tests/test_validation.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
from flask import json, request

from flask_wtf.csrf import generate_csrf
from .base import MyForm, TestCase, to_unicode
from .base import MyForm, TestCase, to_unicode, capture_logging


class TestValidateOnSubmit(TestCase):
Expand Down Expand Up @@ -60,10 +60,15 @@ def test_csrf_token(self):
assert snippet in to_unicode(response.data)

def test_invalid_csrf(self):
from flask_wtf.csrf import logger

with capture_logging(logger) as handler:
response = self.client.post("/", data={"name": "danny"})

response = self.client.post("/", data={"name": "danny"})
assert b'DANNY' not in response.data
assert b'The CSRF token is missing.' in response.data
self.assertEqual(1, len(handler))
self.assertEqual('The CSRF token is missing.', handler[0].message)

def test_csrf_disabled(self):

Expand Down

0 comments on commit b16ba41

Please sign in to comment.