Using PHP to Encrypt Credit Card Data for Storage in a Database
by Andrew Kandels
One of the issues with working in the software-as-a-service industry is that credit card numbers often have to be stored locally in a database. Keeping it on file with your payment gateway alone has a few limitations. The business folks may request storage for various reasons such as:
- Recurring subscriptions (often with variable amounts).
- Customers wanting to keep their card on file for future purchases.
- Transactional based software providers (such as cloud providers).
- Customer service wanting to verify the card on file with a customer.
- Managers wanting to authorize certain charges for employees.
When storing information as confidential as credit card data, even though its behind multiple passwords and buried in a database, it should be encrypted. PHPs mcrypt library is ideal for this, using a cipher like MCRYPT_RIJNDAEL_256 (AES 128-bit) to encode 32 bytes of data (ideal for a card number and expiration). If youre anything like me, developing a home grown solution means:
- Researching the various encryption ciphers.
- Looking into legal requirements.
- Re-reading PHP's
- Write a class or extend one with methods to provide encryption and decryption, generating IVs and such.
- Working with your project's ORM or database libraries to implement the new class or methods for encryption.
- Build a testing strategy to ensure everything works and continues to work with future development.
Id prefer not to do this with every implementation, so I decided to write a class called CreditCardFreezer. CreditCardFreezer is a PHP class which automates the storage and retrieval of encrypted credit card information to and from a database.
Although there are plenty of classes and packages (such as those in the Zend framework) for validating credit card numbers or interfacing with payment gateways, I was hard pressed to find anything that deals with encryption and storage of the secure data. With CreditCardFreezer, its as simple as:
$obj = new CreditCardFreezer; $obj->number = '1234-1234-1234-1234'; $encrypted = $obj->setPassKey('super secret') ->get('number', true); // 'ViSxj3...' // Store $encrypted into your database $obj = new CreditCardFreezer; $number = $obj->set('number', $encrypted, true) ->get('number'); echo $number; // 1234123412341234
CreditCardFreezer implements both a fluent interface for method chaining as well as an object-based one (shown above) which should be familiar for those who use an ORM like Doctrine. A complete documentation on the usage and syntax can be found here.
Some of the features it currently includes are:
- AES 128-bit encryption through PHP's MCRYPT_RIJNDAEL_256 cipher.
- CFB mode for random IV generation upon every encryption to prevent patterns in the output.
- Numerous methods for storing and accessing various attributes used with credit card transactions, including secure attributes like card numbers and unsecured attributes like names and addresses.
- PDO class which can be used to implement ORM-like functionality to directly store and retrieve data from a database connection (and even create the schema).
- PHPUnit tested to ensure it works now and after future development.
Your feedback and any ideas or contributions are always welcome, email me at me [at] andrewkandels.com.