views:

623

answers:

4

We recently had a security audit and it exposed several weaknesses in the systems that are in place here. One of the tasks that resulted from it is that we need to update our partner credentials system make it more secure.

The "old" way of doing things was to generate a (bad) password, give it to the partner with an ID and then they would send that ID and a Base 64 encoded copy of that password in with all of their XML requests over https. We then decode them and validate them.

These passwords won't change (because then our partners would have to make coding/config changes to change them and coordinating password expirations with hundreds of partners for multiple environments would be a nightmare) and they don't have to be entered by a human or human readable. I am open to changing this if there is a better but still relatively simple implementation for our partners.

Basically it comes down to two things: I need a more secure Java password generation system and to ensure that they are transmitted in a secure way.

I've found a few hand-rolled password generators but nothing that really stood out as a standard way to do this (maybe for good reason). There may also be a more secure way to transmit them than simple Base 64 encoding over https.

What would you do for the password generator and do you think that the transmission method in place is secure enough for it?

Edit: The XML comes in a SOAP message and the credentials are in the header not in the XML itself. Also, since the passwords are a one-off operation for each partner when we set them up we're not too worried about efficiency of the generator.

+1  A: 

Couldn't you use SSL Keys for authentication?

ScArcher2
A: 

I'm unclear why transmitting the passwords over SSL -- via HTTPS -- is being considered "insecure" by your audit team. So when you ask for two things, it seems the second -- ensuring that the passwords are being transmitted in a secure way -- is already being handled just fine.

As for the first, we'd have to know what about the audit exposed your passwords as insecure...

delfuego
I'm guessing that the documents are stored in the clear by the recipient, allowing a hacker or corrupt employee to read them. Second, this exposure is probably unnecessary, since the password just needs to authenticate the sender at transmission-time.
erickson
The passwords are very weak at the moment incorporating the ID as part of the password and a couple of non-random digits (ugh).
18Rabbit
+4  A: 

Password Generation

As far as encoding a password for transmission, the only encoding that will truly add security is encryption. Using Base-64 or hexadecimal isn't for security, but just to be able to include it in a text format like XML.

Entropy is used to measure password quality. So, choosing each bit with a random "coin-flip" will give you the best quality password. You'd want passwords to be as strong as other cryptographic keys, so I'd recommend a minimum of 128 bits of entropy.

There are two easy methods, depending on how you want to encode the password as text (which really doesn't matter from a security standpoint).

For Base-64, use something like this:

  SecureRandom rnd = new SecureRandom();
  /* Byte array length is multiple of LCM(log2(64), 8) / 8 = 3. */
  byte[] password = new byte[18];
  rnd.nextBytes(password);
  String encoded = Base64.encode(password);

The following doesn't require you to come up with a Base-64 encoder. The resulting encoding is not as compact (26 characters instead of 24) and the password doesn't have as much entropy. (But 130 bits is already a lot, comparable to a password of at least 30 characters chosen by a human.)

SecureRandom rnd = new SecureRandom();
/* Bit length is multiple of log2(32) = 5. */
String encoded = new BigInteger(130, rnd).toString(32);

Creating new SecureRandom objects is computationally expensive, so if you are going to generate passwords frequently, you may want to create one instance and keep it around.

A Better Approach

Embedding the password in the XML itself seems like a mistake.

First of all, it seems like you would want to authenticate a sender before processing any documents they send you. Suppose I hate your guts, and start sending you giant XML files to execute a denial of service attack. Do you want to have to parse the XML only to find out that I'm not a legitimate partner? Wouldn't it be better if the servlet just rejected requests from unauthenticated users up front?

Second, the passwords of your legitimate partners were protected during transmission by HTTPS, but now they are likely stored "in the clear" on your system somewhere. That's bad security.

A better approach would be to authenticate partners when they send you a document with credentials in the HTTP request headers. If you only allow HTTPS, you can take the password out of the document completely and put it into an HTTP "Basic" authentication header instead. It's secured by SSL during transmission, and not stored on your system in the clear (you only store a one-way hash for authentication purposes).

HTTP Basic authentication is simple, widely supported, and will be much easier for you and your partners to implement than SSL client certificates.

Protecting Document Content

If the content of the documents themselves is sensitive, they really should be encrypted by the sender, and stored by you in their encrypted form. The best way to do this is with public key cryptography, but that would be a subject for another question.

erickson
Yeah, it's base 64 encoding.
18Rabbit
Okay. I would assume you don't really care what the encoding is (since the encoding doesn't really impact the security). If that's the case, I'd probably use new BigInteger(130, rnd).toString(32) to generate a password. That increases password entropy by 2 bits while saving 6 characters in the text.
erickson
A: 

I'd abandon the whole password approach and start using client certificates allowing a 2 side authenticated SSL connection.

You have to generate and sign individual certificates for each client. In the SSL handshake, you request the client's certificate and verify it. If it fails, the connection ends with a 401 status code.

Certificates can be revoked at any time be your side, allowing easily disconnecting former customers.

Since all this happens in the handshake prior to the communication, is is not possible to flood your server with data.

Oli