在Flask-WTF表单中为Google reCAPTCHA渲染Talisman CSP随机数
解决Flask-WTF reCAPTCHA无法解析CSP Nonce的问题
问题根源
Flask-WTF的RECAPTCHA_HTML配置是纯字符串,当通过{{ form.recaptcha }}渲染验证码时,框架只会原样输出这个字符串,不会解析其中的Jinja2模板变量(比如{{ csp_nonce() }})。
解决方案
方法1:自定义RecaptchaWidget解析Nonce
通过重写Flask-WTF的RecaptchaWidget,让它在渲染时解析nonce变量:
- 自定义Widget类,利用Flask的模板渲染能力解析
RECAPTCHA_HTML中的变量:
from flask import current_app, render_template_string from flask_wtf.recaptcha import RecaptchaWidget, RecaptchaField class NonceAwareRecaptchaWidget(RecaptchaWidget): def render(self, field, **kwargs): # 获取Talisman生成的Nonce(调用全局模板函数csp_nonce()) nonce = current_app.jinja_env.globals['csp_nonce']() # 用render_template_string解析RECAPTCHA_HTML中的模板变量 return render_template_string( current_app.config['RECAPTCHA_HTML'], csp_nonce=lambda: nonce, site_key=current_app.config['RECAPTCHA_PUBLIC_KEY'] )
- 在表单中使用自定义Widget:
from flask_wtf import FlaskForm class ContactForm(FlaskForm): # 其他表单字段... recaptcha = RecaptchaField(widget=NonceAwareRecaptchaWidget())
方法2:手动在模板中渲染reCAPTCHA(更简单)
跳过Flask-WTF的form.recaptcha渲染,直接在模板中手写HTML标签,这样可以直接使用{{ csp_nonce() }}:
<!-- 模板中的reCAPTCHA代码 --> <div class="g-recaptcha" data-sitekey="{{ config.RECAPTCHA_PUBLIC_KEY }}" nonce="{{ csp_nonce() }}"></div> <script src="https://www.google.com/recaptcha/api.js" nonce="{{ csp_nonce() }}"></script>
关键注意事项
- 确保Talisman的CSP配置包含reCAPTCHA相关域名及nonce规则:
TALISMAN_CSP = { 'script-src': [ "'nonce-{nonce}'", "https://www.google.com/recaptcha/", "https://www.gstatic.com/recaptcha/" ], # 其他CSP规则... } - 若使用方法1,
RECAPTCHA_HTML中可以正常使用Jinja2变量(比如{{ csp_nonce() }}),因为现在会被render_template_string解析。
内容的提问来源于stack exchange,提问作者SimonB
相关产品推荐
相关产品推荐

