RE: Good salt practices, references?
From: Michael Wojcik (Michael.Wojcik@merant.com)Date: 09/07/01
- Previous message: Robie Basak: "Re: User authentication over the web (was: Secure Password in database)"
- Maybe in reply to: Andrew van der Stock: "Good salt practices, references?"
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ] [ attachment ]
Message-ID: <27B17B8B25A3D411B45800805FA7F01C012E2EBC@mtvmail.merant.com> From: Michael Wojcik <Michael.Wojcik@merant.com> To: secprog@securityfocus.com Subject: RE: Good salt practices, references? Date: Fri, 7 Sep 2001 12:29:39 -0700
> From: Andrew van der Stock [mailto:ajv@e-secure.com.au]
> Sent: Friday, September 07, 2001 12:24 AM
> I'm looking at trying to reduce the risk from authentication over
> the network using preshared secrets.
I understand that the point of your note is primarily to discuss your
proposed new scheme rather than the old one (which you admit is poor), but
it's worth discussing the old one too, I think.
> Right now, the scheme is:
>
> Server encrypts the password, truncated to 8 characters with 3des,
> using a static 8 byte salt.
Well, reducing the risk posed by *that* scheme shouldn't be hard.
Truncating passwords (which typically have poor per-character entropy
anyway) to eight characters makes them too small to resist searches mounted
even by attackers with modest (in current terms) resources.
Are you encrypting with a static key, or is this a scheme like the classic
Unix crypt(3) where the password is actually the key used to encrypt a
static block? (If the latter, you don't actually have 3DES, since you only
have 64 bits of key material. In any case it's not clear from your
description what advantage you're getting from using 3DES rather than simply
DES.) How is the salt actually used? As an IV? Do you prepend or append
it to the block you're encrypting? *Is* it the block you're encrypting?
A static salt is all but worthless; all it does is prevent an attacker from
using a precomputed dictionary that didn't incorporate that salt. That
seems like an unlikely constraint on an attacker.
> It's then stored on the server, supposedly in a safe place.
That's typically considered an acceptable risk (provided reasonable
precautions are taken) in threat models for shared-secret schemes used for
"ordinary" resources (ie. the materials being protected aren't particularly
sensitive/valuable).
It's worth noting, though, that there are shared-secret auth schemes
(SRP[1], for example, or PAK-RY[2]) in which the server's "verifier" is not
in itself sufficient to impersonate the user (as it is in the scheme you're
describing here). You may want to look into them if you want to upgrade the
threat model to include the possibility that the server's verifier database
gets compromised. That might be a good idea, particularly since in your
current scheme the passwords can be trivially reconstructed from the
server's verifiers. At the very least, the server's verifiers should be
cryptographic hashes of the secrets, and not simply the secrets encrypted
(and thus decryptable).
> When the user authenticates, the client takes the user's input,
> encrypts the password with 3des and the same static salt, and
> takes a random 8 or 16 byte challenge from the server to hash with
> the encrypted password.
What's the hash algorithm?
The "challenge" (really just a nonce) from the server defeats simple replay
attacks and trivial extraction of the verifier from the traffic, anyway.
That's a plus, but overall the scheme is still awfully weak.
> The resulting digest response is sent back to the server. The
> server also does the same as the client and compares the two
> digests. If they compare, you're in.
Well, it's better than some of the home-grown solutions I've seen, but it's
still severely broken. Eight characters is much too short; the fixed salt
is of essentially no value; and the server's database of verifiers seems to
potentially provide a lot more information to an attacker than it needs to.
Perhaps more urgent, there doesn't seem to be any mechanism for the client
to authenticate the server here. You seem to be open not only to
man-in-the-middle attacks but outright impersonation, even to trivial spoofs
that log and reject access attempts without trying to verify them. (Users
are generally willing to believe they've mistyped their passwords.)
> There's two attack mechanisms available:
Oh, more than that, I'm sure. But these are two good ones.
> * get the password from the server; time to decrypt, < 1s.
Yes. Ouch. Completely unnecessary, unless the server is sometimes supposed
to impersonate the user. I hope that's not the case.
> * As the challenge, the fixed 8 bit salt, the response and the
> algorithms are known, a remote attacker with access to the data
> stream can attack the password using standard dictionary and brute
> force attacks, particularly as the initial password is always =< 8
> chars long. It shouldn't take much more than two weeks using
> something like John the Ripper on one machine.
Your estimate is optimistic, I'd guess. Such an attacker would likely have
a precomputed dictionary of common passwords and might well get a hit right
off the bat. If not, they'd have at least eliminated a good portion of the
keyspace, which is simply much too small.
> My current thoughts for improving this process are:
>
> Digest the password using SHA1 and store on the server.
A major improvement, but while you're at it, why not have the server store
the digest of the password plus a decently large (8 bytes is fine) random
salt? That increases the storage requirements for precomputed dictionaries
past the point of practicality. The server stores the salt along with the
digest in its database of verifiers and passes it to the client along with
the nonce generated for just that session.
If H() is the hash function, P is the secret password, S is the salt
computed by the server when the password is stored, V is the server's stored
verifier (V=H(P+S)), and N is the nonce (one-time random value generated by
the server for each attempt), then
the server has:
V, S
and computes:
N
H(V+N)
and sends to the client:
S, N
The client has:
P (from the user)
S, N (from the server)
and computes:
H(H(P+S)+N)
and sends it to the server. That's a pretty standard scheme. There are
ways of strengthening it; IIRC we had a discussion about related
password-hashing modes on SecProg just a few weeks ago.
> When the client connects to the server, the server gives the client
> a random salt to use. The client concatenates the digest,
Presumably "the digest" here is of the password and the nonce sent by the
server. I'd recommend computing the digest with both a per-password salt
and a per-attempt nonce as I described above; that shouldn't otherwise
affect your scheme.
> the current time and IP address,
The client's IP address, presumably, based on what you write below. Do you
ever need to support NATed clients? Often, relying on IP address
authentication turns out to be more trouble than it's worth.
> and symmetrically (ie 3des or AES) encrypts the resulting
> concatenation using the digest as the key with the server supplied
> random salt.
I don't offhand see a problem with this step, but be aware that you've
essentially presented an observer with a partially-known-plaintext attack,
since much of that message can be reliably guessed.
> The server takes the encrypted string, and decrypts it. If the
> time is out of whack (within limits, a la kerberos), it dumps it.
This probably doesn't buy you any additional security unless the server is
prone to re-using nonces. On the other hand, redundancy is nice.
> If the IP address doesn't match its ACLs, it dumps the connection.
Again, for many applications, this would probably eventually prove to be a
mistake. But if you're sure your client systems will always have known-good
IP addresses, and the allowed address set doesn't change too often (since
you have an administrative update to the server every time it does), I
suppose you can keep it. And I don't think it provides much additional
security either; if an attacker has any way of guessing an allowed client
address (say, by observing a single successful authentication exchange and
recording the source address in the packets sent by the client), they can
just use that when building their requests.
For that matter, why aren't you just checking the source address of the
client's packets? The nonce, and to a lesser extent the timestamp, are
already protecting against replay.
> Obvious errors, improvements, or has someone solved this before,
> and I'd be better off adopting that instead?
Your new scheme is clearly an improvement, but security is best handled by
specialists. I'd recommend looking at SRP/EPS to see if it satisfies your
needs. It shouldn't be significantly more difficult to implement. There
was a vulnerability discovered last October in the reference SRP
implementation, but it's been fixed.
One thing you don't appear to have addressed is the allowed password length.
This eight-character limit has to go.
[1] http://srp.stanford.edu
[2] http://www.bell-labs.com/user/philmac/pak.html
Michael Wojcik
Principal Software Systems Developer, Micro Focus
Department of English, Miami University
- Previous message: Robie Basak: "Re: User authentication over the web (was: Secure Password in database)"
- Maybe in reply to: Andrew van der Stock: "Good salt practices, references?"
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ] [ attachment ]
Relevant Pages
|