mozilla / django-csp Goto Github PK
View Code? Open in Web Editor NEWContent Security Policy for Django.
Home Page: https://django-csp.readthedocs.io/en/latest/
License: BSD 3-Clause "New" or "Revised" License
Content Security Policy for Django.
Home Page: https://django-csp.readthedocs.io/en/latest/
License: BSD 3-Clause "New" or "Revised" License
The implementation of the csp_*
decorators is such that they can't be chain, this is unfortunate when using class based views with mixins, for example I had something like:
class SomeMixin(View):
@csp_update(FRAME_SRC=("https://someothersite.com",))
def get(self, *args, **kwargs):
return super(SomeMixin, self).get(*args, **kwargs)
class SomeView(SomeMixin, View):
@csp_update(IMG_SRC=("https://someothersite.com",))
def get(self, *args, **kwargs):
return super(SomeView, self).get(*args, **kwargs)
Only the decorator from SomeView
was actually applied. This doesn't work because csp_update
overrides _csp_update
on the response. I'm not sure if this is a design decision or an implementation flaw. I can put up a PR to fix this if it's wanted!
FWIW I'd expect the outer-most decorator to update anything inside of it.
Using the decorators modifies the config in memory. A pull request to fix this has been submitted. #52
In a Django application, there are often certain views that are not controlled by the developer (such as the Django admin). For those of us using 'strict-dynamic'
in our CSP policies, the only real option currently is to whitelist these URLs (which is very undesirable).
It is also common to have fallback CSP policies for when a user agent doesn't support strict-dynamic
. An example policy would be 'strict-dynamic' 'unsafe-inline' 'self' 'http:' 'https'
. With this policy, a CSP 3.x compatible browser would ignore unsafe-inline
, self
, http:
, and https:
and only obey strict-dynamic
while older browsers would ignore strict-dynamic
and follow the policy in the other directives.
It would be nice to define some sort of settings.CSP_BYPASS_STRICT_DYNAMIC
value that would exclude views from having strict-dynamic
applied to their CSP policy while leaving the other fallback directives alone. That way, views that the developer does not control (like Django admin) would have at least some benefit from CSP.
A decorator to set an entire policy for a specific view. Unlike @csp_patch
(#11) this would completely override the site-wide policy and only include the directives mentioned. It would also cause policy-uri
to be removed and the complete policy to be sent.
Relates to #50
https://docs.djangoproject.com/en/dev/topics/logging/
"A logger can have multiple handlers, and each handler can have a different log level. In this way, it is possible to provide different forms of notification depending on the importance of a message. For example, you could install one handler that forwards ERROR and CRITICAL messages to a paging service, while a second handler logs all messages (including ERROR and CRITICAL messages) to a file for later analysis."
Rather than hardcoded email support, use the standard logging framework
After updating to the current spec + firefox foibles, we need to write better docs, including a note about the report URL: if it redirects (e.g. because of LocaleURLMiddleware
) reports don't get posted.
The CSP 1.0 specification allows this explicitly in the sixth paragraph of Section 3.3: http://www.w3.org/TR/CSP/#processing-model
An example is given, too: "For example, if a server operator is using one policy but wishes to experiment with a stricter policy, the server operator can monitor the stricter policy while enforcing the original policy."
This would require bigger changes to the way the middleware works (maybe a flag as a parameter to the decorators? ... something like only_report=True). If this is in scope for the middleware, I am willing to propose an implementation soon.
Hi!
I've got an issue to load base64 data. Even I put it like this:
CSP_SCRIPT_SRC = (
"'self'", "'unsafe-inline'", 'disqus.com', '*.disquscdn.com',
'*.disqus.com', 'data:'
)
What I do may wrong?
Gino
Something I didn't add into my earlier contribution was coveralls or some similar tool. But I forgot to raise the issue beforehand, so I'm doing it now.
I usually like to look at the code coverage of projects, but since this project lacks it, I was thinking about suggesting adding it. Thoughts?
There's a lack of support for this feature.
I think that {% csp_nonce %}
in conjunction with some kind of random string generation in headers might do the trick.
What do you think?
For example when we start changing the docs it would be nice if users of the older version can still get the docs for that version. Right now it looks like rtd only has latest and stable.
The django admin relies on a fair amount of inline Javascript, which CSP breaks. It'd be nice to be able to specify that the admin interface shouldn't use CSP.
At the moment there can only be one root level config for all of a project. But it would be nice to define this per app or per url
This is possible with https://urlmiddleware.readthedocs.org/en/latest/ and being able to configure the middleware using arguments
config = {
'DEFAULT_SRC': ("'self'",),
'STYLE_SRC': ("'self'", "'unsafe-inline'")
}
middlewarepatterns = mpatterns('',
middleware(r'^accounts/', CSPMiddeware(config=config)),
)
Hi,
I want to use CSP with a directive that matches a script path and whatever the current request's host is, instead of having to explicitly list all the possible hosts.
So in your Django settings you could have:
CSP_DEFAULT_SRC = ["'none'"]
CSP_SCRIPT_SRC = ['{host}/app.js']
And at runtime this would be transformed by django-csp, substituting the host name from the request. A request to a server at example.com would generate a response with a header like:
Content-Security-Policy: default-src 'none'; script-src example.com/app.js
While a request to the same application running on localhost:8000 would generate a response with a header like:
Content-Security-Policy: default-src 'none'; script-src localhost:8000/app.js
On Google App Engine, a site is available at potentially any number of different host names, because every version of a deployed application can have its own link. For example if I upload 3 versions called "v1", "v2", and "foo-bar-baz" to an app called "my-app", then all of these would be valid host names:
When writing a CSP directive, this means you cannot know all the host names that the site will use, so while you could use script-src 'self'
, there's no way of writing a directive that includes a path that covers all host names. E.g. you can't do script-src 'self'/app.js
, you need to do script-src my-app.appspot.com/app.js v1-dot-my-app.appspot.com/app.js v2-dot-my-app.appspot.com/app.js foo-bar-baz-dot-my-app.appspot.com/app.js
.
In addition, you don't want to use a wildcard like script-src *.appspot.com/app.js
because there are many other sites on appspot.com which you don't want to whitelist.
So what would be nice would be a way to substitute the host name from the request, and combine that with the path in a directive. I was thinking to allow a special string in "CSP_*_SRC" settings, {host}
, which the middleware would replace with the host name taken from the request.
Another nice thing about this is it makes it easy to support requests to the local development server on "localhost:8000" without needing to add that explicitly to directives.
I have a proof of concept middleware which should help explain what on earth I am on about.
Any interest in having a feature like this in django-csp itself?
Thanks,
David B.
Installation with Pip has no recent changes. For example, in from_settings from file utils.py the policies 'base-uri', 'child-src', 'form-action' and 'frame-ancestors' do not exist.
The middleware could parse keywords in debug mode (in development phase) and log Django warnings if keywords were misspelled, such as 'noen' or similar. This mechanism could be generalized to check for the possible source expressions.
However, I believe that missing single quotes cannot be reliably detected. (Maybe there is a host on the network with the domain name none?) I'd like to be wrong here...
It appears the policy-uri
directive is gone from the spec so we don't need that view or setting anymore.
There are a few places that still imply the report processing feature exists, even though it was removed in #30.
and a CSP report processing facility to Django.
If you are not using the built in report processor
It may also be worth mentioning on the "CSP Violation Reports" docs page that you'll now need to set up some other service for capturing the reports (and perhaps a link to https://developer.mozilla.org/en-US/docs/Web/Security/CSP/Using_CSP_violation_reports), if only since old blog posts about django-csp still mention the report processing feature, so this would make it much clearer.
I'll try to open a PR for this if I get a moment :-)
I have a blogpost app that allows a url link in the admin.
On the frontend this is display in a popup which will display the Content Security Policy directive error.
Note the frontend is a django flatpage using blogpost template tag
to show the post.
Is there a way to allow a url when it is added in the admin for a model ?
Thanks
Currently django-csp is missing support for CSP 2.0 settings:
Here's an overview of the changes from level 1 https://www.w3.org/TR/CSP2/#changes-from-level-1
Given the project setting:
CSP_SCRIPT_SRC = ("'self'", "'unsafe-inline'")
and a single view, decorated as:
@csp_update(SCRIPT_SRC="'unsafe-eval'")
yields a TypeError
Traceback:
File "/PATH/lib/python2.7/site-packages/django/core/handlers/base.py" in get_response
188. response = middleware_method(request, response)
File "/PATH/lib/python2.7/site-packages/csp/middleware.py" in process_response
43. replace=replace)
File "/PATH/lib/python2.7/site-packages/csp/utils.py" in build_policy
32. config[k] += v
Exception Type: TypeError at /page/
Exception Value: can only concatenate tuple (not "list") to tuple
which is in contrast to the documentation, which says the project settings may be a tuple or list (or None
), while the decorators may be are either strings, lists or tuples.
The issue is likely this line, and changing it to (v,)
seems to fix it, though I don't know if that could be considered a complete fix.
Relates to #50
This needs to be done carefully because since support for child-src is only hitting in FF45 (according to MDN) running both child-src
and frame-src
will be needed for maximum compatibility.
A high traffic site may generate a vast quantity of reports, especially if there's a violation on a main page. We should include the ability to store only a sample of reports. This sample rate should be recorded when the report is stored so metrics can later take it into account.
Per https://w3c.github.io/webappsec-csp/#changes-from-level-2 2.3 though we might want to wait for CSP3 to make it out of draft.
Looked at Sentry but that's probably not a good requirement. We should collect and aggregate these and provide a better way of notifying admins than just sending them every report.
Add probably two models, csp.Report
and csp.Group
, and a couple of settings, including a sample rate.
class Group(Model):
name = CharField() # This is probably a combination of the document-uri and the violated-directive, and possibly blocked-uri.
hash = CharField() # Or this is where we combine all 3 and the name is just more human-readable.
class Report(Model):
group = ForeignKey(Group)
document_uri = CharField()
blocked_uri = CharField()
referrer = CharField()
violated_directive = CharField()
original_policy = TextField()
date = DateTimeField()
sample_rate = FloatField()
def get_hash(self):
"""Some combination of the above attributes to group these things by."""
And I think we want a couple of signals hooked up:
Then a great thing would be a fancy admin view to let us look at reports and groups in a better way than the default Django admin, but hopefully with no additional requirements over the default admin.
https://www.w3.org/TR/CSP/#directive-report-to
http://wicg.github.io/reporting/#examples
Still in draft and not in caniuse yet: Fyrd/caniuse#2375
This is a separate spec and might belong in a separate package.
A possible config format like the following could add the report-to header and report-to=endpoint-1
to the CSP header:
REPORT_ENDPOINTS = (
{ "url": "https://example.com/reports",
"group": "endpoint-1",
"max-age": 10886400 },
{ "url": "https://backup.com/reports",
"group": "endpoint-1",
"max-age": 10886400 }
) # could also be set statically by in the reverse/proxy or webserver config
CSP_REPORT_TO = "endpoint-1"
We'd also need to define how this behaves with respect to CSP_REPORT_URI
.
Django 1.10 introduced a new middleware API: https://docs.djangoproject.com/en/1.10/topics/http/middleware/
Instructions for upgrading the middleware are at:
https://docs.djangoproject.com/en/1.10/topics/http/middleware/#upgrading-pre-django-1-10-style-middleware
The Travis CI configuration will also need to be updated to test against Django 1.10.
Hi, I get this error when I try to install this and add its middleware
No module found: csp.middleware
Trailing slash for report
URL is missing. I know this is stylistic issue, but there should at least be a way to have both.
Current way of saving JSON directly to the database is error prone. If JSON contains any additional field saving of the report fails. For example, for Firefox 16 I had to add those fields:
source_file = models.CharField(max_length=400, null=True, blank=True)
line_number = models.IntegerField(null=True, blank=True)
script_sample = models.TextField(null=True, blank=True)
Currently, only the final header Content-Security-Policy
is sent by django-csp. However, looking at http://caniuse.com/contentsecuritypolicy, it seems many current, and after that many slightly older browsers, still only support webkit's X-WebKit-CSP
form.
Although I can understand the argument that we should only be using the final Content-Security-Policy
, it would improve security for users to also include X-WebKit-CSP
, at least for some time to come. An alternative would be to make this an optional feature.
I'm happy to create a pull request for either option, but wanted to wait to see whether anyone agrees with me.
Django page debug view uses inline JavaScript which does not work if CSP is enabled that page. When Django debug view is displayed instead of original page, CSP should be disabled (or at least allow inline script and other things necessary for Django debug view).
(By Django debug view I have in mind the error page which is displayed on exception or similar.)
can someone please add an example of iframe in a template pointing to yahoo.com or google.com
I want to add an iframe in my django template, pointing to an external application or website, and I am having hard time using django-csp , setting all its headers.
Firefox uses X-Content-Security-Policy
, Chrome uses X-Webkit-CSP
. We should do some basic UA-detection, and send the right header. And probably set Vary: User-Agent
.
Hi all,
We'd like to take advantage of some new functionality added to django-csp. Is there any way that you could create a new release since it seems like there have been numerous changes since the last release?
Thanks! ๐
A decorator to modify the site-wide security policy for a specific view. This would not change any directives not mentioned, except it would cause policy-uri
to be removed and the entire policy to be sent.
The default value for CSP_EXCLUDE_URL_PREFIXES is currently hardcoded as ('/admin',)
I think it would make more sense to to do something like:
prefixes = getattr(settings, 'CSP_EXCLUDE_URL_PREFIXES', None)
if prefixes is None:
try:
prefixes = (reverse('admin:index'),)
except NoReverseMatch:
prefixes = ()
As this guarantees that the path to the standard Django admin (which I'm assuming was the target for /admin
in the first place) is correct if used, and doesn't allow any of these words (and whatever variants one might use) to accidentally be CSP free because of no trailing slash (which the Django admin would provide, being conceptually a URL namespace)
It would be nice to make sure that releases always update the version in the docs to match.
I am trying CSP in my project. For the entire application i have some config setting and for a selected view i have decorated with a different setting. Here are my observations and where I believe django_csp seems to work oddly.
a) Application views:
i) All the violations outside the whitelist is blocked - As expected
ii) All the violations get reported on each occurence ie if the view is called 10 times with same or different violations each occurence is reported through the report-uri - As expected
b) Decorated view:
I used the django_csp.csp.csp decorator to completely define a new csp setting for the view.
i) All the violations outside the whitelist is blocked - As expected
ii) If i made 10 calls to the URL which is using this view, only in the first instance it gets reported and no subsequent call is reported, even though the content is blocked. Strangely if all these 10 calls have different violations, only the first gets reported - Not expected
I did some research around this behaviour and could see that the 'report-uri' directive is not available in the 'Content-Security-Policy' response header for the subsequent calls Is this expected or an issue ?
Relates to #50
https://www.w3.org/TR/CSP3/#disown-opener
It's still in draft and not implemented anywhere.
We should have a signal set up on report creation, like group_created
, so that 3rd party code can listen in and do things like send data to Graphite. This should be really easy.
Traceback (most recent call last):
File "/app/sitepackages/django/core/handlers/base.py", line 235, in get_response
response = middleware_method(request, response)
File "/app/sitepackages/csp/middleware.py", line 43, in process_response
replace=replace)
File "/app/sitepackages/csp/utils.py", line 58, in build_policy
policy.append('report-uri %s' % ' '.join(report_uri))
TypeError: sequence item 0: expected string, __proxy__ found
With CSP_REPORT_URI = reverse_lazy('report_csp')
This may be a meta issue, but there are a number of new directives in the CSP 1.1 draft that need to be added.
The current Group/Report ID is generated based on fields directly in the report. But, for example, someone might care more about the specific view function than the actual URL, or not at all about which content was blocked.
We should make it easy to override Report.get_identifier
without having to monkeypatch. This shouldn't be too hard.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.