我正在开发一个Java服务,它有一个针对它的安全bug,涉及存储在JavaString对象中的秘密。
担心的是,一旦密码存储在String
中,它就会一直保留在字符串池中,直到被垃圾回收,并且可能会以明文形式显示在转储中。
我理解Java的String
类是不可变的,并且首选将机密或密码存储在可变类中,因此可以在使用后尽快将其从内存中删除。
参考文献
然而,当使用第三方库时,我发现这是不切实际的,因为他们中的许多人希望将密码或秘密作为String对象传递给请求,无论我有多安全,在我的代码中,最终都会将char[]
数组转换为String
,这让我们回到了最初的问题,不是吗?
那么,是否有办法将char[]
或StringBuffer
转换为String
,而不会回到最初的问题?
如果您需要调用需要String
的API,则无法避免创建String
。只要您避免字符串文字或显式实习字符串,字符串就不会最终进入字符串池。
这也是一个不可能解决的问题。例如,如果这是一个数据库连接池的密码,密码需要在程序的生命周期内可用,以便能够创建新的连接。即使您可以以某种可清除的方式提供密码,如char[]
、CharBuffer
、StringBuilder
等,也不能保证您调用的API不会将其转换为字符串,或制作副本等。
即使使用char[]
也不能保证您能够正确地从内存中清除它:Java垃圾收集器可以并且将会移动对象,因此您的密码完全有可能仍然在内存中的先前位置,即使您显式地将该char[]
归零。
如果威胁参与者对您的系统有足够的访问权限来检查内存、进行堆转储等,您就会遇到更大的问题,并且担心使用String
与char[]
只是浪费时间,因为威胁参与者将有其他方法来查找您的密码,例如查找配置源、修改程序以在下一次运行时记录密码等。
明确地说,能够快速清除某些敏感信息可以减少攻击窗口,但是除非你在高安全性的环境中工作,否则考虑到所有的警告,这不太可能是正确的事情。