15

从下面的代码中可以看出,我有一个GETfor 注册,它将其工作委托给POST.

class RegistrationHandler(tornado.web.RequestHandler):
    def get(self):
        s = """
          <h1>Register</h1>
              <form method="post" action="/register">
                  <div>
                      <label>User</label>
                      <input name="user_name" value="test@test.com"/>
                  </div>
                  <div>
                      <label>password</label>
                      <input name="password" type="password"/>
                  </div>
                  <div>
                      <input type="submit" value="submit"/>
                  </div>
              </form>
        """
        self.write(s)

    @log_exception()
    def post(self):
        user_name = self.request.arguments['user_name']
        password = self.request.arguments['password']
        log.debug('Registering user with credentials %r' % (user_name, password))
        with sa_session() as db_session:
            User.register(user_name, password, db_session)

当我从我的网络浏览器访问 URL 时,我得到一个注册表单,提交后我得到“403:禁止”。

控制台日志:

2012-10-15 11:27:42,482 - __main__ - DEBUG - Starting server on port 8080
2012-10-15 11:27:49,377 - root - INFO - 304 GET /register (127.0.0.1) 0.78ms
2012-10-15 11:27:53,143 - root - WARNING - 403 POST /register (127.0.0.1): '_xsrf' argument missing from POST
2012-10-15 11:27:53,144 - root - WARNING - 403 POST /register (127.0.0.1) 1.05ms

这个错误是什么意思,我该如何纠正?谢谢。

4

3 回答 3

21

我想你在你的设置中启用了跨站点请求伪造 cookie(默认情况下它是打开的)。

Tornado 的 XSRF 在这里

要解决此问题,请在您的设置中将其关闭:

settings = {
    "xsrf_cookies": False,
}

注意:通常你不想关闭它,通常你会在这样的模板中生成 HTML:请注意添加 XSRF cookie 的 xsrf 位。

 <form method="post" action="/register">
     <input name="user_name" value="test@test.com"/>
     <input name="password" type="password"/>
     <input type="submit" value="submit"/>
{% raw xsrf_form_html() %}
 </form>

---编辑以下评论---而不是:

  def get(self):
        loader = template.Loader("resources")
        page_contents = loader.load('register_page.html').generate()
        self.write(page_contents)

做:

  def get(self):
     self.render("../resources/register_page.html")

或更好:

  def get(self):
     self.render("register_page.html")

(并将其放在您的模板目录中)

于 2012-10-16T14:31:35.353 回答
1

这里同样的问题。在深入研究代码后,我检查了用于检查的 tornado 内置函数:

def check_xsrf_cookie(self):
    """Verifies that the ``_xsrf`` cookie matches the ``_xsrf`` argument.

    To prevent cross-site request forgery, we set an ``_xsrf``
    cookie and include the same value as a non-cookie
    field with all ``POST`` requests. If the two do not match, we
    reject the form submission as a potential forgery.

    The ``_xsrf`` value may be set as either a form field named ``_xsrf``
    or in a custom HTTP header named ``X-XSRFToken`` or ``X-CSRFToken``
    (the latter is accepted for compatibility with Django).

    See http://en.wikipedia.org/wiki/Cross-site_request_forgery

    Prior to release 1.1.1, this check was ignored if the HTTP header
    ``X-Requested-With: XMLHTTPRequest`` was present.  This exception
    has been shown to be insecure and has been removed.  For more
    information please see
    http://www.djangoproject.com/weblog/2011/feb/08/security/
    http://weblog.rubyonrails.org/2011/2/8/csrf-protection-bypass-in-ruby-on-rails

    .. versionchanged:: 3.2.2
       Added support for cookie version 2.  Both versions 1 and 2 are
       supported.
    """
    token = (self.get_argument("_xsrf", None) or
             self.request.headers.get("X-Xsrftoken") or
             self.request.headers.get("X-Csrftoken"))
    if not token:
        raise HTTPError(403, "'_xsrf' argument missing from POST")
    _, token, _ = self._decode_xsrf_token(token)
    _, expected_token, _ = self._get_raw_xsrf_token()
    if not token:
        raise HTTPError(403, "'_xsrf' argument has invalid format")
    if not _time_independent_equals(utf8(token), utf8(expected_token)):
        raise HTTPError(403, "XSRF cookie does not match POST argument")

正如您可以阅读方法定义:

_xsrf值可以设置为名为的表单字段或在名为或_xsrf 的自定义 HTTP 标头中X-XSRFTokenX-CSRFToken

因此我尝试设置一个名为X-CSRFToken. 下面是ajax定义:

$.ajax({
    url: this.my_url,
    type: 'POST',
    data: JSON.stringify(body),
    beforeSend: function(xhr) {
            xhr.setRequestHeader('X-CSRFToken', getCookie('_xsrf'));},
});

最后,我们需要定义getCookie负责检索正确 CSRF 令牌的函数。该函数的定义直接取自 Tornado CSRF 文档

function getCookie(name) {
    var r = document.cookie.match("\\b" + name + "=([^;]*)\\b");
    return r ? r[1] : undefined;
}
于 2021-10-13T09:11:17.023 回答
0

有一个冲突:你是怎么做get的和你放的形式method="post"?这就是为什么error 403

如果您使用get,那么您将不需要xsrf保护。否则,您将其添加到表单声明之后

<form method="post" action="/register">
{% raw xsrf_form_html() %} # the 'raw' word is to force escape to be desactivated (it is by default activated)

所以 xsrf 你会在你渲染的 html 中发现它是一个隐藏的标签。

于 2012-10-20T14:48:42.447 回答