I has been getting request to build web pages and applications that would receive credit card for years.
And I always rejected that as I didn’t want to get responsibility of getting those data leaked.
But recently I got to situation that I couldn’t refuse it anymore.
So I was looking how to do it safe and I got an idea – to use SSL mechanism and keep data stored at the server in encrypted form.
1) you will generate private key – doesn’t need to be signed and it’s for free.
There are many manuals but you can use this:
openssl genrsa -des3 -out webpage.key 2048
Put in some pass phrase.
And then:
openssl req -new -key webpage.key -out webpage.crt
You don’t need to enter any info, just press enter.
And last step:
openssl x509 -req -days 36500 -in webpage.csr -signkey webpage.key -out webpage.crt
Result are files webpage.crt, webpage.csr, webpage.key.
Make sure that at the production server where you have the webpages is located only webpage.crt!!
2) create page for user to enter the data. The page should be accessible only over HTTPS (I like RapidSSL).
3) Don’t save data from the credit card to DB, but call my function creditCardEncrypt:
function XXXCreditCard($creditCard) { $creditCard=str_replace(' ','',$creditCard); $l=strlen($creditCard); $res=""; for ($i=0; $i<$l-4; $i++) { $res.="X"; if ($i % 4 == 3) $res.=" "; } return $res.substr($creditCard, $l-4); }
function creditCardEncrypt($creditType, $creditCard,$cardHolder,$expiration,$cvv) { $text="Credit Type: ".$creditType."\n". "Credit Card: ".$creditCard."\n". "Card Holder: ".$cardHolder."\n". "Expiration: ".$expiration."\n". "CVV: ".$cvv; $path="webpage.crt"; $fp=fopen($path,"r"); $pub_key=fread($fp,8192); fclose($fp); openssl_get_publickey($pub_key); openssl_public_encrypt($text, $crypttext, $pub_key); $res = new stdClass(); $res->creditCard=XXXCreditCard($creditCard); $res->rawData=$crypttext; $res->base64=chunk_split(base64_encode($crypttext)); return $res; }
Result of this function is an object, with variables:
creditCard – credit card number where all except last 4 digits are replaced with X
rawData – raw encrypted data
base64 – encrypted data in base 64 format. Such data can be even send over an email.
EXAMPLE:
$res=creditCardEncrypt('VISA', '1233 1233 3434 1231','Pavel Jiri Strnad', '12/23', '123');
NOTE: in my code is webpage.crt is expected to be at same folder. Place it anywhere you like and change the path.
4) Now you can store to the db values. You can even send the Credit Card data in base64 over email. It looks like this:
GFbvdKbtiOifwyvcAXwcP+l3EcLyWyqeVHPsqwhevLzuV0H+2lQkW2Rl/EXH8HBrRQFizVXC9J+w c6XifqNVx17d0GNRnCk6IzKNAljToTEDx87GpG+noxWbioC1VTmIDqS3FEh/noXwgqMpiUuBtwlX 3RI622Z4B340gcda4YTMqhH1eZ8vdoRZ0Gj79QhA+7JC8uLJoSgzKeRLqA1eLOQzWqDkKF8zxyzk 5DvjvTuABxj4OpuIcjMbO4TOwvQ62PFkhhAFlaiszlPXX4VGU5vzobVeYUygYffYJIV4a2sfZeHH qv9YmLrvyg69Iy07ncJTRqTRB16v3gdg/hwVeg==
5) Now the decoding. It’s not secured to have decoding at the production server. For decoding you need SSL Key and even it’s secured with the password attacker can use brute force and capture the pass phrase once you will type it.
The decoding must be done at some private server of the customer. If he don’t have any, you just need for him a PHP to run decode.
This function creditCardDecrypt will decode the base64 data:
function creditCardDecrypt($base64, $passphrase) { $text = base64_decode($base64); $path="webpage.key"; $fpp1=fopen($path,"r"); $priv_key=fread($fpp1,8192); fclose($fpp1); $res1= openssl_get_privatekey($priv_key,$passphrase); openssl_private_decrypt($text, $res, $res1); return $res; }
and the result looks like this:
Credit Type: VISA Credit Card: 1233 1233 3434 1231 Card Holder: Pavel Jiri Strnad Expiration: 12/23 CVV: 123
You can create just simple page where use will put the base64 text from an email and you will decode him the credit card data.
This whole concept is for small businesses where they will proceed the credit card manually.
Good on this solutions is that no attacker can steal your credit card backward or via SQL injection.
Weak point of this whole solution is that that user still enter credit card data to your web pages. If the attacker will take control over your server he can’t steal all the credit card data backward, but he can steal any new credit card data entered. So make sure you run security checks on your server and for example run every hour sha1 sum check on the pages to collect and save the credit card data – if they will be changed, I suggest to delete them and notify your self that server was compromised.
Enjoy,
p/j
Leave a Reply