Archives for : May2012

Databases: How to securely store sensitive information

One problem that many people have is figuring out the best way to store sensitive information that needs to be retrievable, such as credit card numbers, securely in a database? The solution for passwords is simple: hash (and salt) them. That’s fine, because you don’t ever need to retrieve a password, the user has to input it and you compare the hashes. For credit card information, doing something like that would be, well, absolutely pointless, since it would defeat the purpose of actually storing the credit card information in the database.

How it’s already done

It’s already possible, to some extent, to encrypt credit card information. You could use some private/public key pair someway, or you could just encrypt everything with the same symmetric key. The problem with this is, the private key or encryption key needs to be stored somewhere, and the web server needs to be able to access it. So it may work if your database and web servers are different and your database server gets compromised, but if your web server gets compromised as well (remembering that many smaller websites will use the same server as the web server and database server,) then it’s pretty pointless.

Is there a way that the web server can decrypt it without having any human interaction (e.g. to type in the encryption key) except for the customer? I believe there is.

Alternate Way

So I got to thinking, how could this possibly work? Then I thought of this: take 2 hashes of the password (with 2 different salts,) then use one to store in the database for log in purposes, and then use the other one as a symmetric key for sensitive information and store it in a cookie.

It would go something like this:

  • Password = P
  • Salt1 = S1
  • Salt2 = S2
  • Hash1 = Hash(P & S1)
  • Hash2 = Hash(P & S2)
  • Hash1 and Hash2 are both generated when a user logs in.
  • Hash1 is stored in database, and is used to compare log in.
  • Hash2 is stored in a cookie on the user machine and accessed when needed.
  • Credit Card Info = CC
  • Secure Credit Card Info = Encrypt[Key: Hash2] (CC)
  • Store secure credit card info in the database.

Down Sides

There are of course down sides.

  • It’s extra work to have to do, in that you need to generate an extra hash each time the user logs in.
  • It won’t work  they forget their password. You can use a good password recovery method, but then they’ll need to re-enter all the information you have encrypted.
  • Cookies aren’t necessarily the most secure method of storing info, but at the same time someone would have to compromise your web server and database server whilst that user was logged in to be able to access their cookies, or manage to get into the customers system (but if that happens, it’s not your problem.) Also, make sure your web server doesn’t store a cache of cookies somewhere, or store them in a log file. That would also defeat the purpose (well, it would still make it harder for a hacker to figure out, but once they do it’s all gone.)
  • You won’t be able to do subscription payments, since the customer will need to be logged in to do it. I personally think this could be good, as I don’t like companies automatically charging my credit card, a solution would be for them to email me and have me login to approve each payment.

Also remember, do everything over HTTPs! There’s no excuse to not do everything over HTTPs these days. You should also never rely on the encryption to store data securely, rather you should focus on preventing data getting into the wrong hands… encryption is for if your database does get compromised, you can minimise the damage done.