views:

2969

answers:

10

I have a business requirement that forces me to store a customer's full credit card details (number, name, expiry date, CVV2) for a short period of time.

Rationale: If a customer calls to order a product and their credit card is declined on the spot you are likely to lose the sale. If you take their details, thank them for the transaction and then find that the card is declined, you can phone them back and they are more likely to find another way of paying for the product. If the credit card is accepted you clear the details from the order.

I cannot change this. The existing system stores the credit card details in clear text, and in the new system I am building to replace this I am clearly not going to replicate this!

My question, then, is how I can securely store a credit card for a short period of time. I obviously want some kind of encryption, but what's the best way to do this?

Environment: C#, WinForms, SQL-Server.

+20  A: 

Basically avoid by all means taking the responsiblity to save the CC details on your side, however I can assume you are using a thirdparty service to do your transaction such as PayPal/Verisign or whatever, most of them have API's that enables you to save CC credentials at their side, and they give you back a key that you can then use later to complete or initiate transactions, so they take care of the hard part, while all what you have to do is store this string key in your DB.

bashmohandes
This is correct. The term he is looking for with the card processor is Authorizing, this confirms the funds but does not capture them.
MrChrister
+35  A: 

FYI - it is illegal to store CVV2 numbers for any amount of time and you can be heavily fined for doing so.

Pyroglass
Which section of US law?
Paul Nathan
@Vlion: It's not due to legislation, it's due to the merchant agreement forbidding it. Also note that the merchant agreement forbids storing the CVV2 (or CVC) number even in encrypted form.
Michael Burr
It's not illegal, but it does violate the terms of the credit card processors.
Cade Roux
https://www.pcisecuritystandards.org/pdfs/pcissc_overview.pdf page 2
MrChrister
Apart from it being potentially illegal ans definitely against the rules of card processors, you open yourself up to huge risks if your database is compromised. If it can be proven you are at fault, you may well be sued for any lost monies.
BlackWasp
So that's why Amazon doesn't ask for your CVV!
Henri Watson
+4  A: 

Agreed that you should avoid storing the data if you can. But maybe you are that third party? If so, get familiar with PCI standards. Look around a bit on the site and you'll find the security measures you are required to implement.

Corbin March
+8  A: 

If you are going to store credit card information you really need to be PCI compliant or you're just asking for trouble.

Having said that look at the cell level encryption available in SQL Server 2005 and above. Coincidentally :) I have recently given a presentation with T-SQL samples on encryption with SQL Server 2005/2008 available here: http://moss.bennettadelson.com/Lists/Events/Attachments/9/June2008.zip (Link location updated December 23, 2008)

Joe Kuemerle
You definelty need to be PCI compliant and your probally better off relying upon a third party to process the credit cards.
JoshBerke
+10  A: 

I don't believe it's actually illegal to store CVV info (in the sense that it's against any law), but it does violate Payment Card Industry rules, and they could impose any number of different sanctions. So, your requirements could actually result in you not being able to accept credit cards ;-(

Cade Roux
+7  A: 

Andrew, you need to understand the PCI-DSS, no small task. Personally, I find it extremely vague but here is what I understand.

First off, from the scenario you describe I would attempt to authorize the card for the full amount and then if that failed I would store the customer's information (but not the cardholder data) so someone could contact the user. Where I use to work some of our customers would only charge $1.00 and then void the transaction immediately, just to make sure the card was valid. They would then process all orders manually.

Where you will need to store the number is on a successful authorization. The only number you need then is the credit card number and the transaction code (at least with every gateway I have ever worked with).

The standard, last time I looked at it, is not specific on encryption algorithms but instead makes it clear it should be currently unbreakable encryption.

Now, one thing you cannot do is store the CCV subsequent to authorization. My understanding is that you can store it prior to authorization but I could never get anyone that would put that in writing. Basically, you authorize the card, you better wipe it.

And it is not illegal at this point but if you get nailed they will bring the hammer down on you. They have within their authority to level heavy fines against you, but it seems like what they usually do is put you in remediation. If you don't comply I don't know what happens because everyone I have heard this happening to complied. But then they really go up your booty with a microscope.

Ultimately, I believe their only stick they really have is to prevent you from accepting credit cards. Most merchants I have worked with were scared to death of exactly that.

Flory
"Most merchants I have worked with were scared to death of exactly that". There are few things scarier to a business than, "we're taking away your ability to get money".
Michael Burr
It's also against the scheme rules to charge $1.00 just to see if the card is valid. You are only allowed to charge if you're providing a service or good.
WW
In addition to revoking your acceptance, the main card schemes can levy some pretty large fines, which tend to put the icing on the cake for a lot of merchants.
Rob
+5  A: 

If you just want to store the string for a short period of time in memory, you can take a look at System.Security.SecureString.

Taken from this answer:

SecureString values are stored encrypted (obfuscated, rather), but most importantly, they are never swapped to disk and can be disposed of immediately when you're done with them.

They're tricky to use because you can only build them one character at a time (to encourage you to build them by capturing keystrokes as the user types their password), and require three lines of code to recover and then wipe their plain text, but when used properly they can make a program more secure by avoiding the virtual-memory vulnerability.

At the end of the example the SecureString is converted into a regular managed string, which makes it vulnerable again (be sure to use the try-catch-finally pattern to Zero the string after you're done with it). SecureString's use is in reducing the surface-area of attack by limiting the number of copies the Garbage Collector will make of the value, and reducing the likelihood of being written to the swap file.

// Make a SecureString
SecureString sPassphrase = new SecureString();
Console.WriteLine("Please enter your passphrase");
ConsoleKeyInfo input = Console.ReadKey(true);
while (input.Key != ConsoleKey.Enter)
{
   sPassphrase.AppendChar(input.KeyChar);
   Console.Write('*');
   input = Console.ReadKey(true);
}
sPassphrase.MakeReadOnly();

// Recover plaintext from a SecureString
// Marshal is in the System.Runtime.InteropServices namespace
try {
   IntPtr ptrPassphrase = Marshal.SecureStringToBSTR(sPassphrase);
   string uPassphrase = Marshal.PtrToStringUni(ptrPassphrase);
   // ... use the string ...
}
catch {
   // error handling
} 
finally {
   Marshal.ZeroFreeBSTR(ptrPassphrase);
}
sallen
so a securestring has no place in a web environment then?
Simon_Weaver
+4  A: 

It costs somewhere in the neighborhood of $30,000 to become properly compliant and to be able to do that kind of stuff. You are better off using a 3rd party payment service. Personally, I recommend Element Express, and they have a "Hosted" solution that bypasses the PCI-DSS PAPDB compliance. I've had to convert to this for my own applications, even a Point of Sale machine!!! It's a big pain, but we're a small company.

http://www.elementps.com/software-providers/our-security-edge/hosted-payments/PA-DSS-Certification-vs-Elements-Hosted-Payments/

The above link has some good information about the costs associated with becoming compliant. We have had customers ask us to store credit card numbers, and we won't do it because we could be fined as well. Not good. Don't open yourself up to liability.

Edit:

Additionally, if you DO decide to store the credit card information you definitely need to consider the forms of encryption you are going to use. Symmetric ? Asymmetric ?

If you do Symmetric encryption (Passkey) then you open yourself up to some serious security vulnerabilities if the server(site) that has the key (needed to encrypt) is compromised in any way. Remember, even compiled code won't hide a text key.

If you use Asymmetric encryption (public/private keypairs) then you run into some additional issues, but if the primary public facing server is compromised they will only have the public key, and if they also access your database.. they won't be able to decrpyt the contents.

The question then is, where do you store the private key ? Do you have someone paste it in from their local computers when running admin functions.. have a separate application that runs on the desktop to view orders, etc.

There are a lot of things to take into consideration.

Final note: Use a payment gateway (Element Express, Authorize.NET, Paypal, etc.) and don't store any credit card info locally. :P

Here is a link about using X509 Asymmetric Encryption in C#: http://www.csharpbydesign.com/2008/04/asymmetric-key-encryption-with.html

  • Matthew
Matthew M.
A: 

I have a blog post that deals with this exact situation of storing sensitive data in the database. The blog post uses a String Encryptor class that I built using a Triple DES algorithm but you can plug in your own if you would like.

The blog post contains the video and source code that was used. You can check it out at http://www.wrightin.gs/2008/11/how-to-encryptdecrypt-sensitive-column-contents-in-nhibernateactive-record-video.html. I think it will definitely solve your issue.

Jamie Wright
+2  A: 

Lets look at the requirement a little differently. Currently it looks like this:

As a product owner for website X i want the system to temporarily store a customers cc details so that i can recover a sale that was declined by the CC company

Ppl tend to think like that and request features in that manner. Now i think your requirement is more conveniently described as follows:

As a user i want website X to be able to retry payment for my purchase so i dont have the hassle of having to go thru the checkout process again coz that is a real pain in the...

So there's no explicit requirement for storing anything (on your side) is there? Its only implied

Payment providers can provide programmatic APIs to your merchant account and the ability to attempt a re-auth on a declined attempt. i think @bashmohandes eluded to this earlier

Not all payment providers can do this however i think its dependent on their relationships with the banks involved. Thats the stuff you want to avoid ie. having a close relationship with banks.

Scenario 1: Assuming all i said is true

You don't have to store anything but a reference to the authorization attempt. Some payment providers even give you a sweet backoffice tool so you dont have to make your own to do re-auths. I think paygate does this

Your best bet i believe is to interview a number of payment providers. they should know this stuff like the back of their hands. This is potentially a zero-code solution

Scenario 2: Assuming i'm like totally wrong but legally this storing CC stuff is ok

So you have to store that data somewhere temporarily. I advise:

  • use a 2-way encryption method (naturally) that is non-vendor specific so you can use any language/platform to encrypt/decrypt
  • decouple the encrypt/decrypt service from your app and treat it like a black box
  • use public/private keys for authentication to this service
  • put this machine on a private network with its own elevated firewall rules (doesn't have to be a hardware firewall but hardware is better)
  • have your app servers communicate with this machine via ssl (you could get away with a self-signed cert since its on your private LAN)

All i've suggested in scenario 2 is hurdles but eventually persistence wins the race to get to your data. The only way to absolutely secure data is to unplug your server from the ether but that option is a little radical :-)

Scenario 1 would be nice. Wouldn't it?

phpslacker