假设我试图从使用基本身份验证/基本证书的 RESTful api 中提取,那么在我的程序中存储该用户名和密码的最佳方法是什么?现在它只是以明文形式存放在那里。
UsernamePasswordCredentials creds = new UsernamePasswordCredentials("myName@myserver","myPassword1234");
有没有一些更安全的方法来做到这一点?
谢谢
原文由 A_Elric 发布,翻译遵循 CC BY-SA 4.0 许可协议
重要的提示:
如果您将身份验证系统作为一个整体来设计,则不应存储密码,即使它们是加密的。您存储哈希值,并检查登录期间提供的密码是否与相同的哈希值匹配。这样,数据库的安全漏洞就可以避免暴露用户的密码。
话虽如此,对于您要按原样存储数据(在本例中为密码)的情况,然后采用由内而外的思维方式,以下是保护您的流程的一些步骤:
第一步,您应该将密码处理从
String
更改为character array
。原因是
String
是一个immutable
对象,因此即使对象设置为null
,它的数据也不会立即被清理;数据被设置为垃圾收集,这会带来安全问题,因为恶意程序可能会在清理数据之前访问String
(密码)数据。这就是为什么 Swing 的 JPasswordField 的
getText()
方法被弃用,以及为什么getPassword()
使用字符数组 的主要原因。第二步是加密您的凭据,仅在身份验证过程中临时解密它们。或者在服务器端对它们进行哈希处理,存储该哈希值,然后“忘记”原始密码。
这与第一步类似,可确保您的漏洞时间尽可能短。
建议不要对您的凭据进行硬编码,而是以集中、可配置且易于维护的方式存储它们,例如配置或属性文件或数据库。
您应该在保存文件之前加密您的凭据,此外,您可以对文件本身应用二次加密(对凭据进行 2 层加密,对其他文件内容进行 1 层加密)。
请注意,上面提到的两个加密过程中的每一个本身都可以是多层的。作为概念示例,每个加密都可以是 三重数据加密标准(AKA TDES 和 3DES) 的单独应用。
在您的本地环境得到适当保护后(但请记住,它永远不会“安全”!),第三步是通过使用 TLS(传输层安全性)或 SSL(安全套接字层) 对您的传输过程应用基本保护。
第四步是应用其他保护方法。
例如,将混淆技术应用于您的“使用”编译,以避免(即使很快)您的安全措施暴露,以防万一您的程序被 Eve 女士、Mallory 先生或其他人(坏-伙计们) 并反编译。
更新 1:
应@Damien.Bell 的要求,这里有一个涵盖第一步和第二步的示例:
一个完整的例子,解决每一个保护步骤,将远远超出我认为这个问题的合理范围,因为它是关于 “步骤是什么” ,而不是 “如何应用它们” 。
它会大大超过我的答案(最后是抽样),而这里关于 SO 的其他问题已经针对这些步骤的 “如何做” ,更合适,并提供更好的解释和抽样实施每一步。