-
Notifications
You must be signed in to change notification settings - Fork 102
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
Footgun when accessing nonce value in a middleware #247
Comments
The CSP middleware hangs the nonce off of response = inject_script_into_response(response, nonce=response.csp_nonce) The nonce is wrapped up in a |
Apologies! Yes, that's a typo. I'll amend the original example. I have no opinion on whether the lazy object approach is good or bad, just that this quite specific case where a user misuses the system gives a surprising result, and I think a clear error message would be better. |
Can you try: response = inject_script_into_response(response, nonce=str(request.csp_nonce)) to see if the str coercion works? If your middleware is before the CSP middleware, it should trigger the nonce to be added to the headers, similar to accessing the nonce via templates during the req/resp cycle. |
So here's a project which reproduces the issue: https://github.com/alynn-coefficient/django-csp-247 Observe that:
|
The app was illuminating on the details of the initial report, thank you for putting that together. I'll summarize what you've already shared from the start... Quoting the Django docs:
django-csp middleware before app middlewareWith the app's middleware after django-csp's middleware, we get:
django-csp middleware after app middlewareWhen the django-csp middleware is after the app's middleware, we get:
OptionsDocumentation: This seems like something worth noting in the docs, for sure. It's subtle and can cause a lot of time spent wondering why the nonce isn't showing up. You mention:
but according to django-csp's middleware point of view, it has accomplished it's goal. The nonce was never accessed within it's scope of the request/response cycle so it didn't include the nonce in the header. Only after django-csp added the header was the nonce injected into the body of the HTML. Raise an error: It would be possible to swap out the Include the nonce in the header: I can think on this more but on initial thought I don't see how this is possible. The req/resp cycle has already passed through the django-csp code and the header added. Always include the nonce in the header, whether accessed during the req/resp cycle or not: I think there are valid reasons to avoid adding the nonce to the header if it is not used:
That's all the options I can think of at the moment. I'm open to ideas and suggestions. I appreciate that this is being highlighted and reconsidered. |
I think it would be possible to add the header after the fact if you altered the |
This would required recreating the CSP header if someone accesses the nonce after the header was created. But that's the main point of
You could certainly create I think if you've started writing your own Django middleware, then you need to know about middleware order and operations. I'm in favor of documenting it, something like:
and then raising the error if the def used_csp_nonce_too_late():
raise AttributeError("csp_nonce is not available after the CSP header is written. Maybe change your MIDDLEWARE order?")
setattr(request, "csp_nonce", SimpleLazyObject(used_csp_nonce_too_late)) I wouldn't mess with changing this with |
Completely on board with that as a solution :) |
django-csp
only generates the nonce value (and includes it the header) the first time that.csp_nonce
is accessed on a request. However, if that's accessed first in a middleware afterdjango-csp
has completed, it'll be generated but not included in the header, becausedjango-csp
has already finished processing and sendings its headers. Slightly more concretely, if we have:And foo looks something like:
The script will correctly have a CSP nonce in it, but the CSP header won't necessarily include the nonce because of the position of CSPMiddleware.
Obviously the fix is on the user here and "foo.bar" should be positioned after the CSP middleware, however I can attest this took a while to track down. I think it would be better to make this a hard error if a CSP nonce doesn't already exist.
The text was updated successfully, but these errors were encountered: