Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow users to optionally supply a CSP nonce to generated inline script #84

Closed
wants to merge 2 commits into from
Closed

Allow users to optionally supply a CSP nonce to generated inline script #84

wants to merge 2 commits into from

Conversation

arunanshub
Copy link

If the user has set up a CSP like:

Content-Security-Policy:
  script-src 'nonce-{random}'
  script-src-elem 'nonce-{random}'

The random is substituted with the provided nonce.

It is recommended that the user use an extension like Flask-Talisman and set it up as:

talisman = Talisman()

CSP = {
    # your preferred CSP goes here
}

talisman.init_app(
    app,
    csp=CSP,
    content_security_policy_nonce_in=["script-src-elem"],
    # ...
)

and then load Flask-Moment like:

{% block scripts %}
{# ... #}
{{ moment.include_moment(csp_nonce=csp_nonce()) }}
{# ... #}
{% endblock %}

Valuable resources:

By extension, it is enforced that the `csp_nonce` param is a `str` instance.
@miguelgrinberg
Copy link
Owner

Wouldn't it be easier to pass no_js=True and then include your own <script> tag using all the security choices that you like? I feel that this is complicating this project unnecessarily, since it is already possible to provide your own <script> tag.

@arunanshub
Copy link
Author

arunanshub commented Jan 15, 2022

Since the extension already generates an inline helper script, I believe that providing an option for a CSP nonce would not complicate things. In fact, it saves time that would otherwise be spent in setting up a custom solution of "No-JS-and-Custom-Options".

To add more to the list of benefits, one can also provide the CSP nonce in the script tags required for embedding Momentjs library. However, I would personally draw my line of limit there. Personally, I would add the sources in the script-src or script-src-elem of my CSP, which is against the recommendations of the sources I provided above.

@miguelgrinberg
Copy link
Owner

What I say it complicates things, I mean it makes this package more complex and harder to maintain. I would also posit that in matters of security, I would not trust that some random extension such as this one knows how to set up the <script> tag properly for CSP.

The fact of the matter is that CSP is going to be implemented by a tiny fraction of the people who use this package. Those people will have to go through the effort of setting up their CSP settings anyway, so they might as well invoke the script in their own preferred way, which is something that they'll have to do anyway for their other scripts.

I think having SRI in this package makes sense, because this is a standalone thing that people benefit from even without understanding what SRI is. CSP is not like that, you have to know and willingly set it up, so it isn't a good fit for this package. Sorry.

@arunanshub
Copy link
Author

arunanshub commented Jan 15, 2022

I mean it makes this package more complex and harder to maintain.

May I ask how will it complicate things, even though it is nothing but a simple textual field, which ultimately may or may not be used by the users, just like the other fields?

I think having SRI in this package makes sense, because this is a standalone thing that people benefit from even without understanding what SRI is. CSP is not like that, you have to know and willingly set it up, so it isn't a good fit for this package.

How is this any different from having an option for setting up CSP? In fact, users come to know about CSP in the context of SRI.

@miguelgrinberg
Copy link
Owner

miguelgrinberg commented Jan 15, 2022

How is this any different from having an option for setting up CSP? In fact, users come to know about CSP in the context of SRI.

I explained it above. SRI works on its own and is enabled by default for everybody, the developer doesn't even need to know it is used. Adding a CSP nonce serves no purpose unless you have gone through the effort of setting up CSP somewhere else in your application. If you did that, then you have a bunch of <script> tags to fix with CSP, so you might as well do what you are doing for your other scripts with moment.

@arunanshub
Copy link
Author

Given that this extension generates the inline script and there is no way to turn it off, what else do you suggest that will prevent any CSP errors?

@miguelgrinberg
Copy link
Owner

Pass no_js=True when you create the Moment object and make sure moment.js is included above the place where you call include_moment() in your template.

@arunanshub
Copy link
Author

But that still generates the <script> moment.locale("en"); .... And thus eventually JS complains about Uncaught ReferenceError: moment is not defined.

That is what I'm trying to validate via CSP, but the extension provides no option for turning that off (not recommended) or loading it from local file.

@miguelgrinberg
Copy link
Owner

Okay, sorry, now I think I understand the problem. I'll give the PR another look tomorrow.

@miguelgrinberg
Copy link
Owner

A possible fix is in the main branch. You can use {{ moment.flask_moment_js() }} to retrieve the raw JS code used by this extension, without the moment.js library, and without a <script> tag. This should allow you (I think) to write the <script> tag according to your requirements.

@arunanshub
Copy link
Author

Ah! I was going to implement your current solution and update the pull request! Thanks! 👍

@miguelgrinberg
Copy link
Owner

An added benefit of this solution is that you can now also serve the Flask-Moment JS code as its own resource. I put this example in the docs:

@app.route('/flask-moment.js')
def flask_moment_js():
    return moment.flask_moment_js(), 200, {'Content-Type': 'application/javascript'}

So then in your template you can do:

<script src="/flask-moment.js"></script>

So once again you can add any needed attributes to the script tag, and also benefit from caching at the browser, which wasn't possible before!

@arunanshub
Copy link
Author

Simply excellent and beautifully decoupled! And thanks for all your valuable Flask resources!

@arunanshub arunanshub deleted the csp-nonce-patch branch January 16, 2022 18:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants