Hi all,

So, a while ago, BREACH happened, and Django's CSRF implementation was 
vulnerable, as was Rails'. The paper that discussed it described a 
mitigation (and a Rails patch had already been made), so I implemented that 
same mitigation in a Django patch. Discussion on the Trac ticket has 
stalled, and I've been told this is the place to go.

Disclaimer: although I understand enough about it to write the patch, *I'm 
not a security person* - the reason I'm posting here is that I'm hoping to 
get an answer from someone that *is* a security person as to whether I'm on 
the right track.

To jog your memories (and also in the hope that if I'm misunderstanding the 
problem, someone will correct me), the short version of BREACH is: an 
attacker forcing a user to visit a HTTPS page that a) is gzipped, and b) 
contains *in the response body* a secret (in our case, the CSRF token in 
the form), as well as user input (e.g. reflected URL parameters), then 
observing the size of the HTTPS responses. When the user input partially or 
completely matches the secret, the compressed length is slightly shorter, 
and the attacker can use this to guess the secret byte-by-byte.

In section 3 of the paper, the authors describe a variety of mitigations. 
One of them is to, on each request where a secret S should appear, generate 
a new one-time pad P and instead write P + xor(P, S) in the response. (The 
paper also describes other mitigations, but this is the most feasible¹.)

My understanding is (and I'll reiterate here I'm not a security person) 
that this should make S impossible to deduce via BREACH, as it doesn't 
appear directly anywhere in the response. As P takes on a new value with 
every request, it simply can't be deduced by any method that involves 
making many requests; therefore the same thing will happen to xor(P, S). (I 
think the fact that P changes every request might have been a point of 
confusion in the Trac discussion; there's a lot of comments there talking 
about trying to deduce P).

The patch I've written implements this mitigation, with one difference: 
instead of using xor, it uses a Vigenère cipher (as suggested by FunkyBob), 
as xor was creating non-printable characters which caused problems. I think 
this should be OK as Vigenère is commonly used for one-time pads and does 
more or less the same thing to characters that xor does to bits.

This is pretty much what django-debreach does, except that *it* uses AES 
instead of xor (i.e. the output is K + AES(K, S).). However, this adds 
processing load to every request and a dependency on PyCrypto, and as far 
as I can tell this doesn't actually add any benefit over xor/Vigenère.

So, in summary, I think I'm doing nearly exactly what the paper says, and I 
think it effectively makes the attack practically impossible, but I'd love 
to hear from someone who has a better idea than I as to if I'm actually 
correct on all of this.

Thanks,
Adam

The Trac ticket: https://code.djangoproject.com/ticket/20869
My pull request: https://github.com/django/django/pull/1477
The original 
paper: 
http://breachattack.com/resources/BREACH%20-%20SSL,%20gone%20in%2030%20seconds.pdf
 
(the relevant bit is section 3.4 at the bottom of page 10)
The related Rails pull request: https://github.com/rails/rails/pull/11729

¹ Section 3.4 describes the mitigation I implemented. Section 3.1 describes 
fuzzing the lengths of each response by appending random lengths of garbage 
data, then immediately dismisses this method as ineffective; Russell 
Keith-Magee tells me that a discussion within Django reached the same 
conclusion about this one. Apart from those two, they're all things like 
rate limiting and separating secrets from user input, which don't seem to 
me like things we can enforce on a Django level.

-- 
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-developers+unsubscr...@googlegroups.com.
To post to this group, send email to django-developers@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/66fb5b2b-5f18-4244-92fb-2427b5b63aa8%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to