需要临时存储第三方密码

信息安全 密码 php
2021-08-15 22:34:35

我正在编写的一个特定的 Web 服务与 API 接口。每个 API 调用都需要发送用户的用户名和密码,不维护任何状态。

理想情况下,当使用我的网络服务时,用户将输入他的 API 用户名和密码一次,我的网络服务将存储该信息直到会话结束。我了解出于安全考虑,我不应该使用 PHP 会话存储 API 密码,也不应该将其存储在数据库中。因此,如何在会话期间安全地存储和访问密码?

加密密码、将加密密码存储在 cookie 中、将加密密钥存储在会话中是否安全?

请注意,我最初在 SO 上问了这个问题(没有提出的解决方案):https : //stackoverflow.com/questions/15084025/storing-third-party-passwords-for-reuse-across-pages 如果我先喝咖啡,我会知道在这里而不是那里发帖。SO帖子可以删除,但我不能。

那里给出的答案是我现在在生产中使用的那个,所以如果方法中存在缺陷(在 PHP 会话中存储加密密码,在 cookie 中存储加密密钥),那么我非常想知道。

$encryptionKey = sha1(microtime(true).mt_rand(PHP_INT_MAX / 10, PHP_INT_MAX));
$encryptedPassword = mcrypt_encrypt(MCRYPT_BLOWFISH, $encryptionKey, $password, MCRYPT_MODE_CFB);
setcookie('atwood', $encryptionKey, 0);
$_SESSION['encryptedPassword'] = $encryptedPassword;

$password = mcrypt_decrypt(MCRYPT_BLOWFISH, $_COOKIE['atwood'], $_SESSION['encryptedPassword'], MCRYPT_MODE_CFB);
1个回答

要问的问题是:这里的安全模型什么?

您显然需要将用户密码(一条敏感数据)从用户传输到后端服务器。但是时间很重要:人类用户在用户认为的“会话”开始时输入他的密码一次,密码必须在以后传输到后端(“API 调用”)。因此,某处必须有一些存储空间。

PHP 会话是服务器端存储,作为具有基于时间的到期的小文件的集合。您在“会话变量”中写入的内容最终会进入硬盘。因此,将纯密码存储在会话变量中可能被认为是一种错误的形式,因为当文件被删除时,硬盘物理内容不会被可靠地破坏(删除时,专用于文件的存储区域被标记为可重用,但在该区域确实被另一个文件重用之前,数据本身不会被覆盖)。但有一些细节:

  • 如果您担心通过对旧磁盘(或备份磁带)的事后访问导致数据泄漏,那么您希望避免将文件发送到物理介质。有些人将 PHP 会话文件放在RAM 磁盘上:RAM 磁盘设置了用于此类操作的 OS 工具,并使用session_save_path(). RAM 磁盘中的文件永远不会进入物理存储,因此泄漏了。另一方面,如果服务器重新启动,所有会话都将丢失(这可能是可以容忍的,但这取决于设置)。在多个前端共享会话也将更加复杂。

    注意:在 Linux 系统上,有三种方法可以创建 RAM 磁盘:“真正的”RAM 磁盘(每个最大 16 MB,在启动时调整)、“ramfs”和“tmpfs”。最后一个将使用 RAM,但也会使用交换空间,因此内容可能仍会进入磁盘。有关详细信息,请参阅此页面

  • 如果您担心通过实时入侵您的服务器而泄漏会话数据,那么请考虑可能对某些受操作系统保护的文件进行读取访问的人也可能距离控制整个机器不远,此时他将只是插入 PHP 引擎并在用户密码到达时获取它们。达到这种保护水平没有什么意义。

    您建议加密用户密码,并将密钥存储在客户端浏览器中(作为 cookie),并将加密密码存储在会话文件中;或者你可以做相反的事情(在 PHP 会话中输入密钥,在 cookie 中加密密码)。在这两种情况下,想法是攻击者需要同时获取会话数据和 cookie 来解开密码。仅当您的安全模型假设攻击者能够读取会话文件(即使它们仅在 RAM 磁盘中)但不能读取分配给 PHP 引擎的 RAM(密码有时必须通过该 RAM 传输)时,这才有意义. 这对我来说似乎不是一个非常现实的模型。

如果您确实想使用加密,无论它在特定情况下明显无用,您也可以正确使用:

  • 使用加密安全的 PRNG ( openssl_random_pseudo_bytes())生成(用户特定的)密钥
  • 使用适当的加密。这意味着通常的各种加密模式,随机IV(将与加密文件一起存储),填充......很容易完全错误。可以使用PHP 进行正确的加密,但您必须了解您在做什么,直到细节。在为每个加密实例生成新密钥的特定情况下,在 CFB 模式下使用强分组密码和固定的常规 IV 就足够了,尽管它会泄露密码长度并且 PHP 有做奇怪事情的习惯(例如,它的“CFB”模式实际上是带有 8 位反馈的CFB ,这对于长输入来说速度很慢并且安全性值得怀疑)。

但我仍然建议不要这样做,而是在服务器上使用基于 RAM 的 PHP 会话存储。