8

I have already read through Saving credit card information in MySQL database? and Storing Credit Card Information.

I'm aware that storing credit card information requires PCI compliance, which is not an easy task.

That is not what this question is about. My question is the following:

What is a secure way to encrypt user credit cards? The simplest and easiest that comes to mind is using a private key and encrypting CC's with that. This doesn't seem very secure because the key has to be stored on the server, and if an attacker can get my database, they can probably get the key too.

What I'd like to be able to do is encrypt every CC using that users password as part of the encryption process. If anyone gets the database, they can't decrypt anything because the passwords are stored as salted hashes. This would work great for transactional purchases - the user clicks "Buy," types in their password as a confirmation, I decrypt their CC and make the charge. Their password is only in memory for the duration of the request, and is never written to disk.

Unfortunately this won't work for what I'm trying to build - a service which charges a recurring fee (say, once a month), regardless of whether or not the user is logged in when I need to make the charge.

Given this scenario, is there a secure way of storing user CC's?

Community
  • 1
  • 1
  • Does the server that *stores* the CC information also have to be able to *read* the information? E.g. if the monthly charge can be done by an offline machine that reads a copy of the encrypted data, you might want to consider Public key methods... – Damien_The_Unbeliever Jun 15 '12 at 07:17
  • Presumably the system is always connected, and data can be sent to it whenever a user registers. Yes, easier to secure with a specialized interface but implies an external application; and probably not standard web software otherwise it probably exhibits many of the same vulnerabilities as the original host. Third party specialized offsite solutions exist to do exactly this already exist. – shannon Jun 15 '12 at 07:32

6 Answers6

7

As you need to be able to decrypt, there's always the possibility that the encryption keys leak and you'll lose everything. So you'll never get to absolute security, but you can make it harder for attackers to get to the data.

Nobody but you can really judge what level of security (or obscurity) you should have. This is most likely a function of size of database, visibility etc.

For leaks, unfortunately you'll have to assume that everything leaks and sooner or later (e.g. with brute force attacks on weak passwords) you haven't gained too much when they get out.

Given the last credit card leak scandals - the worst ones had the 3-digit (CVV) number saved with the regular credit card number, which credit card companies explicitly forbid (that's why you'll always have to give it again even if someone has your credit card information on file)

If you don't want to assume the responsibility for holding and processing this kind of data, a good way to go is with an external payment service - let them do the processing and just assert to you that the payment has been processed. You'd have to pay them for their services, but you'd also have to pay for implementing your own solution and for taking the risk.

starlocke
  • 3,407
  • 2
  • 25
  • 38
Olaf Kock
  • 46,930
  • 8
  • 59
  • 90
  • 1
    You and Shannon both mentioned external services, such as authorize.net. If it's illegal to store the 3 digit number then how do those services implement recurring billing? Do they have some sort of deal with the credit card companies? –  Jun 15 '12 at 18:06
  • Sorry, can't help you there. I only know *that* credit card companies forbid to keep the 3 digits. They might offer "recurring payments" as one kind of payment in their API, but this is just a wild guess. – Olaf Kock Jun 16 '12 at 22:18
  • 1
    Exactly. "recurring payments" is an option that can be setup at the time a transaction is created. – starlocke Oct 15 '13 at 19:26
4

If you use the password as the salt for the CC encryption, it would be a very effective way of securing the information, however, they would never be able to change their password... If it is changed, then the encrypted data is lost. The bottom line for securing the encryption key is to make it as difficult as possible to find... essentially the more steps you use to hide the key, the harder it is for them to find it... which means it is harder for you to use and program for it. There is no magic bullet at this time to protect everything. (Invent a secure way to keep the key and you will be rich)

As for the CVV number, it cannot be stored as previously mentioned. With each transaction the cc processing company will give the merchant a Reference Number which is then used in each reoccurring payment. This means if the original transaction required the CVV number, then logic will dictate that the recurring payment will also be authorized by the same user who put it in on the first transaction. Therefore, the reoccurring payments will not need the CVV to maintain the same level of security.

Jon Fidler
  • 41
  • 2
1

You could essentially use multiple servers. Encrypt the cc with a key, but keep that key on a separate encryption server, the is only accessible by a master username and password for windows or whatever OS you're using. This way you're securing your key, setting up a services on the encyrption service to run the card through the encryption and then submit it to the database.

Aaron
  • 21
  • 2
1

Use php's private/public openssl functions when a user makes a purchase you use the data in memory to make the purchase then you store the information using a public key to encrypt it.

To process billing monthly you decrypt the data using the private key that could be manually punched in or stored in code. If you want to store the ssl key in code and not have to remember it or get it everytime. I would encrypt the key using a salt stored in the configuration variables + buy a yubi key and generate a 32 character password + my own password on top of it. Store the yubikey in a safe place (A safe lol). When you need to process credit cards do it with a script that runs in the background and runs all billing at once. To change the password would require you decrypt all cards and re-encrypt them using the new private/public key, or you may just decrypt and re-encrypt the private key ssl.

Magic :)

ldrrp
  • 666
  • 1
  • 7
  • 24
0

You require the card information to be reversibly encrypted. The decryption information has to come from somewhere. You've said the data cannot come from the user, and you don't want it stored at the server, so it must be on separate equipment that is presumably more secure. And if you have the ability to recall that information, so does an attacker who has compromised your system. So presumably the decryption information is not retrieved at the vulnerable host during decryption.

Perhaps consider a third-party service that you can encrypt and send information to, perhaps one that specializes in PCI compliance. It might be able to decrypt the credit card information when you send it a second time and apply a charge, or it might actually store the card information for later use. It might even perform recurring transactions for you.

http://www.authorize.net/solutions/merchantsolutions/merchantservices/automatedrecurringbilling/

I just Googled that, I don't recommend them. But it's an example.

shannon
  • 8,664
  • 5
  • 44
  • 74
  • @OP: Fraud prevention systems require the verification code to ensure the card is held when the transaction is arranged, but offer merchants the ability to identify a transaction as "recurring", and the verified status persists through the recurring transactions. The card processing agency still preserves the card number, but not the CVV2, for the recurring transaction. Google credit recurring transaction best practices if you want to know more, but generally I think you will be having someone else do this lifting for you. – shannon Jun 16 '12 at 09:13
-1

Encrypt the CC information twice. First, encrypt the credit card data based off the user's password (+ salt). Then encrypt the output of that with the server's key.

To access the information, you thus require the user's password (i.e. decrypt using server's key, then decrypt based off password). If the database and server key are compromised, the information still isn't exposed without attacking the user's password first.

It's important that the user's password is for the internal encryption - this allows you to re-encrypt when you change server encryption keys.

When the user changes their password, you also re-encrypt the data. If the user resets their password, then the CC information should be erased (and is lost anyway, as it can't be unencrypted).

MotiNK
  • 421
  • 2
  • 12