在会话中存储信用卡号码 - 围绕它的方式?

JM4*_*JM4 38 php mysql session credit-card

我非常了解PCI合规性,因此在结账过程中我们不需要在公司数据库中存储CC号码(特别是CVV号码).

但是,我希望在处理敏感的消费者信息时尽可能安全,并且好奇如何在不使用SESSION变量的情况下绕过页面传递CC号码.

我的网站以这种方式构建:

  1. 步骤1)从客户收集信用卡信息 - 当客户点击提交时,信息首先通过JS验证运行,然后通过PHP验证运行,如果所有通过他转到步骤2.
  2. 步骤2)信息显示在客户的评论页面上,以确保显示他们即将进行的交易的详细信息.此页面仅显示CC的前6个和后4个,但卡类型和exp日期完全是shwon.如果他点击继续,
  3. 步骤3)将信息发送到另一个运行最后一次验证的php页面,通过安全支付网关发送信息,并返回带有详细信息的字符串.
  4. 步骤4)如果一切顺利,消费者信息(个人信息,而不是CC)存储在数据库中并重定向到完成页面.如果有什么不好的话,他会被告知并重新访问CC处理页面再试一次(最多3次).

有什么建议?

编辑

我在这个问题上得到了很多非常好的回应 - 大多数人似乎同意以下几点:

  1. 运行验证后获取POST变量
  2. 加密ccnum和cvv(不确定你是否可以将cvv存储在DB中)
  3. 存储在临时DB中
  4. 在"审核"页面之后立即访问数据库是可以的
  5. 从DB解密细节
  6. 向处理器发送信息
  7. 收到回应
  8. 终止DB

我认为这总体上是有道理的.有没有人有好的加密/解密方法以及创建临时数据库信息的最佳方法,这些信息会在以后的呼叫中自动删除?

我在PHP和MySQL DB编程

编辑#2

我遇到了Packet General,这似乎是一个理想的解决方案,但真的不想支付另一个软件许可证来实现这个目标. http://www.packetgeneral.com/pcigeneralformysql.html

编辑#3 - 示例代码

我现在已经发布了一些示例代码,我将这些代码放在一起,试图理解本文中提到的加密/解密/密钥和存储.希望已经有用的贡献者可以验证,其他人可以使用类似的功能.为了长度,我不会讨论用于实际CC num本身的验证方法.

表格输入

<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>
Run Code Online (Sandbox Code Playgroud)

PHP加密和存储数据

<?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");

?>
Run Code Online (Sandbox Code Playgroud)

PHP解密数据并发送到网关

    $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);
?>
Run Code Online (Sandbox Code Playgroud)

然后继续获取刚刚在字符串中发送的数据并在Gateway提交中使用.好像对吗?

Rex*_*x M 13

将卡详细信息存储到任何持久性介质(数据库,无论如何),但使用存储在会话中的唯一随机密钥加密卡号.这样,如果会话丢失,关键也是 - 这为您提供了足够的时间来清除过期/放弃的数据.

还要确保您的会话免受劫持.有硬件解决方案,但简单的代码内方法是将会话ID绑定到IP的第一个八位字节加上用户代理的散列.不是万无一失,但它有帮助.

编辑:最大限度地降低风险的关键是确保尽快摆脱这些信息.事务通过后,立即从数据库中删除记录.您还需要一个滚动作业(比如每5分钟)删除任何早于会话超时的记录(通常为20分钟).此外,如果您使用的是数据库这个非常临时数据,确保它不是一个自动的备份系统上.

同样,这个解决方案并非万无一失,我甚至不能100%确定它符合CC安全要求.但是,它应该要求攻击者对您的环境进行总运行时控制以主动解密客户CC信息,并且如果数据库的快照受到损害(更可能/更常见),一次只能强制使用一个CC,这是你可以期待的最好的.


Pau*_*ulG 9

我知道你提到你已经知道PCI合规性,但是使用已经描述的任何方法(例如将卡号保存在任何地方的光盘上)都会违反PCI,并且意味着你面临着令人头疼的合规问题.如果您真的坚持将卡号保存到光盘,那么您现在也可以聘请PCI审核员来帮助您完成整个过程并提供建议.最终,他们需要验证您采用的方法是否合适.

例如,这里的很多答案都谈到了使用加密.这很容易.他们没有谈到密钥管理,这是非常 困难的

因此,我认为更好的方法是在收集卡片详细信息后立即将其提交给支付网关.许多支付网关将允许您执行"仅限商店"式交易,该交易将执行卡详细信息的基本验证并将卡号存储到其(已经符合PCI的)服务器,并返回令牌ID.这种方法意味着你没有任何地方保存完整卡号/ CVV2您的服务器上,以及PCI合规性成为一个巨大的量更容易.

稍后在结账过程中,您使用令牌ID提交授权和结算.

PCI允许您以明文形式存储卡号的前六位/后四位(和失效日期),这样您就可以安全地捕获那些您感觉舒适的位置,以便在最后一步之前重新显示它们.


Sum*_*mer 9

考虑修改结帐流程以摆脱存储信用卡信息的必要性.

第1页:用户输入非信用卡订单信息,如运输和账单地址.
第2页:用户验证非信用卡订单信息,输入信用卡信息,点击"立即付款"(或"修改订单",如果他们想要改变的事情)
步骤3:通过$ _POST请求将信息提交到SSL页面,完成服务器端检查,向处理器提交信用卡数据,并根据响应将用户引导到成功或错误页面.

这样您就可以避免出现技术问题和合规性问题.将信用卡数据存储在数据库或cookie中,即使在短时间内,即使加密,也意味着您要对更高级别的PCI合规性负责.唯一的权衡是您将无法显示包含信用卡详细信息的"审核订单"页面.鉴于您的"审核订单"页面甚至无法显示完整的信用卡号,那么权衡有多大?


tc.*_*tc. 6

您是否有任何理由不能跳过确认步骤并立即提交交易?

我不明白为什么将它保存在数据库中比将其保存在会话变量中更安全 - 服务器泄密仍然会泄露信用卡号,但是如果你将它保留在会话中,那么它写入会话的可能性要小得多磁盘.你可以根据需要加密它,但是它的用处是可疑的(它仍然会被交换到磁盘).添加另一台机器进行加密存储也无济于事,因为受感染的机器只能要求另一台机器进行解密.

编辑:想到这个:

  1. 生成随机的128位密钥.将其保存在会话中.
  2. 使用密钥加密数据.通过<input type ="hidden"> 将其发送到客户端
  3. 确认后,解密数据并提交交易.

攻击者需要同时破坏客户端和服务器以获取信用卡号(这样的攻击者可能已经拥有该号码).在线服务器泄密仍将获得未来交易的信用卡号,但您无法真正阻止它.

编辑:我忘记了细节.对于所有这些方案(不仅仅是我的),你还需要一个MAC来防止重放攻击(或者Eve分散Alice,修改购物篮和账单地址,然后点击"确认"页面......).通常,您希望拥有所有交易数据的MAC(CC,CVV,交易ID,交易金额,账单地址......).