web-dev-qa-db-ja.com

銀行口座の詳細をデータベースに安全に保存

私は定期的(毎週、毎月など)に顧客の口座の口座引き落としを含むサービスを開発しているので、データベースに顧客の情報(BSB /ルーティング番号と口座番号)を保存する必要があります。私はセキュリティに非常に関心があるので、最初はこの情報を保存しないことを考えましたが、このトピックに関する他の多くの質問を読んだ後、うまくいくと思う解決策を思いつきました-実行したいと思います私がセキュリティホールを開けたままにしていないことを確認するために、皆さんを過ぎて。

ユーザーがサービスに登録すると、ユーザーが提供するパスフレーズ(アカウントパスワード)を持つ秘密鍵を使用して、公開鍵と秘密鍵のペアが作成されます。パスワードはbcryptでハッシュされ、公開キーと秘密キーはパスワードハッシュと一緒にユーザーテーブルに格納されます。

また、口座振替を処理する必要があるときに使用される単一の管理者公開/秘密鍵ペアを確立します。公開鍵はアプリケーションとデータベースに認識されますが、秘密鍵はサーバーから隔離されているため、データは暗号化された場合にのみダウンロードされ、他の場所で処理されます。暗号化されたときにダウンロードする代わりに、代わりに秘密鍵をアプリケーションにアップロードし、その要求のデータのみを復号化してから、アップロードされた秘密鍵を削除します-これはセキュリティホールですか?

ユーザーが口座振替に登録すると、サービスはユーザーの公開鍵と管理者の公開鍵を取得し、それらを GPGの複数の受信者機能 を使用して暗号化します。

私の知る限り、これは以下の状況をカバーしています。

  • ユーザーがデータを表示する場合は、情報を解読するためにパスワードを入力する必要があります。
  • ユーザーがデータを追加したい場合は、公開鍵を使用するだけなので、パスワードを入力する必要はありません。
  • 管理者がデータを表示する場合は、情報をダウンロードして解読するか、秘密鍵をアップロードする必要があります(上記を参照)。
  • ユーザーがパスワードを変更した場合は、秘密鍵を更新するだけで済みます。彼らがパスワードを忘れた場合、私がデータを復号化できる唯一の方法は管理者の秘密鍵を使用することですが、これはオフサイトに保管されるため、データを削除する必要があります。

管理者キーペアが侵害されたことが明らかな場合(明白なものは別として)、新しい管理者キーペアを生成し、保存されているすべてのデータを再暗号化する必要がある場合、何か心配はありますか?

この設計にセキュリティホールはありますか?私は確かに専門家ではありませんが、これを研究するために最善を尽くそうとしました。

私は Authorize.netのCustomer Information Manager(CIM) のようなサービスも調べましたが、自分のサービスを使用して支払いを収集する必要があることがわかる限り、代わりにすでに独自のサービスを確立しています商人はこれをより安い料金で行うため、安全な情報保管サービスが必要です。

サービスはHTTPSを使用し、Ubuntu 12.04で実行されます(PHPおよびMySQLを使用)。

あなたが与えることができるどんなアドバイスでも大歓迎です!

ありがとう

5
mitchdav

パスワードはbcryptでハッシュ化され、公開鍵と秘密鍵はパスワードハッシュとともにユーザーテーブルに保存されます。

秘密鍵を保存することは、データベースの侵害により攻撃者が銀行情報を解読できることを意味します。銀行情報をプレーンテキストで保存することもできます。

とにかく、銀行情報をユーザーのキーで暗号化する必要があるのはなぜですか?ユーザーはその情報を要求しますか?「先ほど言った銀行口座を教えてください」?

4
Gerald Davis

おそらく最も財政的に責任のあるソリューションとなるため、セキュリティのためにサードパーティに支払うことを強く検討することをお勧めします。支払いカードのデータを自分で処理する場合、PCI監査を担当することになります。これは非常に費用がかかる可能性があります。また、2015年10月の責任のシフト後(あなたが米国にいると仮定した場合)、支払いチェーンの最も弱いリンクが詐欺の費用をカバーする責任があります。システムが侵害された場合、銀行、支払い処理業者、および被害者によって、干ばつに悩まされることは間違いありません。そのような損失をカバーするお金はありますか?

2
John Deters

はい、これらの関数を使用して、DBからのデータを暗号化および復号化します。

  static function encrypt($s) {
    $keyHex = getenv('APP_KEY');
    if (!$keyHex) {
      Yii::error ("Could not retrieve environment variable APP_KEY");
      return null;
    }
    $key = pack('H*', $keyHex); 
    $iv = mcrypt_create_iv(256/8); // 256 bit / 8 bit/byte = 32
    $cipherText = mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $key, $s, 'cbc', $iv);
    $cipherText64 = base64_encode($iv.$cipherText);
    return $cipherText64;
  }

  static function decrypt($s) {
    $keyHex = getenv('APP_KEY');
    if (!$keyHex) {
      Yii::error ("Could not retrieve environment variable APP_KEY");
      return null;
    }
    $key = pack('H*', $keyHex);
    $cipher = base64_decode($s); 
    $iv = substr($cipher, 0, 256/8);
    $cipher = substr($cipher, 256/8); // strip off IV from front
    $text = mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $key, $cipher, "cbc", $iv);
    $text = rtrim($text, "\0"); // mcrypt leaves null padding on the text
    return $text;
  }

それらは現在環境変数からキーを取得しているため、ユーザーからキーを取得するためにそれらを変更する必要があります。銀行の詳細にアクセスするたびに、ユーザーにパスワードを入力してもらいたいと思います。パブリック/プライベート暗号化を使用する必要はありません。これは小さな値に対してのみ有効ですが、銀行口座番号はおそらく十分に小さいです。キーは、64文字の16進文字列、32バイトのキー、または256ビットのキーである必要があります。ただし、安全にランダムにする必要があります。ユーザーにパスワードを提供させ、それをパスワードベースのキー派生関数(PBKDF)を使用してキーに変換すると、誰かがデータベースをブルートフォース攻撃する可能性があります。

0
Chloe