

Ask HN: Storing Credit Card Numbers - cryptnoob

I would prefer to constrain the discussion to methods of safely storing credit card numbers on a webserver, and stay away from the whole "don't do it" boilerplate.<p>Given that, how would you do it?<p>It seems to me, that any crypto magic you may perform on your data, before storing it into your database, is coded right there for any attacker with access to your source files.  If they have access to your database, I assume they also can access your source files.<p>So, does everybody ignore that fact?  Or do they use compiled code that they were careful to remove the source after they compiled it?<p>I'm envisioning a c program that uses variables like private ip address, ip address, etc, as encryption keys, or just as gates to keep the program from working.  Compile it, remove the source code, and bask in the knowledge that even if your harddrive is cloned, it still won't work when they run it on their system.<p>Is there a better way?
======
peterhi
The first issue is why do you want to store them, just for the record or do
you need to do something with them. Do you need to store that actual number or
would a hash of the number be acceptable (for comparison purposes).

Databases are commonly compromised by SQL injection attacks that reveal the
contents of the database. Some databases, MySQL for example, have functions
that allow the database to display the contents of files off the filesystem.
But on the whole, if someone has gained access to your database it does not
immediately follow that they have access to your code. Only that you need to
tighten up on security.

An alternative to hashes, but somewhat more expensive computationally, would
be to encrypt the CC number into the database using the public key of a
Public/Private encryption scheme (PGP for example). So even if they got hold
of your database and the public key they could still not, realistically,
decode the CC number. Providing the private key is held securely on another
server!

It all comes down to what you need to do with the CC numbers. Long ago I
worked on some software to track CC fraud for a major store (was a CC number
used in store A also being used in store B, it was likely that the card had
been cloned as most customers only shopped at their local branch), we used
hashes of the numbers. We didn't even need to know who the customer was,
everything was driven by electronic till receipts and hashed CC number.

Do you need the actual CC numbers or would a hash be equally as usable?

~~~
cryptnoob
I need the CC numbers to do monthly billing.

------
beagle3
Quite a few people suggested gpg/hash or public key. If you do that (I
wouldn't), be sure to include fluff before and after the number inside your
signed message; A credit card has ~30 bit of randomness, and if you know the
hashed/encrypted (even if salted) version of the hash, a hacker can just
enumerate the credit card number to see if it comes out the same.

It's not just the credit card numbers that are valuable -- it's the
combination of credit card number + billing address that are generally
required to make a purchase. 30 bit enumeration can require just a few minutes
(or even seconds) on modern CPUs and GPUs. So, if you do store them this way,
fluff them front and back with random data that you ignore when decoding.

What would I do? Make sure the user has a password (Use HMAC/bcrypt to verify
password; DO NOT STORE PASSWORD!); When the user logs in, derive key from
password using a different HMAC with different salt, and store in
memory/session vars only for as long as needed. Use _that_ key to encrypt the
credit card number with a symmetric cipher, e.g. AES; make sure to purge these
keys from memory/session directory early and often.

Advantage: You don't have access to the credit card on record even if you (or
a rogue employee) wants to. Active participation from user _required_ to get
access to data. If your server is hacked, only credit cards used while a
hacker has complete view of traffic are compromised, and not all data stored.

Even better: offload to payment processor and make it their problem.

Really.

~~~
cryptnoob
I am writing code to use authorize.net's CIM.

Here's the problem.

I don't like taking more information than is needed from people. I don't
intend to take CVN numbers, and I don't intend to take Street addresses. You
don't need them. All you need is a zip code for verification. I know people
that run telephone chat lines. They only take zip codes, because people are
typing everything into their telephones. No letters allowed.

Also, you'll note that 37 signals only takes a zip code. No CVN, no street
address.

So, I log into my Authorize.net account, go to the virtual terminal, enter a
transaction with only zip code verification. It works. No problem.

I go to their CIM panel, try to enter the same information. They tell me I
need street address. Authorize.net tech support is extremely unhelpful,
telling me to talk to Visa, ignoring that they allowed the exact same
transaction through another area of their site.

So, I'm paying $25 a month for CIM, for the privelege of being forced to make
my users life unnecessarily complicated. I have a problem with that.

If I can safely store those numbers without CIM, I intend to do so.

~~~
beagle3
Well then, the method I described earlier would work for you; Exposure is
limited to clients actually giving their passwords and/or using the credit
cards _while the system is compromised_ ; It mitigates the risk that you keep
hearing about in breaches, of _all_ accounts being exposed.

And just remember, that by storing those numbers locally, you're also taking
potential liability for things that go wrong. To assess how much that is in
cash, call a few insurance companies and ask them to give you a quote. Assume
they have 25% markup on the real cost; That's how much you are "paying",
although you are not doing it out-of-pocket (Though, in a catastrophic event,
you _will_ be paying a lot)

------
icey
You should be using a separate database server than your web server if you're
going to be storing credit card numbers. The database server should not be
accessible by any machine except a small whitelist of IPs that you've
specified. That way when your webserver gets compromised, it will require some
looking around to realize the database containing credit card numbers isn't
there.

Most server compromises that I've seen have stayed local to the server - I'm
not a security pro; but generally I've seen the server that got knocked over
get messed around with, anything on that server was fair game.

Beyond that, I'm sure there are other things you should do to protect the
database that contains the credit card numbers; but seriously - keep them off
your web server.

~~~
cryptnoob
That's actually a direction I was thinking about myself. Make myself a restful
decryption webservice, Communicating by backchannel private ip to the
webserver. When I need a number for monthly billing, submit it to the web
service.

I also had the idea of some dummy security trigger database entries, so if
somebody actually camps out on my server, using my own webservice to decrypt
the database, eventually they hit one of my trigger entries, and my webserver
reboots and my cell phone starts ringing.

~~~
beagle3
If it's monthly billing, why not keep that computer off (plugged out if you're
worried about wake-on-LAN attacks), and manually turn it on once a week/month
for 10 minutes to process everything?

------
mrduncan
I'd recommend starting with the PCI DSS. That standard is required by pretty
much all card companies, and compliance is enforced by a self-assessment
checklist and/or security assessor. If you plan on storing card information,
you must be in compliance with this standard.

PCI DSS Standard:
[https://www.pcisecuritystandards.org/security_standards/pci_...](https://www.pcisecuritystandards.org/security_standards/pci_dss.shtml)

More info on Wikipedia:
[http://en.wikipedia.org/wiki/Payment_Card_Industry_Data_Secu...](http://en.wikipedia.org/wiki/Payment_Card_Industry_Data_Security_Standard)

------
olalonde
You should look up what is recommended by the PCI DSS
([http://en.wikipedia.org/wiki/Payment_Card_Industry_Data_Secu...](http://en.wikipedia.org/wiki/Payment_Card_Industry_Data_Security_Standard)
/ <https://www.pcisecuritystandards.org/>).

------
bensummers
Let your payment gateway handle it. Just store the reference number they give
you in your database, and look it up in their web interface later if you need
it.

Don't let the number even touch the disk!

------
hannibalhorn
If you're going to store that info, use gpg (or perhaps gpgme) to encrypt it
and keep the private key for decryption somewhere completely separate. Access
to the source code shouldn't matter at all.

