私はPCIコンプライアンスをよく知っているので、チェックアウトプロセス中にCC番号(特にCVV番号)を会社のデータベースに保存することについては、耳を傾ける必要はありません。
ただし、消費者の機密情報を処理するときはできるだけ安全にしたいと考えており、可能な限りSESSION変数を使用せずにCC番号をページからページに渡す方法に興味があります。
私のサイトは次のように構築されています。
助言がありますか?
私はこの質問に対して多くの本当に良い回答を受け取りました-大多数は次のことに同意しているようです:
これは全体的に理にかなっていると思います。後で呼び出すときに自動的に削除される一時的なDB情報を作成するための最良の方法とともに、暗号化/復号化のための優れた方法を誰かが持っていますか?
私はPHPとMySQLDBでプログラミングしています
私は理想的な解決策のように思われるPacketGeneralに出くわしましたが、この目標を達成するために別のソフトウェアライセンスにお金を払いたくありません。 http://www.packetgeneral.com/pcigeneralformysql.html
この投稿で言及されている暗号化/復号化/キーとストレージを理解するためにまとめたサンプルコードをいくつか投稿しました。うまくいけば、すでに役立つ貢献者が検証でき、他の人も同様の機能を使用できるようになります。長さのために、実際のCC番号自体に使用される検証方法については説明しません。
<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
$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");
?>
$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);
?>
次に、文字列で送信されたばかりのデータを取得し、ゲートウェイ送信で使用します。そうですか?
クレジットカード情報を保存する必要性をなくすために、チェックアウトプロセスを変更することを検討してください。
ページ1:ユーザーが配送先住所や請求先住所などのクレジットカード以外の注文情報を入力する
ページ2:ユーザーは、クレジットカード以外の注文情報を確認し、クレジットカード情報を入力して、[今すぐ支払う](または変更する場合は[注文を修正])をクリックします。
ステップ3:情報は$ _POSTリクエストを介してSSLページに送信されます。SSLページはサーバー側のチェックを完了し、クレジットカードデータをプロセッサに送信し、応答に基づいてユーザーを成功またはエラーページに誘導します。
このようにして、技術的な問題やコンプライアンスの問題のかすみを回避できます。クレジットカードデータをデータベースまたはCookieに保存することは、たとえ暗号化されていても、短期間であっても、より高いレベルのPCIコンプライアンスに責任があることを意味します。唯一のトレードオフは、クレジットカードの詳細を含む「注文の確認」ページを表示できないことです。また、「注文の確認」ページにクレジットカード番号全体を表示することすらできないことを考えると、トレードオフはどれほど大きいのでしょうか。
カードの詳細を任意の永続メディア(データベースなど)に保存しますが、セッションに保存する一意のおよびランダムキーを使用してカード番号を暗号化します。そうすれば、セッションが失われた場合、キーも重要になります。これにより、期限切れ/放棄されたデータをクリーンアップするのに十分な時間が与えられます。
また、セッションがハイジャックから保護されていることを確認してください。これにはハードウェアソリューションがありますが、コード内の簡単な方法は、セッションIDをIPの最初のオクテットとユーザーエージェントのハッシュに関連付けることです。絶対確実ではありませんが、役に立ちます。
編集:リスクを最小限に抑えるための重要な点は、その情報をできるだけ早く取り除くことです。トランザクションが完了した直後に、データベースからレコードを削除します。また、セッションタイムアウト(通常は20分)より古いレコードを削除するローリングジョブ(たとえば5分ごと)も必要です。また、このvery一時データにデータベースを使用している場合は、自動バックアップシステム上にないことを確認してください。
繰り返しになりますが、このソリューションは絶対確実ではなく、CCセキュリティ要件に準拠しているとは100%確信していません。ただし、攻撃者が顧客のCC情報をアクティブに復号化するには、環境を完全にランタイム制御する必要があります。データベースのスナップショットが危険にさらされた場合(はるかに可能性が高い/一般的)、一度にブルートフォースできるCCは1つだけです。これはあなたが望むことができる最高のものです。
PCIコンプライアンスを認識しているとのことですが、すでに説明した方法のいずれかを使用すると(たとえば、カード番号をどこでもディスクに保持する)、PCIに違反し、コンプライアンスの悪夢が目の前にあることを意味します。カード番号をディスクに保持することを本当に主張している場合は、PCI監査人を雇って、プロセスを支援し、アドバイスを提供することをお勧めします。最終的に、彼らはあなたが取った方法が適切であることを検証する必要があります。
例として、ここでの回答の多くは暗号化の使用について説明しています。それは簡単なことです。彼らはキー管理について話していません 大幅により難しい
したがって、カードの詳細が収集されたらすぐに支払いゲートウェイに送信する方がよいと思います。多くのペイメントゲートウェイでは、「ストアのみ」スタイルのトランザクションを実行できます。これにより、カードの詳細の基本的な検証が実行され、カード番号が(すでにPCI準拠の)サーバーに保存され、代わりにトークンIDが返されます。この方法は、完全なカード番号/ cvv2をサーバーのどこにも保存しないことを意味し、PCIコンプライアンスは巨大な量になりやすくなります。
チェックアウトプロセスの後半で、トークンIDを使用して承認と決済を送信します。
PCIを使用すると、カード番号の最初の6桁/最後の4桁(および有効期限)をプレーンテキストで保存できるため、快適な場所に安全にキャプチャして、最終ステップの直前に再表示できます。
確認手順をスキップしてすぐに取引を送信できない理由はありますか?
データベースに保持する方がセッション変数に保持するよりも安全である理由がわかりません。サーバーの侵害によってクレジットカード番号が提供されますが、セッションに保持すると、次のように書き込まれる可能性がはるかに低くなります。ディスク。必要に応じて暗号化できますが、これの有用性は疑わしいです(ディスクにスワップされます)。暗号化されたストレージを実行するために別のマシンを追加しても、侵害されたマシンは他のマシンに復号化を要求するだけなので、役に立ちません。
編集:これについて考えてみてください:
攻撃者は、クレジットカード番号を取得するために、クライアントとサーバーの両方を危険にさらす必要があります(このような攻撃者は、おそらくすでに番号を持っているでしょう)。オンラインサーバーの侵害は、今後のトランザクションのクレジットカード番号を取得しますが、それを止めることはできません。
編集:そして私は詳細を忘れました。これらすべてのスキーム(私のものだけでなく)では、リプレイ攻撃を防ぐためにMACも必要です(または、イブがアリスの気をそらし、買い物かごと請求先住所を変更して、「確認」ページを押します...)。一般に、所有しているすべてのトランザクションデータ(CC、CVV、トランザクションID、トランザクション金額、請求先住所など)にMACを設定する必要があります。
そうです、sessionsを使用すると、機密データを保存するのに非常に安全ではありません。次のように知られているセッションに侵入する方法があります。
私の頭に浮かぶ最も安全な方法は、情報をデータベースに(一時的に)保存してから、必要なページでその値を読み取ることです。すべての作業が終了したら、削除して戻すことができます。
注意:
this反射的にも役立つことがあります:)
とにかくそれに触れると、安全なクレジットカード番号の保存機能を提供する必要があるようです。サーバーが危険にさらされた場合、いつでも、現在保存されているクレジットカード番号(つまり、キーと暗号化された番号)を復号化するのに十分な情報が含まれます。考えられる解決策は、「暗号化/復号化」サービスとして機能する内部サーバーを使用することです。このように1台のマシンを危険にさらしても、クレジットカード番号は公開されません。
別の方法がありますが、Ajaxが必要です。クレジットカード番号とレビューページの保存はありません。
ページ1:配送、請求、クレジットカード情報を取得するためのフォーム。フォームを含むページの「本文」が、JavaScriptで参照できるように、一意のIDを持つDIV内にあることを確認してください。
ページ2:フォームフィールドを含むGET/POSTリクエストを受け入れ、適切にフォーマットされた「レビュー」ページを好みに戻すサーバー上のファイル。
チェックアウトプロセス:
ちょっとしたハックですが、適切に実行すると、ユーザーにとって100%シームレスになり、一時的なDBの保存などのリスクを負うことなく、カードデータを1回送信できます。
これが私がそれを行うことを計画している方法です-もちろんsslを使用してhttps経由ですべて。
手順1.ユーザーがCC情報を入力し、次のボタンを押します。 CC情報は、自分のDBではなくCCプロセッサのDBにすぐに保存されます。そうしないと、PCIコンプライアンスに違反することになります。 CCは、このステップで実際に課金されることはありません。ただし、CC情報を識別するプロセッサから一意のIDを受け取る必要があります。 (必要に応じて、一意のIDをデータベースに保存します)
手順2.確認ページで、指定された一意のIDを使用してCCプロセッサからCC情報を取得します。私のプロセッサでは、とにかくCCの最後の4つの番号しか取得できません。
ステップ3.購入を確認し、[今すぐ購入]ボタンを押したら、一意のIDを使用してクレジットカードに請求します。
ステップ4.CCの最後の4桁しかない請求書/領収書を含むありがとうページにリダイレクトします(もちろん、CCの最後の4桁を表示する必要はありませんが、表示するのは良いことだと思います)。
これがデータベースの目的です。ここでの法的な影響(国や地域によって異なります)についてはわかりませんが、1つのアプローチは、CC番号を暗号化し、ユーザーから受け取ったらすぐにデータベースに保存することです。必要なときにユーザーに表示できるように、最後の4桁を別のフィールドに保存することをお勧めします。サーバー上のカードプロセッサと対話する必要がある場合は、データベースからカード番号を取得して復号化します。
支払い処理の後のある時点(ステップ3の最後の部分)で、CC#(およびCVC)を暗号化して、支払い処理業者に送信できるようにする必要があります(私は推測します)
確認ページに必要な難読化の横で、情報を受け取ったときにその暗号化を実行してみませんか。 (これはステップ1の最後の部分です)
今後は、この暗号化または難読化されたデータのみを処理し、CC会社を実際に完全なデータを復号化できる唯一の会社にします。
情報を保持するためのセッションやデータベースは必要ありません。
すべてのページは、データを投稿するフォームです。後続の各ページで、前のページの投稿変数が非表示のフォームフィールドに追加され、次のフォーム送信でデータが再度投稿されるようになります。この方法では何も保存されませんが、情報はページからページへと運ばれます。これにより、ユーザーは手順をスキップせずに、最初から最後までプロセスを完了する必要があります。
フォームがHTTPS経由で送信される限り、データは自動的に暗号化され、セキュリティの負担はSSL証明書プロバイダーにあります。
多くの人気のあるコマースサイトがこれを実装しています。たとえば、OSCommerce。
カードnrのハッシュをセッションに保存し、同じハッシュと実際の番号およびユーザーのセッションIDをデータベースに保存できます。次に、ページごとにハッシュとセッション情報を確認して、カード番号を取得できます。
トークン化を使用します。その完全なPCI DSS準拠。
詳細については、こちらをご覧ください https://www.pcisecuritystandards.org/documents/Tokenization_Guidelines_Info_Supplement.pdf