I have a customer with an Access database (ugh!) in which credit cards are stored in plaintext (yikes!), so amongst other changes I'm doing in the app, I'm applying some encryption in there.

I've used Rijndael as the algorithm of choice, but I'm struggling to find the correct approach to storing the encryption/decryption key, since an access database is inherently source-visible. How can I provide decent security on this one to prevent someone grabbing the database (by local access - this machine is NOT Internet connected) ? I feel I'm most of the way there, but missing this vital piece of the jigsaw

[NOTE: Originally posted on crypto.stackexchange.com but they suggested its better suited here]

[UPDATE] For clarification, this is a purely Access system, no web front end. I've split the database into front-end and back-end components, both in Access. The machine(s) that it will be on are right in the shop front - it's the system they use to take customer bookings and/or renewals (and it's the latter that is their given reason for storing credit card details).


How can I provide decent security on this one to prevent someone grabbing the database (by local access - this machine is NOT Internet connected) ?

There is a lot you can do, but most of it is not directly database programming. Because most of this is not programming, it might be out of scope for you. I don't know what you were hired to do or what your background is. If this is out of scope or you don't feel comforatble implementing it, then let your client know your security concerns and recommend they hire a specalist.

  • Hash the credit card numbers.

This depends on the purpose of the stored credit card numbers. If the number are only used to uniqely identify a customer or purchase then you don't actually need the credit card number, just a value that maps unqiuely to the credit card number. If this is the case then replaces the credit card number with a hash of the credit card number. Some hash algorithms: SHA1, MD5, RIPEMD-128/256.

  • Delete the credit card number.

If at some point the credit card number is no longer needed, but the rest of the data in the row is, clear the credit card field. If you need to retain some indication of the card, but not for charging, then keep the last four digits.

  • Break the database into pieces.

If you do not need to access the whole thing at the same time, break the database into pieces you need to access at the same time. If the entries are independent then break it into equal sized pieces. This will limit the damage if one piece gets lost or stolen. Try to load as few pieces at a time as is reasonable. If your application has only a few pieces accessible at a time this will slow down an unauthroized user.

  • Store the keys off the machine.

There are a few ways to do this. One method is using a cryptographic token. There are USB devices, smart card devices, and software tokens. Software tokens can be stored on any removable media (CD-ROM, DVD, USB flah drive, etc). If you do break your database up into pieces, your might consider using different keys for some pieces, especially if some are used less frequently than others.

  • 'Salt' your key

A salt is a random number typically used with hashed password entries to make it difficult for an attacker who accesses a password database to quickly find all the passwords in the database. PBKDF2 is a cryptographic algorithm which uses a salt and a password to generate a key. Generate a salt (random number) for each row and store the salt in plaintext in the row. Use PBKDF2 or another suitable key generation algorithm to generate a key for then row and encrypt the credit card data using the generated key. The purpose is to make the attacker read the database and generate a new key to decrypt each credit card number.

  • Limit network access to the system.

You say the machine is not internet connected but I suspect it is still on an internal network. Use the firewall on the system to restrice network access to two or three other systems. If the system needs to connect to more than two or three other systems then you may need to think about moving the database to a different system or making a dedicated system for the database.

  • Limit user access to the system.

Configure the security policy to allow only a few critical users to logon to the machine. If more than eight people need access to the machine, again that should be a signal that the database should be move to another system or it's own dedicated system. My quick though on eight users: System Administrater, System Administrator alternate, Security Administrator, Security Administrator alternate, Database administrator, Database administrator alternate, Application Developer, Application Developer alternate.

  • Limit physical access to the system.

This is just the good old fashioned locked door. If it need to be in an area shared with other system try to make it systems that allow access to the same users. If all that is available is a closet or cabinet, just make sure that it has a unique key. A lot of office locks and furnite share common keys.

  • Limit what users have physical access to the system.

Just because they need to access the machine don't mean they need physical access to the system. Choose who you give keys to, and instruct them not to make copies or lend it to anyone else.

  • Couple of good points here - physical access is a tough one given the physical location of the machines in a public area, but I'm liking the staff USB key approach. Might research that further. There's only 1 staff member per premise (2 shops in different parts of town), so user access levels is kind of moot – Rob Cowell Aug 7 '11 at 9:05
  • 1
    Does hashing the cc number really protect anything? The keyspace for a cc number is so small that you could easily brute force it, even if it is salted and you get the salt. Other points are good though. – getahobby Aug 7 '11 at 9:57
  • 4
    check the rules as written by the merchant bank. They'll have specific rules about how much credit card number can be stored unencrypted for tracking transactions. And if one needs to store the whole number, how it must be encrypted. – ewanm89 Aug 7 '11 at 12:23
  • 1
    Josh - they're non IT admin staff.The system handles bookings for mailbox rentals, with automatic renewals if they don't explicitly cancel, hence the need to have the CC details to process the renewal transactions. Not sure what else you'd need to know – Rob Cowell Aug 8 '11 at 9:49
  • 2
    (cont) The closest I've found is this and this, which say that 70% of hashed credit card numbers can be recovered in under 2 days. However, if you concatenated the credit card number and the expiration data and hashed that with PBKDF2, that'd be much better. – D.W. Aug 9 '11 at 2:10

To be honest I'd say that if you're running the system as an access database, presumably with the front-end on the same system, there's only a limited amount that you can do to protect the data, as a determined attacker would be able to get access to the encryption key (eg, by reading it from memory when it's used).

That said you may be able to do some things to raise the bar a bit. From what I've seen, one option for storing secrets on a local windows machine is to put them in the registry and ACL protect the registry key. This may provide some protection in the eventuality that someone gets access to the system long enough to grab the .mdb file but not long enough to exhaustively search the machine for the key.

Another valuable protection in this scenario, may be to implement full-disk encryption on the system itself. This would help provide protection in a scenario where the entire device is stolen (presuming it's a desktop machine which would likely be powered off when stolen).

  • 1
    Some good points there - I was thinking rather than the registry with ACL controls, I'd use the DPAPI, but even that's susceptible now (www.dpapick.com) – Rob Cowell Aug 6 '11 at 19:09

Here are some steps you could consider which might help mitigate some risks:

  • Put the database on a separate machine. That separate machine should be locked-down, so that it runs only the services needed to support a database. You can establish a firewall, so it only accepts inbound connections from the front-end web server.

    Another option is to run the front-end webserver in one virtual machine and run the database in a separate virtual machine.

  • Configure the database to lock it down and reduce certain security risks (e.g., configure it so stored procedures and SQL queries cannot spawn shell commands). I don't know the extent to which this is applicable to Access or what configurations are recommended for Access, but this is a good hardening step for some commercial databases.

  • Depending upon your web application's design and needs, it is possible it might only need to write credit card numbers to the database, and not read them. If so, you might be able to configure the database to enforce this restriction, either using fine-grained access controls, or by using coarse-grained access controls plus stored procedures (use table- or user-granularity access control to prevent the web application from directly accessing the credit card numbers, then create a stored procedure which has the ability to write a new credit card number, give the web application permission to invoke the stored procedure, and convert the web application so that every SQL statement which touches credit cards is converted to use this stored procedure). However, this is unlikely to be a trivial change to the web application; this is in the higher-risk, higher-cost category.

  • Review the customer's code to make sure it uses prepared statements (or the equivalent), instead of string concatenation, to build SQL queries. If it uses string concatenation, consider converting it to use prepared statements. String concatenation brings significant risks of SQL injection vulnerabilities and represents a sub-optimal coding practice.

  • As @Rory suggests, you could consider using full-disk encryption for the server that hosts the database. However, this may be of only modest value, because you get back to the conundrum of "where do I store the secret passphrase?". You can have a server operator type in the FDE passphrase on boot-up, but then if there is a power outage or the server otherwise reboots, then your site is down until a server operator personally shows up in person to type in the FDE passphrase.

  • You could look at PCI-DSS compliance as one risk mitigation measure. However, this might be more expensive than the client is prepared for.

Within your restrictions, you're probably not going to be able to completely address the risk of the entire credit card database being stolen. At best you can partially mitigate some of the highest-likelihood risks.

  • 1
    "You could look at PCI-DSS compliance" - yeah, I don't think they're ready for full on compliance, but as an IT professional, I'd be remiss if I returned the database back to them still holding CC numbers in plaintext, hence giving them something a little more robust – Rob Cowell Aug 7 '11 at 9:01
  • 2
    For the usual case, there is a lot of good information here. Unfortunately, most of this information does not apply... No web application, Access database (so no lockdown, finegrained access controls, or really even SP in a noticable fashion)... – AviD Aug 8 '11 at 14:26
  • You can encrypt the Access database, requiring a password to even open it....but the one in question won't encrypt due to some guff about too many Table IDs – Rob Cowell Aug 8 '11 at 16:08
  • >You can establish a firewall, so it only accepts inbound connections from the front-end web server. Will it help an attaker to know to which ip it is connected? I mean that in this case if an attaker has access to the password saver server it could know to which service credentials belong. I suppose that pass saver serve does not have name or url of service, just an id by which a password consumer server communicates. – FreeLightman Apr 3 '18 at 16:06

Don't do that.

Select a payment provider, e.g. Stripe.com or Pay-pal, who will handle the re-billing of subscriptions for you.

pro: You don't have to sweat the details of securing the database or paying someone else to do it.

con: If you already have a merchant account/gateway, you MAY end up paying slightly more. However, chances are good that whatever extra it costs you will be far less than the liability of a data breach, or the security consultant's fee, or even the operating costs of the extra server suggested by D.W.

The fact that your company/client insists on using MS Access for this suggests strongly that they aren't qualified to make IT security decisions. Seriously, just don't do it.

  • roll-your-own crypto is not going to "give them something a little more robust". It's going to give them a false sense of security (warm fuzzy feeling) about a fundamentally insecure system. Rather, you should rename the database "I am a database containing completely insecure payment information. Please hack me.mdb" and make the user type that in every time they want to use it. – Terrel Shumway Aug 21 '13 at 10:38
  • To quote the original question "this machine is NOT Internet connected", so PayPal et al. isn't gonna help here – Rob Cowell Nov 28 '13 at 16:18

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.