On 09/08/2010 10:45 AM, f...@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 majord...@metzdowd.com

Reply via email to