New Article: Securing the Username Token with WSE 2.0

Security Briefs

Syndication

Back in November I worked with Hervey and Matt on a piece dedicated to the care and feeding of Username Tokens. If you're using the Username Token, you should read this article, which just went live at the MSDN Web Services Dev Center. The Username Token is so incredibly easy to abuse.

Thanks to Hervey and Matt for their input.


Posted Feb 01 2005, 02:59 PM by keith-brown
Filed under: ,

Comments

William wrote re: New Article: Securing the Username Token with WSE 2.0
on 02-02-2005 1:45 PM
Thanks Keith. Nice article! Have been having a lot of debates with myself and others around these ideas as of late, so I toss some more spaghetti on the wall...

"We can make progress on both fronts by modifying our approach to creating the password equivalent. Instead of using SHA-1(password), we use SHAd-1(password + userName + scopeUri) as the password equivalent.

userName and scopeUri are salt values. By including the user name as a salt, we limit the scalability of an offline attack by forcing the enemy to attack one password at a time since each account has a different salt."

This allows us to not “have” to store any salt, as the userName and scopeUri are known for each request. However, it does not really add anything over using random salt which is recommended for salt. Instead we could generate 10 bytes (each byte in the 0-255 range) of true random salt and use that instead. That would also satisfy the requirement that the verifier is different on other sites as each salt is random. We also note that the only reason for salt is so that the same password will not result in the same verifier in the db – so this forces a new dictionary attack on each verifier. This does not really hurt me that bad if I am the attacker because I don’t really expect too many people will be using the same PWD anyway. If I do get one or two, that is nice, but no great bargain. So we want salt and we want pwd equiv to not be a simple SHA1(password) of the clear password. Therefore client can send SHA1(userName + password) password equivalent (PWE) to prevent simple dictionary attacks in the pipeline and use SHA1(DBSalt + PWE) as the verifier like (Note this still assumes encrypted channel as recommended):

Client Password Equiv (PWE) = SHA1(userName + password)
DBSalt = RandomBytes(10)
DBVerifier = SHA1(DBSalt + PWE)
Server Verify logic becomes: return ( DBVerifier == SHA1(DBSalt + PWE) );

At user creation, server generates random salt bytes and adds the PWE and hashes that. Verifier is stored along with the salt in the db. When a client sends PWE, the DB salt is pre-pended and hashed and compared to Verifier. This also eliminates the need for the client to request the salt and scopeUri before hand - so I don't have to publish either or worry about canonical forms for user names, etc.

"scopeUri is simply a string that is unique to your password database. This ensures that the password equivalents you are using are different from those that another site uses. Neither of these salts is secret. An attacker gains no additional benefit by discovering their values."

But if I am the attacker and have all the salts and the verifier, I gain great benefit by having all the inputs I need to perform the crack (minus the clear password). So it does not really slow my algo down much to append the salt(s). To this point, it could be interesting to *protect the salt by encryption. Thinking out load...Say you have a Salt Admin and a Salt Service/program. This elected person is not an Admin. A service on the machine runs under Salt admin account - this account pwd is super long and totally random. The service's one public API is to take a PWE and the encrypted salt string and return the Verifier bytes. The caller can verify returned bytes against DBVerifier as above. Now you need the salt admin and DB admin to get together to crack db passwords. Just a thought, could have various forms.

With all this discussion of user databases, I still wonder how great it is to require thousands of companies to build and maintain separate databases when we already have this cool thing called AD? We can leverage helpdesk, password policies, pwd change requests, etc. using existing AD tools that most people will already be familiar with. Naturally this does require we have the *clear pwd in our verify logic as we have to call Win32s LogonUser to verify username/pwd. Naturally, we will encrypt the pwd at the client using the server's public key or session key. And we have to somehow reduce the amount of code that has access to the clear pw in the server pipeline. Have some thoughts on that, but probably another discussion.

Considering all above, I would probably not allow UsernameTokens at all! But instead require SecurityContextTokens only. All methods will require at least a signed SOAP body that is signed with an *authenticated SCT (or Derived SCT) - nothing else is allowed. Now you can focus attention strictly on the mechanics of how the SCT is generated and securing the pwd within that negotiation period. I have a soap.tcp implementation of this at:
http://spaces.msn.com/members/staceyw/Blog/cns!1pnsZpX0fPvDxLKC6rAAhLsQ!273.entry . Anyway, this is all interesting stuff. Thanks again for your article. Cheers.

-- William Stacey [MVP]
Lorenzo Barbieri @ UGIblogs! wrote WS: Rendere sicuro lo Username Token con WSE2.0
on 02-03-2005 1:18 AM
SecureWebServices.Org wrote Securing the Username Token with WSE 2.0
on 02-16-2005 7:48 AM
Keith Brown has an interesting MSDN article about Username Token and the different types of attacks against it. Definitely worth getting developers on your team to read this, especially since it has great parts like "A Non-Solution: Sending Username Token
Mark Wagner's .NET C# Cogitation wrote Securing the Username Token with WSE 2.0 by Keith Brown
on 03-30-2005 3:14 PM
Louis DeJardin @ MarketWatch wrote re: New Article: Securing the Username Token with WSE 2.0
on 04-12-2005 9:06 AM
Thanks for the article. That's a very interesting change in the least persistant information needed by the server.

You've stressed the importance of protecting the signatures produced by password equivalents. That probably applies to all usernametoken signatures even if the password equivalent is not sent or if a one time hash is sent instead. I could be missing something but I couldn't see a wse supported policy construct that enforced that.

So I made a policy statement! It spins through elements - for each signature, if the signingtoken is encrypteddata, the signiture must also be encrypteddata with the same token.

<wsp:Policy wsu:Id="Sign-Username-Buyers">
<wssp:Integrity wsp:Usage="wsp:Required">
<wssp:TokenInfo>
<wssp:SecurityToken>
...
</wssp:SecurityToken>
</wssp:TokenInfo>
<wssp:MessageParts Dialect="http://schemas.xmlsoap.org/2002/12/wsse#part">wsp:Body()</wssp:MessageParts>
</wssp:Integrity>
<wssp:Confidentiality wsp:Usage="wsp:Required">
<wssp:KeyInfo>
...
</wssp:KeyInfo>
<wssp:MessageParts Dialect="http://schemas.xmlsoap.org/2002/12/wsse#part">wse:UsernameToken()</wssp:MessageParts>
</wssp:Confidentiality>
<sc:SignatureConfidentiality wsp:Usage="wsp:Required" xmlns:sc="urn:secret" />
</wsp:Policy>
Louis DeJardin @ MarketWatch wrote re: New Article: Securing the Username Token with WSE 2.0
on 04-12-2005 2:34 PM

Here's the code for the WSE policy assertion.

http://loudej.blogspot.com/2005/04/signatureconfidentiality-policy.html


Thanks again.
- Lou

Andy Neilson wrote re: New Article: Securing the Username Token with WSE 2.0
on 06-07-2005 9:24 AM
This is an excellent article.

There is a potential problem with the method you describe in "A Non-Solution: Sending Username Tokens in the Clear":

>>>... You must also document a canonical form for user names, or silly things like case insensitivity will case some users to fail authentication.<<<

Doing something like translating the user name to lowercase is problematic since such a transformation is culture-dependent. I might be tempted to use String.ToLower(CultureInfo.InvariantCulture), but this is only defined on the .NET platform. For example, there would be no way to guarantee that you would produce the same lowercase representation using Java.

I suppose it might be possible to gather some bits from the user name in a culture-independent way, but my point is that the obvious solution might not work.
Keith Brown wrote re: New Article: Securing the Username Token with WSE 2.0
on 06-07-2005 10:44 AM
Andy,

Yep, the whole naming problem is something that I brought up when Hervey first suggested incorporating the user name into the hash. I immediately thought of the issues one would have canonicalizing the name: user names are almost universally not case sensitive, so I figured canonicalization would make that problematic, especially given localization issues.

That's why it's part of my "non-solution" ;-)

Add a Comment

(required)  
(optional)
(required)  
Remember Me?