Search code examples
recaptchaflask-wtforms

Render Talisman CSP nonce on Google reCAPTCHA style tag on in Flask-wtf / wtforms form


I successfully setup CSP on my flask app using Talisman, but the only item I haven't managed to get working is adding a nonce to the Google reCAPTCHA <style> tag on my Contact form.

I've used the custom flask-wtf RECAPTCHA_HTML Config option, and my rendered html now looks like this:

<script {{ csp_nonce() }} src="https://www.google.com/recaptcha/api.js" async defer></script>
<div class="g-recaptcha" data-sitekey="aYSDvp4uev5dhAGsk6GbGRKEg7UFNmYc1JP9FSKf"></div>

How do I get Flask/Talisman/Flask-wtf to render the {{ csp_nonce() }} so that my rendered html looks more like this:

<script nonce="RYcJMNtXC7nBC4iYECnzildNF6qBMnoT" src="https://www.google.com/recaptcha/api.js" async defer></script>
<div class="g-recaptcha" data-sitekey="aYSDvp4uev5dhAGsk6GbGRKEg7UFNmYc1JP9FSKf"></div>

I've tried escaping the curly braces (ie. using \{\{) and adding |safe in the html template, but no luck there.

My actual template reads:

{{ form.recaptcha }}

Cheers.


Solution

  • Well, this one is pretty simple if you keep Flask's Contexts in mind. I simple inserted the CSP nonce from Talisman into the RECAPTCHA_HTML within the route that loads my Contact form. But, I did have to put RECAPTCHA_HTML = '' in my Config.

    #!/usr/bin/env python3
    '''webapp.links.routes'''
    
    from flask import Blueprint, render_template, current_app
    from webapp.routes.links.forms import ContactForm
    from webapp import Config, talisman
    
    links = Blueprint('links', __name__)
    
    @links.route("/contact", methods=['GET', 'POST'])
    def contact_route():
        '''
        Contact form
        '''
    
        ## Construct HTML for Google reCAPTCHA with Talisman nonce
        _RECAPTCHA_SRC = '"https://www.google.com/recaptcha/api.js"'
        _RECAPTCHA_CLASS = 'g-recaptcha'
        _RECAPTCHA_SNIPPET = 'data-sitekey="' + Config.RECAPTCHA_PUBLIC_KEY + '"'
    
        _RECAPTCHA_HTML =    '<script nonce="' + talisman._get_nonce() + \
                            '" src=' + _RECAPTCHA_SRC + ' async defer></script>' + \
                            '<div class="' + _RECAPTCHA_CLASS + '" ' + _RECAPTCHA_SNIPPET + '></div>'
        current_app.config.update(RECAPTCHA_HTML = _RECAPTCHA_HTML)
    
    
        form = ContactForm()
        if form.validate_on_submit():
    
        ### Normal form validation/handling below here ....
    

    This now renders the Google reCAPTCHA with the nonce in the tag in my HTML like this:

    <script nonce="RfK9KoHnAipsTmRLFS5KmnaaYIV1we6b" src="https://www.google.com/recaptcha/api.js" async defer></script>
    <div class="g-recaptcha" data-sitekey="aYSDvp4uev5dhAGsk6GbGRKEg7UFNmYc1JP9FSKf"></div>
    

    Hope this helps someone else in the future.