Python中的安全凭证存储

18 投票
2 回答
26719 浏览
提问于 2025-04-17 14:22

攻击方式

在存储凭证的情况下,有一种可能的威胁模型是攻击者能够:

  • 查看任何用户进程的内存
  • 读取本地用户文件

据我所知,对于这种攻击方式,大家普遍认为是无法完全防止的(因为程序需要在内存中存储凭证才能使用它们),但有一些方法可以减轻这种风险:

  • 尽量减少敏感数据在内存中存储的时间
  • 一旦不再需要数据,就立即覆盖内存中的内容
  • 对内存中的数据进行混淆,保持移动,以及其他通过模糊处理来增强安全性的方法

特别是Python

第一种方法比较容易实现,可能可以通过一个密钥管理工具来完成(希望是内核空间存储)

第二种方法据我所知是无法实现的,除非编写一个C语言模块(但我希望我错了,或者能有现成模块的列表)

第三种方法就比较棘手了。

特别是,Python是一种具有强大反射和自省能力的语言,因此很难防止任何能够在解释器进程中执行Python代码的人访问凭证。

大家似乎一致认为没有办法强制执行私有属性,而且尝试这样做最多只是让使用你代码的其他程序员感到烦恼

问题

考虑到这些因素,如何在Python中安全地存储身份验证凭证?有哪些最佳实践?对于“万物皆公开”的语言哲学,有没有什么解决办法?我知道“我们都是成年人”,但难道我们真的要在与攻击者分享密码和使用其他语言之间做出选择吗?

2 个回答

2

我不是这个领域的专家,其实我只是想解决和你一样的问题,但看起来像是Hashicorp的Vault可能会很有帮助。

特别是关于存储第三方服务的凭证的问题。例如:

在这个一切都依赖API的现代世界,很多系统也支持程序化地创建访问凭证。Vault利用了这个支持,提供了一种叫做动态秘密的功能:这些秘密是按需生成的,并且支持自动撤销。

在Vault 0.1版本中,Vault支持动态生成AWS、SQL和Consul的凭证。

更多链接:

34

存储身份验证信息有两个很不同的原因:

  1. 为了验证你的用户:比如说,只有在用户通过你的程序进行身份验证后,才能访问服务。
  2. 为了让程序与其他程序或服务进行身份验证:例如,用户启动你的程序,然后程序通过IMAP访问用户的电子邮件。

在第一种情况下,你绝对不应该存储密码(或者密码的加密版本)。相反,你应该用高质量的盐对密码进行哈希处理,并确保你使用的哈希算法计算起来比较复杂(以防止字典攻击),比如PBKDF2或bcrypt。想了解更多细节,可以查看盐值密码哈希 - 正确做法。如果你遵循这种方法,即使黑客获取了盐值和慢哈希的令牌,他们也无能为力。

在第二种情况下,有很多措施可以让秘密更难被发现(正如你在问题中提到的),比如:

  • 在需要时才解密秘密,解密后立即重新加密
  • 使用地址空间随机化,每次应用程序运行时,密钥存储在不同的地址
  • 使用操作系统的密钥存储
  • 使用像C/C++这样的“硬”语言,而不是像Java或Python这样的基于虚拟机的语言

这些方法当然比什么都不做要好,但熟练的黑客迟早会攻破它。

令牌

从理论上讲,身份验证就是证明被挑战的人确实是他们所声称的那个人。传统上,这是通过共享秘密(密码)来实现的,但还有其他方式可以证明自己,包括:

  • 带外身份验证。例如,在我所在的地方,当我尝试登录我的网上银行时,我会收到一条短信,里面有一个一次性密码(OTP)。通过这种方法,我通过拥有特定的电话号码来证明我自己。
  • 安全令牌:登录服务时,我需要按下令牌上的按钮以获取一次性密码,然后将其用作我的密码。
  • 其他设备:

    • 智能卡,特别是美国国防部使用的那种,称为CAC。Python有一个叫做pyscard的模块可以与之接口。
    • NFC设备

更完整的列表可以在这里找到。

这些方法的共同点在于,最终用户控制这些设备,秘密信息实际上不会离开令牌/卡片/手机,当然也不会存储在你的程序中。这使得它们更加安全。

会话劫持

然而(总是有“然而”):

假设你成功地保护了登录,使得黑客无法访问安全令牌。现在你的应用程序可以愉快地与安全服务进行交互。不幸的是,如果黑客能够在你的计算机上运行任意可执行文件,他们可以劫持你的会话,例如通过在你合法使用服务时注入额外的命令。换句话说,虽然你保护了密码,但这完全无关紧要,因为黑客仍然可以访问“安全”的资源。

这是一个非常真实的威胁,多个跨站脚本攻击已经证明了这一点(一个例子是美国银行和美国银行网站存在漏洞,但还有无数其他例子)。

安全代理

如上所述,在第三方服务或系统上存储帐户凭据以便应用程序能够登录是一个根本性的问题,尤其是当唯一的登录方式是用户名和密码时。

一种部分缓解此问题的方法是将与服务的通信委托给一个安全代理,并在应用程序和代理之间开发一个安全的登录方法。在这种方法中:

  • 应用程序使用PKI方案或双因素身份验证登录到安全代理
  • 用户将第三方系统的安全凭据添加到安全代理中。这些凭据从未存储在应用程序中
  • 稍后,当应用程序需要访问第三方系统时,它会向代理发送请求。代理使用安全凭据登录并发出请求,将结果返回给应用程序。

这种方法的缺点包括:

  • 用户可能不想信任安全代理来存储凭据
  • 用户可能不信任安全代理处理流向第三方应用程序的数据
  • 应用程序所有者需要额外的基础设施和托管成本来运行代理

一些回答

那么,关于具体的回答:

如何安全地存储身份验证凭据?

  • 如果存储应用程序用来验证用户的密码,使用PBKDF2算法,比如https://www.dlitz.net/software/python-pbkdf2/
  • 如果存储访问其他服务的密码/安全令牌,那么没有绝对安全的方法。
  • 但是,可以考虑切换身份验证策略,例如使用智能卡,使用例如pyscard。你可以使用智能卡来同时验证用户对应用程序的身份,并安全地验证应用程序对其他服务的身份,使用X.509证书。

在我看来,编写一个特定的模块来尽可能隐藏秘密信息是没有问题的,这样其他人就很难重用(让其他程序员感到烦恼就是它的目的)。你甚至可以用C语言编写大部分代码并链接到它。但出于明显的原因,不要对其他模块这样做。

不过,最终,如果黑客控制了计算机,那么计算机上就没有隐私可言。理论上的最坏情况是你的程序在虚拟机中运行,而黑客可以完全访问计算机上的所有内存,包括BIOS和显卡,并可以通过身份验证步骤来发现其秘密。

在没有绝对隐私的情况下,其余的只是混淆,保护的程度仅仅取决于混淆的难度与熟练黑客获取信息的意愿之间的关系。我们都知道这会如何结束,即使是对于定制硬件价值数十亿美元的产品

使用Python密钥环

虽然这可以相对安全地管理密钥,但所有Python应用程序都共享对令牌的访问。这对于你担心的攻击类型来说,根本不安全。

撰写回答