我在一本Java认证书中读到了关于java.io.Console
类的内容,可能我错过了之前章节的一些基础知识,但能有人解释以下吗?
文中提到readPassword
方法返回一个字符数组而不是字符串,以防止潜在的黑客找到该字符串并找到密码。
字符数组为什么更安全?如果您可以获取数组中的值,那么难道您不能创建一个脚本来循环尝试各种组合,最终还是会找到密码吗?
来自文档:
控制台对象通过其readPassword方法支持安全密码输入。该方法以两种方式帮助保护密码输入。首先,它抑制了回显,因此密码不会显示在用户的屏幕上。其次,readPassword返回一个字符数组而不是字符串,因此密码可以被覆盖,一旦不再需要,便从内存中删除。
这里的想法是,您可以调用Arrays.fill(或等效方法)来“清空”char数组,一旦验证了密码,从那时起,密码将不再存储在内存中。由于字符串是不可变的,所以字符串将一直存在于堆中,直到被垃圾收集 - 如果它成功地使自己成为国际化字符串,则永远不会被收集,否则在任何其他情况下仍可能“太长”。 在此期间,它可能容易受到各种向量的嗅探攻击。
这是一种最佳实践。虽然看起来并没有太多意义,但我们之所以这样做是为了让生活更轻松。
如果密码在内存中,缓冲区读取溢出可能会导致密码被读取。或者它可能保存在核心转储或休眠映像中。使用可变的char[]
允许数据在一个希望很窄的时间窗口之后被销毁,只要它没有被复制到字符串中,复制到其他地方,它可能在缓冲区中,垃圾收集器喜欢移动对象等等。
在Swing中有一个有趣的例子,JPasswordField
提供了一种char[]
读取数据的方式,但例如如果它有一个操作监听器(这是非常常见的使用方式),它将从数据创建一个String
。
字符串是一个不可变的类,当密码存储在字符串中时,您无法控制其生命周期,这意味着它可能长时间存在于内存中(即使它没有被interned,它也会一直存在于内存中,直到JVM退出),并且可能受到内存转储等影响。当密码存储在字符数组中时,您可以清除该数组,从而在验证密码后从内存中删除密码。