I've started tackling one of the ideas that's been on our GSoC ideas
page for a couple years now: integrating django-secure. I chatted with
Carl about the idea and he's onboard. There are a couple of design
decisions we'll need to make.
1. How to integrate django-secure with the checks framework
django-secure essentially implements its own checks framework (which
predates the one in Django). The tricky part is that django-secure's
checks are not ones that generally should pass on a
development instance; they're checks that only make sense to run on a
production server (or at least against a production settings file).
I'm thinking to have some way to skip these new checks by default and
run them only when requested (e.g. manage.py check secure
--settings=prod_settings). Other options include an entirely separate
command like django-secure implements (curently called checksecure),
but perhaps could be called checkdeploy and eventually extended with
other checks that are relevant only in production. Idea/insight from
those more familiar with the checks framework (Chris, Russ), would be
welcome.
2. How to add settings for django-secure
As discussed in the thread below, I'm going to explore developing an
API for storing settings on an AppConfig to avoid adding more global
settings.
https://groups.google.com/d/topic/django-developers/qnnCLppwA3o/discussion
I have imported django-secure into django.contrib.secure and started
work on integrating it with the built-in checks framework as well as
removing some bits of it that have since been added to Django
(frame-deny, SSL-proxy support).
--To view this discussion on the web visit https://groups.google.com/d/msgid/django-developers/CAJxq84_Tq1Fnm_pG4pMSy98DOLsnLtVp9jEgTo6X8%2BH%2BJYi1dQ%40mail.gmail.com.
You received this message because you are subscribed to the Google Groups "Django developers" group.
To unsubscribe from this group and stop receiving emails from it, send an email to django-develop...@googlegroups.com.
To post to this group, send email to django-d...@googlegroups.com.
Visit this group at http://groups.google.com/group/django-developers.
I am fine with putting it in core instead of contrib. That just means we need to figure out what to do about settings since we cannot put them on an AppConfig. Assuming we don't want to add them as normal settings, we may be able to use the approach proposed on this mailing list for the CSRF settings -- using attributes on the middleware class (PR). In that could work by iterating through MIIDDLEWARE_CLASSES until it finds a subclass of SecurityMiddleware and then check the attributes (settings) on that class. I will look into this approach tomorrow.
-1 to adding the middleware.
Regarding settings, would it be preferable to move them into a single dictionary setting called something like SECURITY_MIDDLEWARE_CONFIG?
I've implemented the ability to register "deployment checks" by adding deploy=True to register: @register("tag_name", deploy=True). These checks are only run if you pass the --deploy flag to check. So in development you can run `manage.py check --deploy --settings=settings_prod` to check your production settings file. Running these checks automatically if DEBUG is False would likely give them better visibility, but I don't see an easy way of disabling them when testing if we did that.Regarding settings, would it be preferable to move them into a single dictionary setting called something like SECURITY_MIDDLEWARE_CONFIG?
On Thursday, August 28, 2014 6:27:40 AM UTC-4, Tim Graham wrote:The settings for the SecurityMiddleware as they appear in django-secure are:SECURE_HSTS_SECONDS=0SECURE_HSTS_INCLUDE_SUBDOMAINS=FalseSECURE_CONTENT_TYPE_NOSNIFF=FalseSECURE_BROWSER_XSS_FILTER=FalseSECURE_SSL_REDIRECT=FalseSECURE_SSL_HOST=NoneSECURE_REDIRECT_EXEMPT=[]Yo-Yo, would be helpful to say *why* you are -1 so we can take that into consideration.
On Thursday, August 28, 2014 2:45:07 AM UTC-4, Yo-Yo Ma wrote:+1 on basically adding the functionality of checksecure to the default validation.-1 to adding the middleware.
--
You received this message because you are subscribed to the Google Groups "Django developers" group.
To unsubscribe from this group and stop receiving emails from it, send an email to django-develop...@googlegroups.com.
To post to this group, send email to django-d...@googlegroups.com.
Visit this group at http://groups.google.com/group/django-developers.
To view this discussion on the web visit https://groups.google.com/d/msgid/django-developers/5069271f-8a21-4fdd-921f-ee2baa11b45b%40googlegroups.com.
If it weren’t for backwards compatibility, we could recursively merge dicts from user settings into defaults settings. For example https://github.com/django/django/pull/3138 achieves that in override_settings.
Considering how many settings we’ve turned into dicts, I’m wondering if we should accept the consequences and implement the merging behavior. We’d have to make sure that setting a key to None is equivalent to not providing it at all. We could take this opportunity to review default values for settings, as we’ve already done in a few specific cases.
If base.py adds CONTENT_TYPE_NOSNIFF and prod.py wants to add HSTS_SECONDS, it would look like this: <snip>
-1 on using dictionaries to group somewhat related settings. Dicts make it much harder to override specific keys - and implementing a dict merge to get around a problem that we're creating ourselves for reasons of perceived attractiveness seems a little backwards. Mergingi
SECURITY_MIDDLEWARE = {'HSTS_SECONDS': 10,}
SECURITY_MIDDLEWARE_HSTS_SECONDS = 10
# base.py
SECURITY_MIDDLEWARE = {'HSTS_SECONDS': 10,'HSTS_INCLUDE_SUBDOMAINS': True,'CONTENT_TYPE_NOSNIFF': True,'BROWSER_XSS_FILTER': True,'SSL_REDIRECT': False,'SSL_HOST': 'prod.my.host.com',}
#staging.py
from base import *
SECURITY_MIDDLEWARE = {'SSL_HOST': 'staging.my.host.com',}
I think the problem becomes more pronounced when you want to override a single sub-setting between your different environments:# base.pySECURITY_MIDDLEWARE = {'HSTS_SECONDS': 10,'HSTS_INCLUDE_SUBDOMAINS': True,'CONTENT_TYPE_NOSNIFF': True,'BROWSER_XSS_FILTER': True,'SSL_REDIRECT': False,'SSL_HOST': 'prod.my.host.com',}#staging.pyfrom base import *SECURITY_MIDDLEWARE = {'SSL_HOST': 'staging.my.host.com',}Does staging now represent the merged dicts of base and staging, or the merged dicts of default and staging? I believe, with the merged dict implementation, it is the merge of staging and default. Now if all of the settings were their own setting rather than an entry in a dict, I'd just set the single setting I'd need to change, and be done with it.There are very little gains to using a dict, and I would argue it harms readability and the use of settings in general unless it's actually required.
Hi Claude,
On 08/31/2014 12:08 PM, Claude Paroz wrote:
(...)
> Once again, I'm not advocating for dictionary settings, only for fare
> debate :-)
I hope you found this email fair ;-)
A case in point is a change that was introduced in 1.7 -- putting the TEST
settings of databases into an inner dict. When it was brought up, all
responses were positive. (...)(...)
As I said, everybody who commented on it back then liked it. I still like it
in that context (though, as I mostly work on the Oracle backend, I'm biased).
If we now decide that we globally don't like the concept, perhaps it is not
too late to revert it. Or perhaps the decision shouldn't be so global.
After I wrote the original email, I found #17101 which is where the checkdeploy idea came from. We can just close that ticket (or modify it) if we decide on a different solution. It was created before the checks framework was merged and I agree a separate command may not be ideal, although it may make the implementation slightly easier. I'll look into using DEBUG tomorrow. One issue is that we don't want these checks run during testing (and DEBUG is often False there). Maybe if these checks are registered with something like checks.register(foo, deploy=True), we can skip any checks registered like that during testing. I'll have to see if there's some way to make this work with 'manage.py test' as well as with 3rd party test runners. If we had a separate checkdeploy command, avoiding this problem might be somewhat easier.
I am fine with putting it in core instead of contrib. That just means we need to figure out what to do about settings since we cannot put them on an AppConfig. Assuming we don't want to add them as normal settings, we may be able to use the approach proposed on this mailing list for the CSRF settings -- using attributes on the middleware class (PR). In that case, the check could work by iterating through MIIDDLEWARE_CLASSES until it finds a subclass of SecurityMiddleware and then check the attributes (settings) on that class. I will look into this approach tomorrow.
Thanks for the feedback!
On Wednesday, August 27, 2014 8:47:26 PM UTC-4, Curtis Maloney wrote:For what it's worth, I agree with Russ.Having security as an optional extra [which is how it will look to outsiders] is a bad look for Django, and certainly doesn't fit with the "Secure by default" philosophy.
--CurtisOn 28 August 2014 10:34, Russell Keith-Magee <rus...@keith-magee.com> wrote:
Hi Tim,On Thu, Aug 28, 2014 at 3:35 AM, Tim Graham <timog...@gmail.com> wrote:
I've started tackling one of the ideas that's been on our GSoC ideas
page for a couple years now: integrating django-secure. I chatted with
Carl about the idea and he's onboard. There are a couple of design
decisions we'll need to make.+1 to the idea. It was part of Chris' original proposal; we just didn't get around to it with the available time.1. How to integrate django-secure with the checks framework
django-secure essentially implements its own checks framework (which
predates the one in Django). The tricky part is that django-secure's
checks are not ones that generally should pass on a
development instance; they're checks that only make sense to run on a
production server (or at least against a production settings file).
I'm thinking to have some way to skip these new checks by default and
run them only when requested (e.g. manage.py check secure
--settings=prod_settings). Other options include an entirely separate
command like django-secure implements (curently called checksecure),
but perhaps could be called checkdeploy and eventually extended with
other checks that are relevant only in production. Idea/insight from
those more familiar with the checks framework (Chris, Russ), would be
welcome.Generally, I'd be opposed to the idea of Yet Another Command to run checks - if you make it optional, it won't get run, and this is something we want to be forced in front of everyone.We use DEBUG as a proxy for "In Production" in other locations in the codebase - e.g., whether ALLOWED_HOSTS checks are run. If we were to supplement that with a --production=true/false flag to the checks command (to override the rare legitimate occasions where DEBUG=True in production, or DEBUG=False in development), wouldn't that meet all the needs here?2. How to add settings for django-secure
As discussed in the thread below, I'm going to explore developing an
API for storing settings on an AppConfig to avoid adding more global
settings.
https://groups.google.com/d/topic/django-developers/qnnCLppwA3o/discussion
I have imported django-secure into django.contrib.secure and started
work on integrating it with the built-in checks framework as well as
removing some bits of it that have since been added to Django
(frame-deny, SSL-proxy support).Is it appropriate for this to be a contrib package? That implies it needs to be added to INSTALLED_APPS; I'm not convinced that this is a desirable approach.If django-secure is important enough to include as part of Django's codebase (and I fully agree it is), I'd consider security to be part of core, not something you can opt out of. Including it as django.core.checks.security (or similar) would make more sense to me.Russ %-)
--
You received this message because you are subscribed to the Google Groups "Django developers" group.
To unsubscribe from this group and stop receiving emails from it, send an email to django-develop...@googlegroups.com.
To post to this group, send email to django-d...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/django-developers/CAJxq84_Tq1Fnm_pG4pMSy98DOLsnLtVp9jEgTo6X8%2BH%2BJYi1dQ%40mail.gmail.com.
--
You received this message because you are subscribed to the Google Groups "Django developers" group.
To unsubscribe from this group and stop receiving emails from it, send an email to django-develop...@googlegroups.com.
To post to this group, send email to django-d...@googlegroups.com.
Visit this group at http://groups.google.com/group/django-developers.
To view this discussion on the web visit https://groups.google.com/d/msgid/django-developers/2d66a232-1f19-4bcc-8178-7e1e060f497b%40googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/django-developers/2316E343-8EEF-40B3-B043-CA64FA555382%40solidlinks.nl.
To view this discussion on the web visit https://groups.google.com/d/msgid/django-developers/6E64C365-8959-40F3-95F2-FDB4C86F7158%40stufft.io.
If I were hosting a Django site on example.com, and enable HSTS with includeSubdomains and a lifetime of 6 months, as seems to be common now, I might not only break my own site, but also every other side under example.com. Upon discovering the error it can be corrected, but not before a unknown set of users has memorized that all of example.com and any site under it must use HTTPS.
If we recommend HSTS, we need visible warnings and a small duration in examples, for people who copy-paste without reading.