diff options
| -rw-r--r-- | openerp/http.py | 86 |
1 files changed, 76 insertions, 10 deletions
diff --git a/openerp/http.py b/openerp/http.py index af151a0e325..2d68fd216ff 100644 --- a/openerp/http.py +++ b/openerp/http.py @@ -420,8 +420,7 @@ class WebRequest(object): return consteq(hm, hm_expected) def route(route=None, **kw): - """ - Decorator marking the decorated method as being a handler for + """Decorator marking the decorated method as being a handler for requests. The method must be part of a subclass of ``Controller``. :param route: string or array. The route part that will determine which @@ -446,16 +445,55 @@ def route(route=None, **kw): :param cors: The Access-Control-Allow-Origin cors directive value. :param bool csrf: Whether CSRF protection should be enabled for the route. - Defaults to ``True``. + Defaults to ``True``. See :ref:`CSRF Protection + <csrf>` for more. + + .. _csrf: + + .. admonition:: CSRF Protection + :class: alert-warning + + .. versionadded:: 9.0 + + Odoo implements token-based `CSRF protection + <https://en.wikipedia.org/wiki/CSRF>`_. + + CSRF protection is enabled by default and applies to *UNSAFE* + HTTP methods as defined by :rfc:`7231` (all methods other than + ``GET``, ``HEAD``, ``TRACE`` and ``OPTIONS``). + + CSRF protection is implemented by checking requests using + unsafe methods for a value called ``csrf_token`` as part of + the request's form data. That value is removed from the form + as part of the validation and does not have to be taken in + account by your own form processing. + + When adding a new controller for an unsafe method (mostly POST + for e.g. forms): + + * if the form is generated in Python, a csrf token is + available via :meth:`request.csrf_token() + <openerp.http.WebRequest.csrf_token`, the + :data:`~openerp.http.request` object is available by default + in QWeb (python) templates, it may have to be added + explicitly if you are not using QWeb. + + * if the form is generated in Javascript, the CSRF token is + added by default to the QWeb (js) rendering context as + ``csrf_token`` and is otherwise available as ``csrf_token`` + on the ``web.core`` module: - CSRF protection only applies to *UNSAFE* methods as - defined by :rfc:`7231`: GET, HEAD, TRACE and OPTIONS are - safe, all other methods are unsafe. + .. code-block:: javascript + + require('web.core').csrf_token + + * if the endpoint can be called by external parties (not from + Odoo) as e.g. it is a REST API or a `webhook + <https://en.wikipedia.org/wiki/Webhook>`_, CSRF protection + must be disabled on the endpoint. If possible, you may want + to implement other methods of request validation (to ensure + it is not called by an unrelated third-party). - CSRF protection requires a csrf token to be sent as part - of the request's form data, it can be obtained via - :meth:`request.csrf_token() - <openerp.http.WebRequest.csrf_token>` """ routing = kw.copy() assert 'type' not in routing or routing['type'] in ("http", "json") @@ -769,6 +807,34 @@ class HttpRequest(WebRequest): and request.endpoint.routing.get('csrf', True): # csrf checked by default token = self.params.pop('csrf_token', None) if not self.validate_csrf(token): + if token is not None: + _logger.warn("CSRF validation failed on path '%s'", + request.httprequest.path) + else: + _logger.warn("""No CSRF validation token provided for path '%s' + +Odoo URLs are CSRF-protected by default (when accessed with unsafe +HTTP methods). See +https://www.odoo.com/documentation/9.0/reference/http.html#csrf for +more details. + +* if this endpoint is accessed through Odoo via py-QWeb form, embed a CSRF + token in the form, Tokens are available via `request.csrf_token()` + can be provided through a hidden input and must be POST-ed named + `csrf_token` e.g. in your form add: + + <input type="hidden" name="csrf_token" t-att-value="request.csrf_token()"/> + +* if the form is generated or posted in javascript, the token value is + available as `csrf_token` on `web.core` and as the `csrf_token` + value in the default js-qweb execution context + +* if the form is accessed by an external third party (e.g. REST API + endpoint, payment gateway callback) you will need to disable CSRF + protection (and implement your own protection if necessary) by + passing the `csrf=False` parameter to the `route` decorator. + """, request.httprequest.path) + raise werkzeug.exceptions.BadRequest('Invalid CSRF Token') r = self._call_function(**self.params) |
