将银行帐户详细信息安全地存储在数据库中

信息安全 加密 银行
2021-09-02 17:41:42

我正在开发一项服务,该服务将涉及定期(每周、每月等)直接借记客户帐户,因此我需要将他们的信息(BSB/路由号码和帐号)存储在我的数据库中. 我非常关心安全性,所以我的第一个想法是不要存储这些信息,但是在阅读了关于这个主题的许多其他问题之后,我想出了一个我认为可行的解决方案 - 但我想运行它过去你们,以确保我没有留下任何安全漏洞。

当用户注册到服务时,它将创建一个公钥/私钥对,私钥具有用户提供的密码(他们的帐户密码)。密码使用 bcrypt 散列,公钥和私钥与密码散列一起存储在用户表中。

我还将建立一个管理员公钥/私钥对,当我们需要处理直接借记时将使用它。公钥对应用程序和数据库是已知的,但私钥将被保存在服务器之外,因此只有在加密后才能下载数据,然后在其他地方进行处理。加密时下载的替代方法是将私钥上传到应用程序,仅解密该请求的数据,然后删除上传的私钥 - 这是一个安全漏洞吗?

当用户注册直接借记时,该服务将获取用户的公钥和管理员的公钥,并使用GPG 的多收件人功能对其进行加密。

据我所知,这包括以下情况:

  • 如果用户想要查看数据,他们将需要提供密码来解密信息。
  • 如果用户想要添加更多数据,他们不需要提供密码,因为我只使用他们的公钥。
  • 如果管理员想要查看数据,他们需要下载信息并解密,或者上传他们的私钥(见上文)。
  • 如果用户更改了他们的密码,我只需要更新他们的私钥。如果他们忘记了密码,我可以解密他们的数据的唯一方法是通过管理员私钥,但由于这是在场外保存的,因此应该删除数据。

如果管理密钥对被泄露(除了显而易见的问题)并且我需要生成一个新的管理密钥对然后重新加密所有存储的数据,是否会有任何问题?

此设计中是否存在任何安全漏洞?诚然,我不是专家,但我已尽力对此进行研究,现在很想得到一些意见。

我还研究了Authorize.net 的客户信息管理器 (CIM) 之类的服务,但据我所知,您需要使用他们的服务来收款,而我们已经建立了自己的商家以更便宜的价格进行此操作率,所以我们只需要一个安全的信息存储服务。

该服务将使用 HTTPS,并在 Ubuntu 12.04 上运行,使用 PHP 和 MySQL,如果有帮助的话。

您可以提供的任何建议将不胜感激!

谢谢

3个回答

密码使用 bcrypt 散列,公钥和私钥与密码散列一起存储在用户表中。

存储私钥意味着数据库的破坏将允许攻击者解密银行信息。您不妨以纯文本形式存储银行信息。

为什么银行信息需要用用户的密钥加密呢?用户是否会请求该信息“请告诉我我之前告诉过你的银行账户”?

我强烈建议您考虑向第三方支付安全费用,因为这可能是对财务负责的解决方案。如果您自己处理支付卡数据,您将负责 PCI 审计,这可能非常昂贵。在即将到来的 2015 年 10 月责任转移之后(假设您在美国),支付链中最薄弱的环节将负责支付欺诈费用。如果您的系统遭到破坏,您无疑会被银行、您的支付处理商和受害者晾在一边。你有钱来弥补这些损失吗?

是的,使用这些函数来加密和解密来自数据库的数据。

  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 个字符的十六进制字符串、32 字节的密钥或 256 位的密钥。不过,它必须是安全随机的。如果您让用户提供密码并将其转换为具有基于密码的密钥派生功能 (PBKDF) 的密钥,那么有人可能会暴力攻击数据库。