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.

Reply via email to