【问题标题】:CSRF with WTforms and webapp2带有 WTforms 和 webapp2 的 CSRF
【发布时间】:2017-09-20 12:34:47
【问题描述】:

WTForms 文档为implementing CSRF with Flask 提供了一个很好的示例:

class MyBaseForm(Form):
    class Meta:
        csrf = True
        csrf_class = SessionCSRF
        csrf_secret = app.config['CSRF_SECRET_KEY']

        @property
        def csrf_context(self):
            return session

我想做同样的事情,但使用 webapp2 会话而不是 Flask 会话。

csrf_context 是一个快捷方式,因此您不必在每次创建表单时都通过会话。有谁知道如何为 webapp2 会话创建这样的快捷方式?

如果没有这个快捷方式,每次创建表单时都需要这样做:

form = MyForm(meta={'csrf_context': self.session})

这是一些我宁愿避免的非常尴尬的语法。

【问题讨论】:

    标签: csrf webapp2 wtforms


    【解决方案1】:

    我想出了一个解决方案,可以减少我的问题中描述的笨拙语法。我修改了wt.Form 子类的__init__,如下所示:

    class MyBaseForm(wt.Form):
        class Meta:
            csrf = True
            csrf_class = SessionCSRF
            csrf_secret = settings.SESSION_KEY
            csrf_time_limit = timedelta(minutes=60)
    
        def __init__(self, *args, **kwargs):
            if "session" in kwargs:
                super(MyBaseForm, self).__init__(
                    *args, meta={'csrf_context': kwargs["session"]}, **kwargs)
            else:
                super(MyBaseForm, self).__init__(*args, **kwargs)
    

    现在,当我创建一个表单时,我可以这样做:

    form = MyForm(session=self.session)
    

    而不是问题中显示的尴尬语法。

    为了处理已发布的表单数据,我想出了另一种简化处理的技术。

    首先,我创建一个除了 CSRF 字段之外没有其他字段的表单:

    class NoFieldForm(MyBaseForm):
        pass
    

    其次,我创建了一个用于检查 CSRF 的装饰器:

    def check_csrf(func):
        def wrapper(*args, **kwargs):
            handler = args[0]
            session = handler.session
            request = handler.request
            f = forms.NoFieldForm(request.POST, session=session)
            f.validate()
            if f.csrf_token.errors:
                msg = "The CSRF token expired. Please try again. "
                self.session["msg"] = msg
                self.redirect(self.request.path)
            else:
                func(*args, **kwargs)
        return wrapper
    

    第三,我装饰了我所有的 POST 处理程序:

    class SomeHandler(webapp2.RequestHandler):
        @check_csrf
        def post(self):
            pass
    

    让我解释一下。装饰器(通过对 post webhandler 的调用)将接收一些表单数据,但出于 CSRF 检查的目的,我们将丢弃除 CSRF 之外的所有表单数据。我们可以通过使用忽略存在的任何其他表单数据的 NoFieldForm 使其通用。我使用 wtforms 来检查以确保 CSRF 表单字段和会话令牌匹配并且会话令牌没有过期。

    如果CSRF通过了,那么我们调用正常处理的handler来处理具体的表单。如果 CSRF 失败,那么我们根本不会调用处理程序,在我的示例中,我们会重定向回原来的位置并显示错误消息。

    【讨论】:

      猜你喜欢
      • 2013-03-16
      • 2020-09-26
      • 2012-05-20
      • 2017-02-19
      • 1970-01-01
      • 2012-10-14
      • 1970-01-01
      • 2016-02-05
      • 2023-03-13
      相关资源
      最近更新 更多