Hi again, I really couldn't understand the response this post has got. It deserved at least a little feedback, positive or negative. I guess I wont be submitting this over melange.
Still, I have put some effort and research in the proposal. So if possible I would like to know if it had anything of value. Maybe some one could work over that, even me if I get the time. -- Rohan On 23:40 +0530 / 31 Mar, Rohan Jain wrote: > Hi, > > I am Rohan Jain, a 4th (final) year B.Tech undergraduate Student > from Indian Institute of Technology, Kharagpur. I have been using > django since over a year and generally look into the code base to find > about various implementations. I have made attempts to make some minor > contributions and if selected this would be my first major one. > > More about Me: <http://www.rohanjain.in/about/> > IRC, Github: crodjer > > I am interested in contributing some security enhancements to django > as my Summer of Code project. Below is the 1st draft of my proposal > regarding this. A pretty version of this is available at: > https://gist.github.com/2203174 > > > #Abstract > > Django is a reasonably secure framework. It provides an API and > development patterns which transparently take care of the common web > security issues. But still there are security features which need > attention. I propose to work on integration of existing work on > centralized token system and improved CSRF checking without any > compromises. If time permits I will also attempt on integration of > django-secure. > > #Description > ##Centralized tokenization > There are multiple places in django which use some or other kinds of > tokens: > > - contirb.auth (random password, password reset) > - formtools > - session (backends) > - cache > - csrf > - etags > > Token generation is pretty common around the framework. So, instead > of each application having its own token system, and hence needs to be > maintained separately. There should be centralized token system, which > provides an abstract API for everyone to loose. In fact, I have seen > that some apps use `User.objects.make_random_password` from > contrib.auth, which they can be sure of being maintained in the future > for random generation. To me this looks kind of weird. > In last djangocon, a lot of work regarding this was done over [Yarko's > Fork][yarko-fork]. > > I had a discussion with Yarko Tymciurak regarding this. The work is > nearly ready for a merge, only some tasks left. In the initial period > my SoC I can work over these to insure that the already done > significant work gets in django and is updated for 1.5. > > - Porting more stuff to the new system (README.sec in > [yarko's fork][yarko-fork]) > - Testing - See if the current coverage of the tests is enough, write > them if not. > - Compatibility issues > - API Documentation > > I will study the changes done at djangocon and then attempt the tasks > mentioned above. > > ##CSRF Improvements > > Cross-Origin Resource Sharing (CORS): > W3C has a working draft regarding [CORS][w3c-cors-draft], which opens > up the possibility for allowing client-side request cross-origin > requests. This directly triggers in mind the capability to develop > API which can be exposed directly to the web browser. This would let > us get rid of proxies and other hacks used to achieve this. > Currently all the major browsers support this: Chrome (all versions), > Firefox (> 3.0), IE (> 7.0), Safari (> 3.2), Opera (> 12.0). > Introduced it here as some further parts of the post refer to this. > > ###Origin checking > > With CORS around need for using CSRF token can be dropped, at least in > some browsers. [Ticket #16859][orig-check-ticket], is an attempt for > that. But this was rejected because of neglecting the case for > presence of `CSRF_COOKE_DOMAIN` (Refer to the closing comment on the > ticket for details). So to handle this we need to simulate checking of > CSRF cookie domain as web browsers do it. Maybe: > > ```python > reqest.META.get('HTTP_ORIGIN').endswith(settings.CSRF_COOKIE_DOMAIN) > ``` > > As the closing comment points it out, we can't do this with secure > requests. They need to be essentially checked against the referrer or > origin, at least for now. We can not be sure that some untrusted or > insecure subdomain has not already set the cookie or cookie domain. > d > To deal with this, we have to consider https separately as it is > being done now. So it will be something like: > > > ```python > def process_view(self, request, ....): > > # Same initial setup > > if request.method not in ('GET', 'HEAD', 'OPTIONS', 'TRACE'): > > host = request.get_host() > origin = reqest.META.get('HTTP_ORIGIN', "") > cookie_domain = settings.CSRF_COOKIE_DOMAIN > > if request.is_secure(): > good_referer = 'https://%s/' % host > referer = origin or request.META.get('HTTP_REFERER') > # Do the same origin checks here > > # We are insecure, so care less > # A better way for this check can be used if needed > elif origin.endswith(cookie_domain): > # Safe, accept request > > # Some unsupported browser > # Do the conventional checks here > ``` > > If the above were to be implemented, the setting `CSRF_COOKIE_DOMAIN` > should be deprecated for something like `CSRF_ALLOWED_DOMAIN` which > makes more sense. > > I would also suggest making CSRF cookie as http only. There doesn't > seem a reason currently why the cookies would be needed to be accessed > in browser. > > ###Less restrictive secure requests > > The current CSRF system is pretty much secure as it is. But CSRF > protection poses too much restriction to https. It says no to all the > request, without honouring any tokens. It kind of has to, thanks to > the way browsers allow cookie access. A cookie accessible through > subdomains mean that any subdomain secure or insecure can set the CSRF > token, which could be really serious for the site security. To get > around this, currently one has to completely exempt views from CSRF > and may or may not handle CSRF attacks. This can be dangerous. Also if > a person has a set of sites, which talk to each other through clients > and decides to run it over https, it would need some modifications. > > Django should behave under https similarly as it does under http > without compromising any security. So, we need to make sure that the > CSRF token is always set by a trusted site. Signing the data with the > same key, probably `settings.SECRET_KEY`, across the sites looks apt > for this, using `django.core.signing`. We can have `get_token` and > `set_token` methods which abstract the signing process. > This can be done in two ways: > > - Store CSRF data in sessions data in case `contrib.sessions` is > installed. Then the data will automatically be signed with the > secret key or will not be stored in the client as cookies at all. > > - In case of it being absent from installed apps, revert to custom > signing > > ```python > from django.core.signing import TimestampSigner > > signer = TimestampSigner("csrf-token") > CSRF_COOKIE_MAX_AGE = 60 * 60 * 24 * 7 * 52 > > > def get_unsigned_token(request): > # BadSignature exception needs to be handled somewhere > return signer.unsign(request.META.get("CSRF_COOKIE", None) > max_age = CSRF_COOKIE_MAX_AGE) > > def set_signed_token(response, token): > response.set_cookie(settings.CSRF_COOKIE_NAME, > signer.sign(request.META["CSRF_COOKIE"]), > max_age = CSRF_COOKIE_MAX_AGE, > domain=settings.CSRF_COOKIE_DOMAIN, > path=settings.CSRF_COOKIE_PATH, > secure=settings.CSRF_COOKIE_SECURE > ) > > > def get_token(request): > if 'django.contrib.sessions' in settings.INSTALLED_APPS: > return request.session.csrf_token > else: > return get_unsigned_token(request) > > def set_token(response, token) > if 'django.contrib.sessions' in settings.INSTALLED_APPS: > request.session.csrf_token = token > else: > set_signed_token(response, token) > > # Comparing to the token in the request > constant_time_compare(request_csrf_token, get_token(csrf_token)) > > ``` > > Now, doing this is not as simple as the above code block makes it > look. There is a lot which can and probably will go wrong with this > approach: > > - Even when the token is signed, other domains can completely replace > the CSRF token cookie, it won't grant them access through CSRF > check though. > > - This sort of couples CSRF with sessions, a contrib app. Currently > nothing except some of the other contrib apps are tied up with > sessions. It will break if sessions were to be removed in future or > the API changed. Also, this means that if one website is using > sessions CSRF, all of the other must be too. > > - If this were successfully implemented, is this exposing any > critical security flaws otherwise? Will it cause compatibility > issues? > > As Paul McMillan said "This is a hard problem", I'll delegate figuring > this to future me. I will look into [The Tangled Web][tangled-web] > and [Google's Browser Security Handbook][gobrowsersec] for ideas, > again suggested by Paul on the IRC. > > ###Better CORS Support > Since, already introducing Origin checking, we can go one step further > and try to provide better support for CORS for browsers supporting it. > A tuple/list setting, which specifies allowed domains will be > provided. Using this the various access control allowance response > headers will be set when the request origin is from amongst the > allowed domains. For CSRF check, just see if http origin is present in > allowed domains. > > ```python > > def set_cors_headers(response, origin): > response['Access-Control-Allow-Origin']: origin > > def process_response(self, request, response): > > origin = reqest.META.get('HTTP_ORIGIN', "") > > if origin in settings.CSRF_ALLOWED_DOMAINS: > set_cors_headers(response, origin) > > def process_request(self, request, response): > > # Use origin in settings.CSRF_ALLOWED_DOMAINS here instead of > # origin.endswith > > ``` > > Probably, something similar to the above will be needed to incorporate > the CORS support. > > ##Integrating django-secure > A really useful app for catching security configuration related > mistakes is [carljm's django-secure][djang-secure]. It is specially > useful to find out issues that might have been introduced while quick > changes to settings for development. This project is popular and > useful enough that it can be shipped with django. I haven't been able > give this enough time yet. I can think of two ways of integrating > this: > > - Dropping it as a contrib app > This seems pretty straight forward would require minimal amount of > changes. > > - Distribute around the framework: > Like CSRF, this can also be distributed framework wide and hence it > won't be optional to have. Apps can still define custom checks in > the same way when `django-secure` was installed as a pluggable > application. > > The app might also need some changes whilst being integrated: > > - More security checks, if required > - Adjust according to the changes introduced above. > > #Plan > I think that the tasks centralized tokenization and CSRF enhancements > will be enough to span through the SoC period. If after a thorough > implementation and testing of these, I still have time, django-secure > integration can be looked into. > > ##Timeline > I have listed the tasks above in a chronological order. I'll add a > more granular timeline in one of the next drafts. > > > [yarko-fork]: https://github.com/yarko/django > [w3c-cors-draft]: http://www.w3.org/TR/access-control/ > [orig-check-ticket]: https://code.djangoproject.com/ticket/16859 > [tangled-web]: > http://www.amazon.com/The-Tangled-Web-Securing-Applications/dp/1593273886/ > [gobrowsersec]: http://code.google.com/p/browsersec/wiki/Main > [django-secure]: https://github.com/carljm/django-secure > > > -- > Thanks > Rohan Jain -- You received this message because you are subscribed to the Google Groups "Django developers" group. To post to this group, send email to django-developers@googlegroups.com. To unsubscribe from this group, send email to django-developers+unsubscr...@googlegroups.com. For more options, visit this group at http://groups.google.com/group/django-developers?hl=en.