On 22:50 +0100 / 13 Apr, Luke Plant wrote:
> Hi Rohan,
> 
> Sorry for the slow reply on this one, I've had a busy time recently.
> Please see my comments on some parts of this proposal.

No worries about this.
> 
> On 31/03/12 19:10, 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) 
> > ```
> 
> I'm very cautious about making the logic here more complex. It can be
> done, but every additional code path increases the possibility of a
> security hole. ..

Yes, this will touch critical code of the framework and cannot afford
to expose any possible vulnerabilities. That is why I am planning of a
thorough security level testing and of course any patch relating this
(or anything else in this security related proposal) will need careful
reviews before being considered safe.

> .. At the moment, it seems that few browsers send the
> 'Origin' header for normal HTML requests. (Recent versions of Chrome,
> Firefox and Opera do not, I don't know about IE).

Page, http://caniuse.com/cors mentions the browsers and their versions
which support CORS. A big share of browser does support it and another
big one (constituting old IE and Opera) does not. We cannot expect
these browsers to go away anytime soon, so we have to keep maintaining
a compatibility system.

Since http referrer is already being used in case of secure requests,
how about something similar in normal requests? Isn't the argument
about referrer being absent only in 0.2% case or less valid here? Is
0.2% too significant for normal requests?

> > 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.
> 
> Currently the CSRF cookie has to be accessible in browser if the AJAX
> workaround in our docs is to work at all:
> 
> https://docs.djangoproject.com/en/dev/ref/contrib/csrf/#ajax
> 

Sorry, I forgot to consider this. Will strike the statement.

> 
> > ###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.
> 
> 
> The reason for the strict referer checking under HTTPS is set out here:
> 
> https://code.djangoproject.com/wiki/CsrfProtection
> 
> Particularly, it is to fix the 'CSRF + MITM' attack that is possible
> under HTTPS. The key elements are set out in the following scenario
> (although it is not the only variation):
> 
>  - a client connects to a site via HTTP: http://example.com/
>  - in the response, an active MITM attacker sets a cookie over
>    HTTP for example.com
>  - this cookie will be used by the client when it connects over HTTPS
>    to the same domain (this is the fundamental problem, but we can't
>    fix it - it's what browsers do).
>  - the MITM also inserts a POST form in the HTTP response.
>    The form has a CSRF token that matches the cookie that was
>    set by the attacker.
>    The forms targets https://example.com/ and is automatically
>    submitted by javascript.
> 
> Without strict referer checking, the POST request will succeed, even
> though it is forged.
> 
> Signing the cookie or token value does no good at all, because the
> attacker can retrieve a valid cookie/token pair directly from
> https://example.com/.

I am a bit confused about this. How can an attacker extract the token
out of the signed cookie without the private key? There is a
possibility that the attacker deletes and sets the cookie right out,
but since that case won't be correctly signed server can handle it
securely.

> 
> So, this part of the proposal is flawed.
> 
> Storing a token in the session *does* work, because the attacker can't
> know what it is. However, as you mentioned, this ties CSRF protection to
> the session, which has a number of disadvantages - we moved away from it
> because of genuine problems people were having, associated with false
> positives from the CSRF middleware due to session cycling (since the
> CSRF token was tied to a particular session).
> 

The idea tying the CSRF system over sessions a higher level app, i.e.
contrib.sessions does not give a good feeling. So, making a check if
sessions is installed in the CSRF middleware won't be right. Instead
there can be a concept of 'pluggable token stores' with CSRF. A store
will be expected to expose an interface similar to that by sessions.

One such store can be 'django.contrib.sessions.csrf.SessionStore'
which will basically be an abstraction to the session backend. I
suggested putting the csrf backend in the session app to ensure that
it is maintained with contrib.sessions.

> Also, I'm not sure that it is safe for the case where the session data
> is exposed e.g. if the session backend actually stores the session the
> cookie, rather than in a database to which an attacker has no access.
> Since the attacker can send javascript to the client, he can extract the
> cookie that way, and I think forge a request (I haven't thought this
> through).

If the CSRF token stores thing is their, we can have the session store
complain when cookie backend is being used. And instead, provide one
another store probably one which uses signed cookies. This can be use
in cases where sessions database storage is not present.

CSRF token has to be stored somewhere in order to maintain a state.
So on some level or another we have to use the cookies system, however
bad design it may have.
Referrer/Origin checking seems like one other way for getting past
this all.

--
Regards
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