Hashing algorithm needed

Marsh Ray marsh at extendedsubset.com
Wed Sep 8 14:08:46 EDT 2010


On 09/08/2010 10:45 AM, flj at mail.dnttm.ro wrote:
> Hi.
>
> Just subscribed to this list for posting a specific question. I hope
> the question I'll ask is in place here.

Oh good, this makes me not the new guy now :-)

These seem like nice standard, authentication system design questions. 
I'll give them a shot.

> We do a web app with an Ajax-based client. Anybody can download the
> client and open the app, only, the first thing the app does is ask
> for login.

Using SSL here makes all the difference in the world. Without SSL, an 
attacker can modify your javascript to do anything he wants, such as 
sending the password in plaintext or redirecting the browser to a 
malware site.

Since SSL is required for us to even discuss security in a meaningful 
way, most of the rest of my comments assume all URLs are https. Ideally, 
the only thing you serve out of port 80 is a redirect to https and you 
support STS Strict Transport Security.
http://en.wikipedia.org/wiki/Strict_Transport_Security

> The login doesn't happen using form submission, nor does it happen
> via a known, standard http mechanism.

Still, you're sending something via a standard HTTP POST or GET method. 
I assume you're using a standard session cookie? Be sure it has the 
"secure" flag set.

> What we do is ask the user for some login information, build a hash
> out of it, then send it to the server and have it verified. If it
> checks out, a session ID is generated and returned to the client.
> Afterwards, only requests accompanied by this session ID are answered
> by the server.
>
> Right now, the hash sent by the browser to the server is actually not
> a hash, but the unhashed login info. This has to be changed, of
> course.

Although it doesn't seem right to me either, sending the plaintext 
password via a HTTP POST body is really the standard way to implement a 
login form over https.

Again, your servers will refuse to accept credentials except over SSL, 
right?

> What we need is a hashing algorithm that: - should not generate the
> same hash every time

I think the words you want to use are "select a standard, well-accepted 
hash algorithm for use in this authentication protocol". For example, 
SHA-256.

Hash functions (all functions really) by definition produce the same 
output for the same inputs. So you want to include "unpredictable" data 
in the input.

> - i.e. should includen something random
> elements

In addition to the random data chosen by the client, it would be good to 
have some random data sent by the server, too. Its better if this data 
is not sent back by the client directly, the legitimate server should 
know what he sent.

> - should require little code to generate - should allow
> verification of whether two hashes stem from the same login data,
> without having access to the actual login data

That's the hard part.

> We need to implement the hashing algorithm in Javascript and the
> verification algorithm in Java, and it needs to execute reasonably
> fast, that's why it has to require little code.

Standard hash algorithms usually have Javascript code available that 
should be fast enough for a login process. Java will have a native C 
implementation available in its crypto library.

> None of us is really
> into cryptography, so the best thing we could think of was asking for
> advice from people who grok the domain.
>
> The idea is the following: we don't want to secure the connection, we
> just want to prevent unauthenticated/unauthorized requests.

The only way to do that is to "sign" the contents of each and every http 
request with the password. There are schemes that do this, but again 
it's rather pointless since the bad guy supplied the Javascript that the 
browser is running anyway.

> Therefore, we only send a hash over the wire and store it in the
> database when the user changes his password, and only send different
> hashes when the user authenticates later on. On the server, we just
> verify that the stored hash and the received hash match, when an
> authentication request arrives.

It will take a little more than just comparing a received hash with a 
static database entry. If that were all there was to it, the transmitted 
hash would be a password equivalent.

In any case, if the attacker can see these transmitted hashes he can 
attempt to crack them at a later time to recover the password unless 
there was a secret he doesn't know mixed in to the hashed data (but how 
could there be if you don't secure the connection?) So you're putting 
the complexity of the user's chosen password plus a hashing function 
that runs quickly in Javascript in a computational drag race with the 
attacker's set of gigahertz CPUs, GPUs, and Amazon EC2 nodes. The best 
you can do is include the random data to prevent him from using 
precomputed tables to help with the attack and raise the cost of 
cracking each password.

In practice, attackers can conduct millions of tries per second so most 
passwords can be cracked relatively quickly. This is especially bad 
because 43%* of users will be using that same password for their online 
banking and all their accounts.

*From memory, study conducted by Sophos a few years back.

> Cleartext passwords aren't stored
> anyway, and don't ever travel over the wire.

This is a good goal. Watch out for this: if the thing you send over the 
wire could be used to login on a different connection, then it doesn't 
matter if it's hashed or not, it represents a "plain text equivalent 
password".

> However, we could not imagine a reasonable algorithm for what we need
> until now, and didn't find anything prefabricated on the web.

This problem has been studied pretty thoroughly for web applications 
over the years but it comes down to this: With SSL you might as well 
send the plaintext password, without it you aren't securing anything anyway.

There are attempts to improve on this. For example Micorosoft's 
integrated auth which can negotiate Kerberos or NTLMv2 authentication. I 
haven't looked into the Kerb one much, but the NTLMv2 auth has some 
long-known security weaknesses.

> Therefore we ask for help.

Here's an existing scheme that's a lot like what you're asking for:
http://en.wikipedia.org/wiki/Digest_access_authentication

Best of all, it's already built into the HTTP client and server.

> PS: reusing the session ID is of course a security risk, since it
> could allow session hijacking. We're aware of this, but don't intend
> to do anything about it other than warn customers/users.

So what are they going to do about it other than worry?

> Since it's a
> web application, its client code is open, and anybody being able to
> watch the connection can deduce whatever is needed to hijack the
> session, no matter what algorithm is used, unless the connection is
> encrypted right from the start. Connection security is however
> outside the scope of the web application.

It's good that you're considering that from the beginning, but I suggest 
you reconsider that decision.

> We can't encrypt
> communication in Javascript for efficiency reasons,

And for actual security reasons, too.

> it has to be done
> in a lower layer (VPN or SSL, for example).

Again, it's got to be SSL anyway.

> It may in theory work
> using a preshared key, but it's not reasonable to believe that the
> application users will be able to cope with such a mechanism.

That's a good bet. Or at least you can expect that for every group of 
users who can handle presharing a key there exists a much larger group 
that includes potential users which can not.

- Marsh

---------------------------------------------------------------------
The Cryptography Mailing List
Unsubscribe by sending "unsubscribe cryptography" to majordomo at metzdowd.com



More information about the cryptography mailing list