Re: Design and code review requested for Django string signing / signed cookies

2010-01-06 Thread Elias Torres


On Jan 6, 10:37 am, Luke Plant <l.plant...@cantab.net> wrote:
> On Wednesday 06 January 2010 04:24:15 Elias Torres wrote:
> > Thanks Luke for your explanation. I think I have learned something
> > here in terms of my own application security independent of
> >  Django's multi-app environment. Basically, you're reminding me
> >  that as an application, I must be careful to not sign any random
> >  string for a user, because it can be re-used for another purpose.
> >  Therefore, we include the 'purpose', salt, or namespace in the
> >  process. One thing I would like to ask though, is whether the salt
> >  needs to be part of the key or the value? If you look at
> >  TimestampSigner, the timestamp goes as part of the value. I think
> >  the same can be done with the name of the cookie. In other words
> >  you can always use a method like _cookie_signature as in Tornado's
> >  implementation [1] and always pass two parts: cookie name and
> >  cookie value. Technically, as long as your SECRET_KEY is
> >  protected, there should not be a need to creating multiple signing
> >  keys, especially if the data is not secret.
>
> > def _cookie_signature(self, *parts):
> >   hash = hmac.new(SECRET_KEY, digestmod=hashlib.sha1)
> >   for part in parts: hash.update(part)
> >     return hash.hexdigest()
>
> This is equivalent to:
>
>   hmac.new(SECRET_KEY,  
>    digestmod=hashlib.sha1).update("".join(parts)).hexdigest()
>
> With this, one problem is that accidental collisions between different
> parts of code are easier.  Consider two cookies:
>
> Cookie 1, name = "use", value = arbitrary string set by user
> Cookie 2, name = "user_id", value = server assigned once they've
> logged in correctly.
>
> By supplying "r_id123" as the value for cookie 1, I can forge a
> user_id=123 cookie.  If some validation is imposed on cookie 1, it
> might still be possible to manipulate the system such that "r_id123"
> is a valid choice, and the exploit would still work.

Agreed.

>
> Actually, the implementation in Tornado does not include the cookie
> name in the signature at all, making it even more vulnerable to this
> kind of attack.

Absolutely. I mailed the Tornado mailing list last night as well on
the matter.

>
> So that would be my defence of why it's better to put the "purpose"
> namespace into the key, rather than the value, in the context of HMAC.
> I'm not an expert though.

Can a separator solve that issue?

>
> This is one of the tricky things with security - it's never just a
> case of "use this API" - what you feed into the API is always
> critical.

Absolutely. It can become a very powerful black box.

>
> > Any thoughts on Django's auth using HMAC besides md5 and sha1
> >  hashing alone?
>
> It sounds like a good idea, I'm not aware of any particular problems
> with our current implementation that would make this a priority
> change.
>

I think you are right and the 'being able to sign other messages'
attack that HMAC protects us against is not the main issue with
passwords. However, one thing I see some folks moving towards are
slower hashing functions to better protect stolen databases against
dictionary attacks. My friend enlightened me that computing SHA1 HMACs
or hashes it's way too fast so even with a salt, you can still match
many passwords from a stolen database. bcrypt on the other hand is
much slower. But that's just an FYI, not really suggesting to use it.

Thanks for the answers. Every time the subject comes up, I learn
something else about security and passwords.

[1] http://www.mindrot.org/projects/py-bcrypt/


> Luke
>
> --
> "Mediocrity: It takes a lot less time, and most people don't
> realise until it's too late." (despair.com)
>
> Luke Plant ||http://lukeplant.me.uk/
-- 
You received this message because you are subscribed to the Google Groups 
"Django developers" group.
To post to this group, send email to django-develop...@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.




Re: Design and code review requested for Django string signing / signed cookies

2010-01-05 Thread Elias Torres
On Jan 5, 2:33 pm, Luke Plant <l.plant...@cantab.net> wrote:
> On Tuesday 05 January 2010 16:53:17 Elias Torres wrote:
>
> > Simon,
>
> > I'm not a security expert by any means, but I really the fact that
> > you're making use of HMACs in your design. I will ask a good friend
> > (Ben Adida) who's really an expert on the subject to see if your
> > paranoia on adding a salt and hashing the key helps you in any way.
> >  My intuition says if the salt will be stored and made available to
> >  anyone with access to the DB, I'm not sure it will make much of a
> >  difference. HMAC takes care of the prefix/suffix attacks already.
>
> The point of the 'salt' is to make it easy to use unique keys.  
> Otherwise, one use of HMAC with SECRET_KEY in a web app could be
> trivially used to compromise another usage.
>
> For example, suppose that, on a social network, the user can specify
> the username of someone that they nominate as a 'best friend' .  This
> value might be stored in a signed cookie.  If we use SECRET_KEY
> without salt as the HMAC key, the user then has access to the value
> HMAC(SECRET_KEY, some_username). But suppose another signed cookie is
> used to store the username when a user logs in (as opposed to using a
> session).  The value will be HMAC(SECRET_KEY, users_username).  Since
> an attacker can trivially get hold of  HMAC(SECRET_KEY,
> somone_elses_username), they can log in as anyone they like.
>
> 'Salt' in the key is to protect against that.  The signed cookie
> implementation, for example, uses the cookie *name* as part of the
> salt, so that all cookies have their own key.  The salt is not a
> secret, so doesn't provide any additional protection against brute
> force attacks, but it isn't meant to.
>
> Luke

Thanks Luke for your explanation. I think I have learned something
here in terms of my own application security independent of Django's
multi-app environment. Basically, you're reminding me that as an
application, I must be careful to not sign any random string for a
user, because it can be re-used for another purpose. Therefore, we
include the 'purpose', salt, or namespace in the process. One thing I
would like to ask though, is whether the salt needs to be part of the
key or the value? If you look at TimestampSigner, the timestamp goes
as part of the value. I think the same can be done with the name of
the cookie. In other words you can always use a method like
_cookie_signature as in Tornado's implementation [1] and always pass
two parts: cookie name and cookie value. Technically, as long as your
SECRET_KEY is protected, there should not be a need to creating
multiple signing keys, especially if the data is not secret.

def _cookie_signature(self, *parts):
  hash = hmac.new(SECRET_KEY, digestmod=hashlib.sha1)
  for part in parts: hash.update(part)
return hash.hexdigest()


Any thoughts on Django's auth using HMAC besides md5 and sha1 hashing
alone?

Thanks,

-Elias

[1] http://github.com/facebook/tornado/blob/master/tornado/web.py#L251

>
> --
> "Making it up? Why should I want to make anything up? Life's bad
> enough as it is without wanting to invent any more of it." (Marvin
> the paranoid android)
>
> Luke Plant ||http://lukeplant.me.uk/
-- 
You received this message because you are subscribed to the Google Groups 
"Django developers" group.
To post to this group, send email to django-develop...@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.




Re: Design and code review requested for Django string signing / signed cookies

2010-01-05 Thread Elias Torres
oops.. I mean really *like*. Thanks.

On Jan 5, 12:09 pm, Karen Tracey <kmtra...@gmail.com> wrote:
> On Tue, Jan 5, 2010 at 11:53 AM, Elias Torres <el...@torrez.us> wrote:
>
> > I'm not a security expert by any means, but I really the fact that
> > you're making use of HMACs in your design.
>
> There seems to be a key word missing here: really  the fact...
>
> (One might guess based on the rest of the message, but still it might be
> nice to know what was intended to go there.)
>
> Karen
-- 
You received this message because you are subscribed to the Google Groups 
"Django developers" group.
To post to this group, send email to django-develop...@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.




Re: Design and code review requested for Django string signing / signed cookies

2010-01-05 Thread Elias Torres
Simon,

I'm not a security expert by any means, but I really the fact that
you're making use of HMACs in your design. I will ask a good friend
(Ben Adida) who's really an expert on the subject to see if your
paranoia on adding a salt and hashing the key helps you in any way. My
intuition says if the salt will be stored and made available to anyone
with access to the DB, I'm not sure it will make much of a difference.
HMAC takes care of the prefix/suffix attacks already.

Anyway, the main point of my email is to remind folks here that
password management in Django is still not using HMAC-based hashing.
Please read [1] on the matter. I'm currently using Tornado so I used a
couple of methods from Django auth [2] blindly thinking that Django
was doing the right thing and after a friendly code review I was
caught with simple hashing. The good thing is that it was very easy
for me to make a backwards-compatible change to the get_hexdigest()
function:

  if algorithm == 'hmac':
return hmac.new(raw_password, salt, hashlib.sha1).hexdigest()

The nice property of the authentication code path, is that the secret
key is owned by the user logging in and no-one else. Therefore, the
chance of discovering people's passwords with a dump from a Django
application is really small.

[1] http://benlog.com/articles/2008/06/19/dont-hash-secrets/
[2] http://code.djangoproject.com/svn/django/trunk/django/contrib/auth/models.py

Regards,

Elias Torres

On Jan 4, 7:47 am, Simon Willison <si...@simonwillison.net> wrote:
> I'm pursing expert feedback on the crypto used in Django signing /
> signed cookies. Here's the e-mail I'm sending out to various mailing
> lists. I'll also link to this post from a number of places and see if
> I can get some smart eyes on it that way.
>
> 
>
> Hello,
>
> We've been working to add string signing and signed cookies to the
> core of the Django web framework <http://www.djangoproject.com/>. We
> have a design and an implementation but we've decided we should get
> some feedback from security experts before adding it to the project.
>
> I'd really appreciate any feedback people can give us on the approach
> we are using. We're planning on adding two APIs to Django - a low-
> level API for signing and checking signatures on strings, and a high-
> level API for setting and reading signed cookies.
>
> The low-level API can be seen here:
>
> http://github.com/simonw/django/blob/signed/django/utils/signed.py
>
> The core signing logic lives in the Signer class on line 89:
>
> http://github.com/simonw/django/blob/signed/django/utils/signed.py#L89
>
> Here are the corresponding unit tests:
>
> http://github.com/simonw/django/blob/signed/tests/regressiontests/uti...
>
> To summarise, the low-level API is used like this:
>
> >>> signer = Signer('my-top-secret-key')
> >>> value = u'Hello world'
> >>> signed_value = signer.sign(value)
> >>> signed_value
>
> 'Hello world:DeYFglqKoK8DLYD0nQijugnZaTc'>>> unsigned_value = 
> signer.unsign(signed_value)
> >>> unsigned_value
>
> u'Hello world'
>
> A few notes on how the code works:
>
> Signing strings
> ---
>
> Actual signatures are generated using hmac/sha1. We encode the
> resulting signature with base64 (rather than the more common
> hexdigest). We do this because the signatures are expected to be used
> in both URLs and cookies, where every character counts. The relevant
> functions are:
>
> def b64_encode(s):
>     return base64.urlsafe_b64encode(s).strip('=')
>
> def base64_hmac(value, key):
>     return b64_encode(
>         (hmac.new(key, value, sha_constructor).digest())
>     )
>
> Picking a key to use for the signature
> --
>
> We've been (I think) pretty paranoid about picking the key used for
> each signature. Every Django installation has a SECRET_KEY setting
> which is designed to be used for this kind of purpose. Rather than use
> the SECRET_KEY directly as the key for signatures, we derive a key for
> each signature based on the SECRET_KEY plus a salt.
>
> We do this because we're worried about attackers abusing a component
> of a Django application that allows them to control what is being
> signed and hence increase their information about the key. I don't
> know if hmac/sha1 can be attacked in this way, but I'm pretty sure
> this is a good idea. If you have any tips as to how I can explain the
> benefits of this in the documentation for the feature they would be
> greatly appreciated!
>
> By default, the key we actually use for the signature (and hence pass
> to the base64_hmac function above) is sha1('signer' + SECRET_KEY +
> salt). 'salt' defaults