在SESSION存储信用卡号码 – 方法?

我非常了解PCI合规性,因此在结帐过程中不需要对公司数据库中的CC号码(尤其是CVV号码)进行存储。

但是,我希望在处理敏感的消费者信息时尽可能地安全,并且好奇如何避免在页面之间传递CC号码,而不是尽可能使用SESSIONvariables。

我的网站是这样build立的:

  1. 步骤1)从客户收集信用卡信息 – 当客户提交时,首先通过JSvalidation运行信息,然后运行PHPvalidation,如果全部通过,则转到步骤2。
  2. 步骤2)信息显示在顾客的评论页面上,以确保他们即将到来的交易的细节被显示。 本页只显示CC的前6位和后4位,但是卡的types和过期date都是完整的。 如果他点击继续,
  3. 步骤3)将信息发送到另一个运行最后一次validation的php页面,通过安全支付网关发送信息,string返回细节。
  4. 步骤4)如果一切顺利,消费者信息(个人,而非CC)被存储在数据库中,并被redirect到完成页面。 如果有什么不好,他会被告知并重新回到CC处理页面再试一次(最多3次)。

有什么build议么?

编辑

在这个问题上,我收到了很多很好的回应 – 大多数人似乎同意以下几点:

  1. 在validation运行后采取POSTvariables
  2. encryptionccnum和cvv(不知道你是否被允许在数据库中存储cvv)
  3. 存储在临时数据库中
  4. 在“审查”页面确定后立即访问数据库
  5. 从数据库中解密详细信息
  6. 发送信息给处理器
  7. 接受回应
  8. 终止数据库

我认为这是有道理的。 有没有人有encryption/解密的良好方法,以及创build临时数据库信息的最佳方式,在稍后调用时会自动删除?

我在PHP和MySQL数据库编程

编辑#2

我遇到了Packet General,它似乎是一个理想的解决scheme,但真的不想为了完成这个目标而支付另一个软件许可证。 http://www.packetgeneral.com/pcigeneralformysql.html

编辑#3 – 示例代码

我现在已经发布了一些示例代码,我试图理解本文提到的encryption/解密/密钥和存储。 希望已经有帮助的贡献者可以validation,其他人也可以使用类似的function。 为了长度的缘故,我不会进入用于实际CC号本身的validation方法。

表单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> 

PHPencryption和存储数据

 <?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解密数据并发送到网关

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

然后继续采取刚刚在string中发送的数据并在网关提交中使用。 好像?

考虑修改您的结帐过程,摆脱存储信用卡信息的必要性。

第1页:用户input非信用卡订单信息,如运费和账单地址
第2页:用户validation非信用卡订单信息,input信用卡信息,并点击“立即付款”(或“修改订单”,如果他们想改变的话)
步骤3:通过$ _POST请求将信息提交给SSL页面,完成服务器端检查,将信用卡数据提交给处理器,并根据响应指示用户成功或错误页面。

这样你就可以避免技术问题和合规问题的阴霾。 即使在encryption的情况下,即使短时间内将信用卡数据存储在数据库或cookie中,也意味着您要对更高水平的PCI合规性负责。 唯一的折衷是你将无法显示信用卡详细信息“审查订单”页面。 考虑到您的“查看订单”页面甚至不能显示完整的信用卡号码,多大的折衷呢?

将卡的详细信息存储到任何持久性介质(数据库,不pipe)中,但使用存储在会话中的唯一随机密钥对卡号进行encryption。 这样,如果会话丢失,关键也是 – 这给你足够的时间来清理过期/废弃的数据。

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

编辑 :最大限度地减less风险的关键是确保尽快摆脱这些信息。 交易完成后,从数据库中删除logging。 您还需要一个滚动工作(比如说每5分钟),删除比会话超时更早的任何logging(通常是20分钟)。 另外,如果您正在使用数据库来处理这个非常临时的数据,请确保它不在自动备份系统上。

再说一次,这个解决scheme不是万无一失的,我甚至不能100%确定它符合CC安全要求。 但是,它应该要求攻击者对您的环境进行总体运行时控制,以主动解密客户的CC信息,并且如果数据库的快照遭到破坏(更可能/常见),则一次只能有一个CC被强行摧毁,这是最好的,你可以希望。

我知道您提到您了解PCI合规性,但是使用已经描述的任何方法(例如,将卡号保持在任何位置)将会对PCI造成不良影响,这意味着在您之前您会遇到令人头痛的恶梦。 如果你真的坚持把卡号保存到光盘上,那么你现在就可以得到一个PCI审计员来帮助你完成整个过程并提供build议。 最终,他们将需要validation你采取的方法是适当的。

举个例子,这里的很多答案都是关于使用encryption的。 这是容易的一点。 他们没有谈论关键pipe理,这是非常 困难的

因此,我认为一个更好的方法是在收集信息后立即将卡的详细信息提交给支付网关。 许多支付网关将允许您执行“仅存储”式交易,该交易将对卡详细信息进行基本validation,并将卡号存储到其(已经是PCI兼容的)服务器,并返回给您一个令牌ID。 此方法意味着您不必将任何位置的完整卡号/ cvv2存储在您的服务器上,并且PCI合规性变得非常容易。

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

PCI允许您以明文forms存储卡号的前六位/后四位(以及有效date),因此您可以安全地捕捉到任何您感到舒适的位置,以便在最后一步之前重新显示。

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

我不明白为什么将它保存在数据库中比保留在会话variables中更安全 – 服务器的妥协方法仍然会放弃信用卡号码,但是如果将它保留在会话中,则不太可能写入磁盘。 如果你愿意,你可以encryption它,但是这个的有用性是可疑的(它仍然会被交换到磁盘)。 添加另一台计算机来执行encryption存储也无济于事,因为受感染的计算机可能只是要求另一台计算机进行解密。

编辑:只是想到这一点:

  1. 生成一个随机的128位密钥。 保存在会话中。
  2. 用密钥encryption数据。 通过<input type =“hidden”>发送给客户端
  3. 确认后,解密数据并提交交易。

攻击者需要妥协客户端和服务器来获取信用卡号码(这样的攻击者可能已经有这个号码了)。 一个在线服务器的妥协仍然会得到未来交易的信用卡号码,但你不能真正阻止。

编辑:我忘了细节。 对于所有这些scheme(不仅仅是我的),你还需要一个MAC来防止重放攻击(或者Eve分散Alice的注意力,修改购物篮和帐单地址,并点击“确认”页面…)。 一般来说,您希望拥有所有交易数据的MAC(CC,CVV,交易ID,交易金额,帐单地址等)。

你是对的,使用会话对于存储敏感数据是非常不安全的,可以通过以下方式进入会话:

会话劫持
会话固定

我想到的最安全的方式是将信息存储在数据库中(暂时),然后在需要的页面上读取该值。 一旦你完成了这一切,你可以删除它。

注意:

  • 您必须在保存到数据库之前对其进行encryption
  • 如果你在共享主机,请小心
  • 确保一旦完成就将其删除

你可能会发现reflection性有用,以及:)

看来,无论如何,你需要提供安全的信用卡号码存储function。 如果服务器遭到入侵,任何时候都将包含足够的信息来解密当前存储的信用卡号码(即密钥和encryption号码)。 潜在的解决scheme是使用一个内部服务器,作为“encryption/解密”服务,没有别的。 这种方式危害一台机器不会暴露信用卡号码。

还有另一种方法,但它需要Ajax。 不存储信用卡号码和评论页面。

第1页:表格捕捉运输,账单和信用卡信息。 确保页面的“正文”(包括表单)位于具有唯一ID的DIV中,以便您可以使用JavaScript进行引用。

第2页:服务器上的一个文件,它将接受带有表单域的GET / POST请求,并返回一个格式正确的“查看”页面。

结帐过程:

  1. validation表单。
  2. 将信用卡相关字段复制到全局JavaScriptvariables中。
  3. 通过表单字段循环,并与表单字段(不包括信用卡相关的字段)build立一个查询/数据string
  4. 对“review”页面执行一个Ajax请求,并将表单字段/值的查询string传递给它。 在服务器上呈现并返callback用Ajax函数。
  5. 从Ajax请求返回呈现的HTML评论页面,并用它replace“DIV”容器中的内容(有效地用评论HTMLreplace表单和其他元素)。
  6. 使用JavaScript将存储在全局JSvariables中的信用卡数据复制到审查页面的相应位置。 当用户从“查看”页面“完成”订单时,您也可以将卡片数据复制到隐藏表单域中。
  7. 用户提交从评论页到服务器的订单,用处理器的网关执行卡validation,然后下订单,或者返回error handling页面,从未存储卡细节。
  8. 我build议“下单”function执行一个完整的HTTP请求(而不是Ajax),以重新加载浏览器页面,该页面不再具有存储在全局JSvariables中的卡数据。

这是一个黑客,但如果正确完成,它是100%无缝的用户,并允许您单一的卡数据传输,而不需要承担临时数据库存储等风险。

这是数据库的用途。 我不确定这里的法律后果(根据国家和地区不同而不同),但一种方法是encryptionCC号码,并在您从用户处收到CC号码后立即将其存储在数据库中。 您可能需要将最后4位数字存储在单独的字段中,以便在需要时可以将其显示给用户。 当您需要与服务器上的卡处理器进行交互时,请从数据库中检索并解密卡号。

以下是我计划如何做 – 当然,通过https使用ssl的一切。

步骤1.用户inputCC信息并按下下一个button。 CC信息会立即保存到CC处理器的数据库,而不是您自己的数据库,否则您会破坏PCI合规性。 CC实际上并没有收取这一步。 但是您应该从处理器接收一些唯一的ID来标识CC信息。 (如果你想要在你的数据库中存储唯一的ID)

步骤2.在确认页面上,使用他们提供的唯一ID从CC处理器中检索CC信息。 无论如何,我的处理器只会让我找回CC的最后4位数字。

第3步。他们确认购买后,按立即购买button,使用唯一的ID收取信用卡。

第4步。redirect到一个包含只有CC最后四位数字的发票/收据的谢谢页面(当然,您不必显示CC的最后4个,但是我认为这是一件好事)。

您可以在会话中存储卡nr的哈希值,并在数据库中存储相同的哈希值以及实际的数字和用户的会话标识。 然后为每个页面你可以检查哈希和会话信息来获得卡号。

在付款处理的稍后阶段(步骤3的最后一部分),您需要encryptionCC#(和CVC)以便能够将其发送到支付处理器(我假设)

为什么不在收到信息时正确执行encryption,在确认页面所需的混淆旁边。 (这是步骤1的最后一部分)

从现在开始,只能使用这个encryption或模糊的数据,使CC公司成为唯一一个真正能够解密全部数据的人。

会议或数据库不需要保存信息。

每个页面都是张贴数据的表单。 在每个后续页面上,来自前一页面的postvariables被添加到隐藏的表单域,以便下一个表单提交再次发布数据。 这样就不会存储任何东西,但是信息是一页一页地传送的。 这也迫使用户完成从开始到结束的过程而不尝试跳过步骤。

只要表单通过HTTPS提交,数据就会自动encryption,并且安全负担在您的SSL证书提供程序上。

许多stream行的商业网站实现这一点 例如OSCommerce。

使用Tokenization。 它完全支持PCI DSS。

更多可以在这里, https: //www.pcisecuritystandards.org/documents/Tokenization_Guidelines_Info_Supplement.pdf