diff --git a/docs/api.rst b/docs/api.rst index 1a65bc74..ae76acce 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -1,8 +1,6 @@ Developer Interface =================== -This part of the documentation covers all interfaces of Flask-WTF. - Forms and Fields ---------------- @@ -36,6 +34,9 @@ CSRF Protection .. autoclass:: CsrfProtect :members: +.. autoclass:: CsrfError + :members: + .. autofunction:: generate_csrf .. autofunction:: validate_csrf diff --git a/docs/changelog.rst b/docs/changelog.rst index 14a04b0a..c8ba7625 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -1,6 +1,36 @@ Flask-WTF Changelog =================== +Version 0.14 +------------ + +In development + +- Use itsdangerous to sign CSRF tokens and check expiration instead of doing it + ourselves. (`#264`_) + + - All tokens are URL safe, removing the ``url_safe`` parameter from + ``generate_csrf``. (`#206`_) + - All tokens store a timestamp, which is checked in ``validate_csrf``. The + ``time_limit`` parameter of ``generate_csrf`` is removed. + +- Remove the ``app`` attribute from ``CsrfProtect``, use ``current_app``. + (`#264`_) +- ``CsrfProtect`` protects the ``DELETE`` method by default. (`#264`_) +- The same CSRF token is generated for the lifetime of a request. It is exposed + as ``request.csrf_token`` for use during testing. (`#227`_, `#264`_) +- ``CsrfProtect.error_handler`` is deprecated. (`#264`_) + - Handlers that return a response work in addition to those that raise an + error. The behavior was not clear in previous docs. + - (`#200`_, `#209`_, `#243`_, `#252`_) + +.. _`#200`: https://github.com/lepture/flask-wtf/issues/200 +.. _`#209`: https://github.com/lepture/flask-wtf/pull/209 +.. _`#227`: https://github.com/lepture/flask-wtf/issues/227 +.. _`#243`: https://github.com/lepture/flask-wtf/pull/243 +.. _`#252`: https://github.com/lepture/flask-wtf/pull/252 +.. _`#264`: https://github.com/lepture/flask-wtf/pull/264 + Version 0.13.1 -------------- diff --git a/docs/csrf.rst b/docs/csrf.rst index 101cb144..3c6ed48b 100644 --- a/docs/csrf.rst +++ b/docs/csrf.rst @@ -1,34 +1,26 @@ -CSRF Protection -=============== - -This part of the documentation covers the CSRF protection. - -Why CSRF --------- +.. module:: flask_wtf.csrf -Flask-WTF form is already protecting you from CSRF, you don't have to -worry about that. However, you have views that contain no forms, and they -still need protection. +.. _csrf: -For example, the POST request is sent by AJAX, but it has no form behind -it. You can't get the csrf token prior 0.9.0 of Flask-WTF. That's why we -created this CSRF for you. +CSRF Protection +=============== -Implementation --------------- +Any view using :class:`flask_wtf.FlaskForm` to process the request is already +getting CSRF protection. If you have views that don't use ``FlaskForm`` or make +AJAX requests, use the provided CSRF extension to protect those requests as +well. -.. module:: flask_wtf.csrf +Setup +----- -To enable CSRF protection for all your view handlers, you need to enable -the :class:`CsrfProtect` module:: +To enable CSRF protection globally for a Flask app, register the +:class:`CsrfProtect` extension. :: from flask_wtf.csrf import CsrfProtect - CsrfProtect(app) + csrf = CsrfProtect(app) -Like any other Flask extensions, you can load it lazily:: - - from flask_wtf.csrf import CsrfProtect +Like other Flask extensions, you can apply it lazily:: csrf = CsrfProtect() @@ -38,94 +30,86 @@ Like any other Flask extensions, you can load it lazily:: .. note:: - You need to setup a secret key for CSRF protection. Usually, this - is the same as your Flask app SECRET_KEY. + CSRF protection requires a secret key to securely sign the token. By default + this will use the Flask app's ``SECRET_KEY``. If you'd like to use a + separate token you can set ``WTF_CSRF_SECRET_KEY``. + +HTML Forms +---------- -If the template has a form, you don't need to do any thing. It is the -same as before: +When using a ``FlaskForm``, render the form's CSRF field like normal. .. sourcecode:: html+jinja -
+ {{ form.csrf_token }}
-But if the template has no forms, you still need a csrf token: +If the template doesn't use a ``FlaskForm``, render a hidden input with the +token in the form. .. sourcecode:: html+jinja -
- + +
-Whenever a CSRF validation fails, it will return a 400 response. You can -customize the error response:: +JavaScript Requests +------------------- + +When sending an AJAX request, add the ``X-CSRFToken`` header to it. +For example, in jQuery you can configure all requests to send the token. + +.. sourcecode:: html+jinja + + + +Customize the error response +---------------------------- + +When CSRF validation fails, it will raise a :class:`CsrfError`. +By default this returns a response with the failure reason and a 400 code. +You can customize the error response using Flask's +:meth:`~flask.Flask.errorhandler`. :: + + from flask_wtf.csrf import CsrfError - @csrf.error_handler - def csrf_error(reason): - return render_template('csrf_error.html', reason=reason), 400 + @app.errorhandler(CsrfError) + def handle_csrf_error(e): + return render_template('csrf_error.html', reason=e.description), 400 + +Exclude views from protection +----------------------------- We strongly suggest that you protect all your views with CSRF. But if -needed, you can exclude some views using a decorator:: +needed, you can exclude some views using a decorator. :: - @csrf.exempt @app.route('/foo', methods=('GET', 'POST')) + @csrf.exempt def my_handler(): # ... return 'ok' -If needed, you can also exclude all the views from within a given Blueprint: +You can exclude all the views of a blueprint. :: csrf.exempt(account_blueprint) -You can also disable CSRF protection in all views by default, by setting +You can disable CSRF protection in all views by default, by setting ``WTF_CSRF_CHECK_DEFAULT`` to ``False``, and selectively call ``csrf.protect()`` only when you need. This also enables you to do some -pre-processing on the requests before checking for the CSRF token:: +pre-processing on the requests before checking for the CSRF token. :: @app.before_request def check_csrf(): if not is_oauth(request): csrf.protect() - -AJAX ----- - -Sending POST requests via AJAX is possible where there are no forms at all. -This feature is available since 0.9.0. - -Assuming you have done ``CsrfProtect(app)``, you can get the csrf token via -``{{ csrf_token() }}``. This method is available in every template, that -way you don't have to worry if there are no forms for rendering the csrf token -field. - -The suggested way is that you render the token in a ```` tag: - -.. sourcecode:: html+jinja - - - -And it is also possible to render it in the `` - -We will take the ```` way for example, the ``