Bug 51966 - Tomcat does not support ssha hashed passwords in all contexts
Summary: Tomcat does not support ssha hashed passwords in all contexts
Status: RESOLVED DUPLICATE of bug 56403
Alias: None
Product: Tomcat 6
Classification: Unclassified
Component: Catalina (show other bugs)
Version: 6.0.33
Hardware: PC All
: P2 enhancement with 6 votes (vote)
Target Milestone: default
Assignee: Tomcat Developers Mailing List
URL:
Keywords:
: 45871 (view as bug list)
Depends on:
Blocks:
 
Reported: 2011-10-05 18:34 UTC by Adam Caldwell
Modified: 2014-09-15 10:58 UTC (History)
5 users (show)



Attachments
Patch that implements ssha passwords (10.46 KB, patch)
2011-10-05 18:34 UTC, Adam Caldwell
Details | Diff
updated patch that uses a saltBytes attribute / can be used with any digest algorithm (13.27 KB, patch)
2011-10-06 01:29 UTC, Adam Caldwell
Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Adam Caldwell 2011-10-05 18:34:10 UTC
Created attachment 27699 [details]
Patch that implements ssha passwords

We have a requirement to use ssha hashed passwords (salted SHA-1) for tomcat.  This is only supported with LDAP currently -- and we can't use LDAP.

I have created a patch that implements SSHA for all other Security Realms
Comment 1 Christopher Schultz 2011-10-05 21:44:11 UTC
Comment on attachment 27699 [details]
Patch that implements ssha passwords

(Marked patch as patch, so we can see diffs via BZ)
Comment 2 Christopher Schultz 2011-10-05 21:58:49 UTC
I like this idea (and have been considering it for a while), but I don't like the implementation due to the following reasons:

1. Uses part of the password as the salt, which is not a good idea. Read-up on password salting
2. Reveals the last 4 bytes of the user's password by using it as the salt :( (https://issues.apache.org/bugzilla/attachment.cgi?id=27699&action=diff#orig/apache-tomcat-6.0.33-src/java/org/apache/catalina/realm/RealmBase.java_sec7)
3. Static string "ssha" implies SHA-1 hashing (which is flawed)
4. Hard-coded salt-length ("last 4 bytes = 8 characters" which is incorrect)
5. Overloads RealmBase.digest with a 2-argument version, and then always calls that with null instead of calling the single-arg version
6. Looks like this patch could have been a single minor change to the RealmBase.digest method

I would support a patch that:

1. Didn't use part of the password to salt the password itself
2. Allowed the realm configuration to specify the hashing algorithm to use
3. Allowed the realm configuration to specify the salt length
Comment 3 Adam Caldwell 2011-10-05 22:16:39 UTC
Thank you for the great feedback. The salt isn't part of the users password. If you look at the digest method that's used to generate the encoded password, it is 4 random bytes. The ssha name is the same name/4 random byte method that is already used in the ldap code. 

My need for this stems from a weblogic to tomcat conversion we are doing. Weblogic uses the same 4-byte random method.

I do like the idea of hard-coding less though so that you could use salts with any algorithm. I'll see what I can come up with.
Comment 4 Adam Caldwell 2011-10-06 01:29:54 UTC
Created attachment 27703 [details]
updated patch that uses a saltBytes attribute / can be used with any digest algorithm

I've re-worked the patch to address the concerns.  I added an isValidEncodedPassword to Realm Base that is now used by the other methods.  The number of saltBytes is configurable and the RealmBase main has been updated to accept a -s ## to indicate how many salt bytes to use.
Comment 5 Christopher Schultz 2011-10-11 20:30:51 UTC
(In reply to comment #3)
> Thank you for the great feedback. The salt isn't part of the users password. If
> you look at the digest method that's used to generate the encoded password, it
> is 4 random bytes.

Given the small scope of the patch, it wasn't clear that Principal.getPassword was returning the hashed password from the credential store. Apologies for not reading carefully.
Comment 6 Mark Thomas 2011-10-28 22:14:06 UTC
*** Bug 45871 has been marked as a duplicate of this bug. ***
Comment 7 Neale Rudd 2012-03-20 06:50:14 UTC
Hey Guys,

Great work on the patch so far Adam.

I'd love to see this implemented as well.  The current hashing provides no security at all unless symbols are used in the passwords, because of the availability of good, large rainbow tables on the net these days.

However, I'd prefer the salt to be prepended and separated with a $ symbol like other implementations typically use.  The current patch seems to rely on a fixed salt-length, which means the length can't ever be changed (all hashes would become useless).

eg:
arbitrary-length-hex-encoded-salt-bytes$hex-encoded-digest

The patch can check for a $ symbol, and separate the string based on it.

Advantages:
- If no $ mark found, the digest can be treated as non-salted - so older hashes can remain valid until the users change their passwords.
- Avoids needing to set the salt-length in a server.xml parameter, which removes a couple of functions from the patch and the necessary extra documentation for them.
Comment 8 Neale Rudd 2012-03-20 07:07:08 UTC
Could also change Realmbase.main to use SecureRandom.
Comment 9 Christopher Schultz 2012-03-22 20:22:45 UTC
I recently added the capability to use salted and iterated hashes to my own DataSourceRealm -- but it's been diverging from TC's realms for quite a while.

Mine does not use $ to separate the salt from the hash, so that essentially fixes my salt-length in stone. I might want to change my implementation ;)

I'd be happy to share my code with the community, but either I or someone else will have to do some heavy work on it to get it to fit-in with the current Realm code in Tomcat.
Comment 10 Oliver Kohll 2012-07-24 20:11:50 UTC
Just another strong vote for salted passwords. Any issues with or progress on the current patch?
Comment 11 david 2012-08-27 21:00:16 UTC
Unfortunately, just adding salt to hashes doesn't provide much more security these days.  Modern password hashing algorithms, such as bcrypt, include the salt as part of the hash.  What's more, the current digest algorithms are woefully out of date, so just adding salt will just extend the illusion that they are secure.

A better solution would be to allow users to plug in a digest algorithm that they trust, and perhaps to bundle a few high quality third-party algorithms as well.

I'm going to create a separate bug report with more details.
Comment 12 Oliver Kohll 2013-02-10 11:00:38 UTC
David, I see your other report

https://issues.apache.org/bugzilla/show_bug.cgi?id=53785

is currently marked RESOLVED WONTFIX. I'm not a security expert but I don't think there's much argument that salting or a pluggable architecture would be an improvement on the current implementation of unsalted hashing.

I for one appreciate the work others have done to date, above. It's unfortunate I don't have enough knowledge to contribute helpful patches myself but I'm sure this is going to be something that sees an increasing amount of interest.
Comment 13 Christopher Schultz 2013-02-13 18:16:04 UTC
Please see http://markmail.org/thread/cipopgduels3d7yh

No responses thus far. Feel free to reply and voice your support!
Comment 14 Gabriel 2014-02-01 17:27:14 UTC
I am relatively new to Tomcat.  Has any progress been made on this issue?  I would like to use Tomcat with DataSourceRealm for a web application but am not willing to store user passwords without salting them, preferably with arbitrarily sized salt.  I am surprised that this hasn't been addressed and that fixing the issue is not a priority.  Are there alternatives I am not aware of that people are using, and is that why adding support for salt is not a priority?
Comment 15 S 2014-02-02 17:59:17 UTC
Hi,

what I'm doing is to hash the user-entered password 999x on the client with a salt (visible in the JS code) on the OK-Click in my login form. Then I send it to Tomcat and have it compared to the stored hash (1000x hashed with the same salt).

This way there is never send a unhashed password (even not when you are not using https, which you shouldn't) and you can configure the number of pre-hashing to your needs (to be safe against generating rainbow tables for your salt). This might be useful in times of modern GPUs executing billions of SHA1-hashes per second (2300M/s SHA1 hashes in 2009).
Comment 16 Christopher Schultz 2014-02-05 22:23:35 UTC
(In reply to S from comment #15)
> Hi,
> 
> what I'm doing is to hash the user-entered password 999x on the client with
> a salt (visible in the JS code) on the OK-Click in my login form. Then I
> send it to Tomcat and have it compared to the stored hash (1000x hashed with
> the same salt).

This is awful security. When the client is involved in authentication, that's called not being authenticated.

In production, we salt-hash 75000 times by default, and should probably do more. 10k times isn't nearly enough.

> This way there is never send a unhashed password (even not when you are not
> using https, which you shouldn't) and you can configure the number of
> pre-hashing to your needs (to be safe against generating rainbow tables for
> your salt). This might be useful in times of modern GPUs executing billions
> of SHA1-hashes per second (2300M/s SHA1 hashes in 2009).

Shouldn't use HTTPS, or shouldn't send otherwise-unencrypted passwords over HTTPS? Both of those sound like bad advice.

Nobody should be using SHA-1 anymore for authentication.

Realistically, nobody should be using crypto hashing for password hashing, anyway.
Comment 17 S 2014-02-05 23:56:25 UTC
(In reply to Christopher Schultz from comment #16)
> This is awful security. When the client is involved in authentication,
> that's called not being authenticated.
I don't understand. It's the same Tomcat does out-of-the-box (send data to j_security_check and wait for the result), but with more hashing.

> In production, we salt-hash 75000 times by default, and should probably do
> more. 10k times isn't nearly enough.
I'll test how long a client takes for 100K and if its acceptable (which I assume) I'll change.

> > This way there is never send a unhashed password (even not when you are not
> > using https, which you shouldn't) 
> Shouldn't use HTTPS, or shouldn't send otherwise-unencrypted passwords over
> HTTPS? Both of those sound like bad advice.
I meant: You should use https. I can't see the problem generated by sending a (salted, many-round) hash (with the exception of rainbow table attacks).

> Nobody should be using SHA-1 anymore for authentication.
> Realistically, nobody should be using crypto hashing for password hashing,
> anyway.
The second Tomcat supports SCrypt or BCrypt I'll change. What's your suggestion for the time being?
Besides changing Tomcat yourself like in http://stackoverflow.com/questions/12285604/writing-a-custom-tomcat-realm-using-bcrypt, which I really don't want to do.
Comment 18 Gabriel 2014-02-06 00:22:01 UTC
The only advantage I see of hashing in the client side is not storing a String with the cleartext password in memory.  Strings are immutable objects, so they cannot be cleared once password processing is completed.  If no references point to it, then the garbage collector should eventually do the job.  I've seen that careful password authentication implementations use a char array for this reason.  Char arrays are mutable, so as soon as password processing is complete, all of the array elements are zeroed out, reducing the time an attacker might have to read the password off memory.  Tomcat's password authentication methods should follow this best practice and be changed to do the handling with char[].  

A risk of receiving the cleartext password is that someone with access to the server may write code to store passwords, and if users use the same password for other web accounts, then bad things can happen.  Hashing might make it just a bit less easy for an insider to do that.  They can still do brute force and dictionary attacks, of course.  So it doesn't go a long way at all.  

Hashing on the server is necessary to protect passwords in the event a malicious person obtains access to the password table, even if hashing was done on the client side.  Client side hashing by itself would make no difference here.

And of course, no kind of hashing protects from weak passwords or stolen passwords from the clients via key loggers and whatnot.  

Should we change the meta data of this thread to reflect the direction the discussion has taken?  Is this still a Tomcat 6 issue, or should we say it is a proposed new feature for Tomcat 8 revisions?  Or do you think that all versions of Tomcat should be updated?
Comment 19 Gabriel 2014-02-06 02:55:19 UTC
(In reply to S from comment #17)
> (In reply to Christopher Schultz from comment #16)
> > This is awful security. When the client is involved in authentication,
> > that's called not being authenticated.
> I don't understand. It's the same Tomcat does out-of-the-box (send data to
> j_security_check and wait for the result), but with more hashing.
> 
> > In production, we salt-hash 75000 times by default, and should probably do
> > more. 10k times isn't nearly enough.
> I'll test how long a client takes for 100K and if its acceptable (which I
> assume) I'll change.
> 
> > > This way there is never send a unhashed password (even not when you are not
> > > using https, which you shouldn't) 
> > Shouldn't use HTTPS, or shouldn't send otherwise-unencrypted passwords over
> > HTTPS? Both of those sound like bad advice.
> I meant: You should use https. I can't see the problem generated by sending
> a (salted, many-round) hash (with the exception of rainbow table attacks).

Hashing on the client side has its merits as long as you also hash on the server side and you don't use the same salt on the client as you do on the server.  In particular, if your client code fetches the salt corresponding to a username, that lets an attacker know if they have a valid username (if they receive a salt from the server to do hashing on the client side).  If you use a random salt generated for a client session or even a constant client-side salt, it is best to also hash on the server side with an independent user-specific hash.  

If you hash on the client side but not the server side, and an attacker steals the password table, they essentially have all the passwords they need to get into your site.  They don't need to know the cleartext passwords... they can modify the javascript on the client side to send the stolen hash (and not hash again) and the server will let them in.  This is why strong hashing on the server side is necessary.

> 
> > Nobody should be using SHA-1 anymore for authentication.
> > Realistically, nobody should be using crypto hashing for password hashing,
> > anyway.
> The second Tomcat supports SCrypt or BCrypt I'll change. What's your
> suggestion for the time being?
> Besides changing Tomcat yourself like in
> http://stackoverflow.com/questions/12285604/writing-a-custom-tomcat-realm-
> using-bcrypt, which I really don't want to do.
Comment 20 Gabriel 2014-02-06 03:14:43 UTC
(In reply to Gabriel from comment #19)
> 
> Hashing on the client side has its merits as long as you also hash on the
> server side and you don't use the same salt on the client as you do on the
> server.  In particular, if your client code fetches the salt corresponding
> to a username, that lets an attacker know if they have a valid username (if
> they receive a salt from the server to do hashing on the client side).  If
> you use a random salt generated for a client session or even a constant
> client-side salt, it is best to also hash on the server side with an
> independent user-specific hash.  
> 
Oops... random salt generated for a client session wouldn't work, would it?  It would either have to be constant or user specific.  I suppose constant is best on the client side.
Comment 21 S 2014-02-06 09:42:43 UTC
In order to illustrate how I understood possibilities and their use in Tomcat, I made a list of authentication mechanisms:

0) Compare the sent PW to the stored PW
1) Hashing the sent PW on the server, compare it to stored hash (Tomcat default)
2) Hashing the PW n times on the client, hashing the sent hashed PW once more on the server, compare it to stored n+1 rounds hash
3) Hashing the PW n times on the client (with [fixed and user known] salt), hashing the sent hashed PW once more on the server, compare it to stored n+1 rounds hash (n with salt, 1 without salt)
4) Using jBCrypt / scrypt

All these come in http / https flavors.
As far as I understand, only 1, 2 and 3 are possible today without changing Tomcat.
Do you agree?

In terms of security it is 0<<<<<<<<<<<<<<<<<<1<<<<<<<<<<<<<<<<<<2<3<<<<<<<<<<<<<<<<<< ..... <<<<<<<<<<<<<<<<<<4
A support for jBCrypt / scrypt would really be great!
Comment 22 Gabriel 2014-04-13 16:03:57 UTC
Note Bug 56403 for Tomcat 8 deals with a pluggable interface that would make it easier to resolve this.
Comment 23 Mark Thomas 2014-09-15 10:58:15 UTC
The broader solution outlined in bug 56403 is the right way to do this. I'm currently working on taking Chris's proposal there and turning it into a patch that can be applied to 8.0.x.

*** This bug has been marked as a duplicate of bug 56403 ***