title: Storing Credit Card Numbers in SESSION - ways around it?
body: <p>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. </p>
  
  <p>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.</p>
  
  <p>My site is built in this way: </p>
  
  <ol>
  <li>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.</li>
  <li>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,</li>
  <li>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.</li>
  <li>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).</li>
  </ol>
  
  <p>Any suggestions?</p>
  
  <h2>EDIT</h2>
  
  <p>I have received a lot of really good response on this question - majority seem to agree on the following: </p>
  
  <ol>
  <li>taking POST variables after
  validation is run</li>
  <li>encrypting ccnum and cvv (not sure
  you are allowed to store cvv in DB
  at all though)</li>
  <li>Storing in temporary DB</li>
  <li>Access DB immediately after 'review'
  page is OK'd</li>
  <li>decrypt details from DB</li>
  <li>send information to processor</li>
  <li>receive response</li>
  <li>terminate DB</li>
  </ol>
  
  <p>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?</p>
  
  <p>I am programming in PHP and MySQL DB</p>
  
  <h2>EDIT #2</h2>
  
  <p>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.
  <a href="http://www.packetgeneral.com/pcigeneralformysql.html" rel="noreferrer">http://www.packetgeneral.com/pcigeneralformysql.html</a> <br /><br /></p>
  
  <h2>EDIT #3 - Sample Code</h2>
  
  <p>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.</p>
  
  <h2>Form Input</h2>
  
  <pre><code>&lt;form action="&lt;?php $_SERVER['PHP_SELF']; ?&gt;" method="POST"&gt;
  &lt;input type="text" name="CC" /&gt;
  &lt;input type="text" name="CVV" /&gt;
  &lt;input type="text" name="CardType" /&gt;
  &lt;input type="text" name="NameOnCard" /&gt;
  &lt;input type="submit" name="submit" value="submit" /&gt;
  &lt;/form&gt;
  </code></pre>
  
  <h2>PHP Encrypt and Storing Data</h2>
  
  <pre><code>&lt;?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");
  
  ?&gt;
  </code></pre>
  
  <h2>PHP decrypting data and sending off to gateway</h2>
  
  <pre><code>    $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);
  ?&gt;
  </code></pre>
  
  <p>then proceed to take the data just sent in the string and use in Gateway submission. Seem right?</p>