Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Storing Credit Card Numbers in SESSION - ways around it?

I am well aware of PCI Compliance so don't need an earful about storing CC numbers (and especially CVV nums) within our company database during checkout process.

However, I want to be safe as possible when handling sensitive consumer information and am curious how to get around passing CC numbers from page to page WITHOUT using SESSION variables if at all possible.

My site is built in this way:

  1. Step 1) collect Credit Card information from customer - when customer hits submit, the information is first run through JS validation, then run through PHP validation, if all passes he moves to step 2.
  2. Step 2) Information is displayed on a review page for customer to make sure the details of their upcoming transaction are shown. Only the first 6 and last 4 of the CC are shown on this page but card type, and exp date are shwon fully. If he clicks proceed,
  3. Step 3) The information is sent to another php page which runs one last validation, sends information through secure payment gateway, and string is returned with details.
  4. Step 4) If all is good and well, the consumer information (personal, not CC) is stored in DB and redirected to a completion page. If anything is bad, he is informed and told to revisit the CC processing page to try again (max of 3 times).

Any suggestions?

EDIT

I have received a lot of really good response on this question - majority seem to agree on the following:

  1. taking POST variables after validation is run
  2. encrypting ccnum and cvv (not sure you are allowed to store cvv in DB at all though)
  3. Storing in temporary DB
  4. Access DB immediately after 'review' page is OK'd
  5. decrypt details from DB
  6. send information to processor
  7. receive response
  8. terminate DB

I think this makes sense overall. Does anybody have good method for the encryption/decryption along with best way to create temp DB info that is automatically deleted on later call?

I am programming in PHP and MySQL DB

EDIT #2

I came across Packet General which seems like an ideal solution but REALLY don't want to pay for another software license to accomplish this goal. http://www.packetgeneral.com/pcigeneralformysql.html

EDIT #3 - Sample Code

I have now posted some example code I put together trying to make sense of the encryption/decryption/key and storage mentioned in this post. Hopefully, the already helpful contributors can validate and others are able to use similar functionality. For the sake of length I will not go into the validation methods used for the actual CC num itself.

Form Input

<form action="<?php $_SERVER['PHP_SELF']; ?>" method="POST">
<input type="text" name="CC" />
<input type="text" name="CVV" />
<input type="text" name="CardType" />
<input type="text" name="NameOnCard" />
<input type="submit" name="submit" value="submit" />
</form>

PHP Encrypt and Storing Data

<?php

$ivs = mcrypt_get_iv_size(MCRYPT_DES,MCRYPT_MODE_CBC);
$iv = mcrypt_create_iv($ivs,MCRYPT_RAND);
$key = "1234"; //not sure what best way to generate this is!
$_SESSION['key'] = $key;

$ccnum = $_POST['CC'];
$cvv = $_POST['CVV'];
$cctype = $_POST['CardType'];
$ccname = $_POST['NameOnCard'];

$enc_cc = mcrypt_encrypt(MCRYPT_DES, $key, $ccnum, MCRYPT_MODE_CBC, $iv);
$enc_cvv = mcrypt_encrypt(MCRYPT_DES, $key, $cvv, MCRYPT_MODE_CBC, $iv);
$enc_cctype = mcrypt_encrypt(MCRYPT_DES, $key, $cctype, MCRYPT_MODE_CBC, $iv);
$enc_ccname = mcrypt_encrypt(MCRYPT_DES, $key, $ccname, MCRYPT_MODE_CBC, $iv);


//if we want to change BIN info to HEXIDECIMAL
// bin2hex($enc_cc)

$conn = mysql_connect("localhost", "username", "password");
mysql_select_db("DBName",$conn);

$enc_cc = mysql_real_escape_string($enc_cc);
$enc_cvv = mysql_real_escape_string($enc_cvv);
$enc_cctype = mysql_real_escape_string($enc_cctype); 
$enc_ccname = mysql_real_escape_string($enc_ccname);

$sql = "INSERT INTO tablename VALUES ('$enc_cc', '$enc_cvv', '$enc_cctype', '$enc_ccname');

$result = mysql_query($sql, $conn) or die(mysql_error());
mysql_close($conn);

Header ("Location: review_page.php");

?>

PHP decrypting data and sending off to gateway

    $conn = mysql_connect("localhost", "username", "password");
    mysql_select_db("DBName",$conn);

$result = mysql_query("SELECT * FROM tablename");

echo mcrypt_decrypt (MCRYPT_DES, $_SESSION['key'], $enc_ccnum, MCRYPT_MODE_CBC, $iv);
echo mcrypt_decrypt (MCRYPT_DES, $_SESSION['key'], $enc_cvv, MCRYPT_MODE_CBC, $iv);
echo mcrypt_decrypt (MCRYPT_DES, $_SESSION['key'], $enc_cctype, MCRYPT_MODE_CBC, $iv);
echo mcrypt_decrypt (MCRYPT_DES, $_SESSION['key'], $enc_ccname, MCRYPT_MODE_CBC, $iv);

mysql_close($con);
?>

then proceed to take the data just sent in the string and use in Gateway submission. Seem right?

like image 771
JM4 Avatar asked May 24 '10 20:05

JM4


People also ask

What is the best practice when storing payment card information?

Keep paper documents with credit card numbers locked in a secure place (like a safe) when not in use. Electronic storage of credit card numbers is also common if, for example, you process recurring or repeat transactions. If you do this, you cannot store these files unencrypted.

How do you store credit card numbers?

You should store paper documents with credit card numbers locked in a safe place such as a safe when not in use and restrict access. Electronic storage of credit card numbers is also standard if, for example, you perform recurring or recurring transactions.

How do you store credit card numbers securely in database?

First, storing credit card info should be an option. Secondly, the data should be stored securely, using a strong form of encryption. I recommend AES with 256bit key size.

Is it legal to store credit card information on paper?

To store credit card information on paper, you must cross it out with a dark pen to make the security code unreadable after completing the transaction and before storing a paper authorization form.


2 Answers

Store the card details to any persistence medium (database, whatever), but encrypt the card number with a unique and random key that you store in the session. That way if the session is lost, the key is too - which gives you enough time to clean out expired/abandoned data.

Also make sure your sessions are protected from hijacking. There are hardware solutions to this, but a simple in-code way is to tie the session ID to a hash of the first octet of the IP plus the user agent. Not foolproof but it helps.

Edit: The key bits to minimizing your risk is to make sure you get rid of that info as soon as possible. Right after the transaction goes through, delete the record from the database. You also need a rolling job (say every 5 minutes) that deletes any records older than your session timeout (usually 20 minutes). Also, if you are using a database for this very temporary data, make sure it is not on an automated backup system.

Again, this solution is not foolproof and I am not even 100% sure it is compliant with CC security requirements. However, it should require an attacker have total runtime control of your environment to actively decrypt customer CC info, and if a snapshot of your database is compromised (much more likely/common), only one CC can be brute-forced at a time, which is about the best you can hope for.

like image 176
Rex M Avatar answered Oct 08 '22 18:10

Rex M


Consider modifying your checkout process to get rid of the necessity of storing credit card information.

Page 1: User enters non-credit-card order information, like shipping and billing address
Page 2: User verifies non-credit-card order information, enters credit card information, and clicks "Pay Now" (or "Revise Order" if they want to change things)
Step 3: Info is submitted via a $_POST request to an SSL page, which completes serverside checks, submits credit card data to processor, and directs the user to a success or error page based on the response.

This way you'll avoid a haze of technical problems and compliance problems. Storing credit card data in a database or cookie, even for a short period of time, even if encrypted, WILL mean that you're responsible for a higher level of PCI compliance. The only tradeoff is you won't be able to show a "review order" page with credit card details. And how big a tradeoff is that, given that your "review order" page can't even show the full credit card number?

like image 10
Summer Avatar answered Oct 08 '22 17:10

Summer