【问题标题】:Why we read password from console in char array instead of String [duplicate]为什么我们从 char 数组中的控制台读取密码而不是 String [重复]
【发布时间】:2012-09-23 08:09:59
【问题描述】:

可能重复:
Why is char[] preferred over string for passwords?

当我为OCPJP 做准备时,我遇到了这个话题——“从控制台读取用户输入”。

有一个例子,它在String 引用中读取username,而在char[] 数组中读取password,但我不明白为什么它使用char 数组。这是代码:-

Console console = System.console();

String username = console.readLine("User Name? ");
char[] password = console.readPassword("Password? "); 

这让我产生了疑问。为什么我们不使用 String 引用来存储密码。由于 Strings不可变的, 因此读取字符串中的密码必须更安全,因为它的内容无法更改。

那么,在char[] 数组中读取password 的意义何在..

谁能解释一下这个问题?

【问题讨论】:

    标签: java console


    【解决方案1】:

    正如您所说,字符串是不可变的,这意味着一旦您创建了字符串,如果另一个进程可以转储内存,那么在 GC 启动之前,您就无法(好吧,可以通过反射)删除数据。

    使用数组,您可以在使用完数据后显式擦除数据:您可以用任何您喜欢的内容覆盖数组,并且密码不会出现在系统中的任何位置,即使在垃圾回收之前也是如此。

    【讨论】:

    • 至少这是使用字符数组作为密码的意图。但是,我不太确定考虑堆碎片整理、虚拟内存、交换等是否真的如此。如果例如对堆进行碎片整理会导致 char 数组在进程的内存空间内移动,旧位置上的内容实际上会被擦除吗?
    • 我相信这取决于 GC 的具体实现...
    【解决方案2】:

    来自Javadoc of java.io.Console

    安全说明:如果应用程序需要读取密码或其他安全数据, 它应该使用readPassword()readPassword(String, Object...) 并手动归零 处理后返回的字符数组以最小化 内存中的敏感数据。

    这只是为了防止其他应用程序(如键盘记录器等)访问密码。

    此外,如果您使用String,由于它们是不可变的,因此修改它们会在内存中创建副本。在这种情况下,使用char[] 可以为您省钱。由于它们是可变的,它们不会创建副本,您可以在处理后将它们设为 null。

    【讨论】:

    • 看不出 char[] 与键盘记录器的字符串有何不同...
    • @caarlos0 实际上,这不会阻止键盘记录器,但会减少读取内容的机会,因为副本不可用并且数据将被取消。
    • 如果我错了,请纠正我,但是,我认为键盘记录器会捕获键盘事件。所以,你使用什么数据类型并不重要......对吗?我相信它只会阻止人们从内存转储中获取字符串。
    • 由于对焦问题,他们无法直接从输入中获取键。相反,他们必须读取内存。
    • 嗯,在这种情况下,你是对的。谢谢。
    【解决方案3】:

    我相信这样您就可以在不再需要它们时通过覆盖它们来从内存中清除它们。至少在Java中,如果你使用String,那么内存中可能会有剩余的副本。

    如果您使用 for 循环覆盖 char 数组并将每个值设置为 0,我认为内存中不会有任何剩余副本。

    【讨论】:

      【解决方案4】:

      由于字符串是不可变的,因此它们不能被覆盖并在应用程序处于活动状态时保留在内存中。 char 数组,另一方面可以清除所有密码信息。

      【讨论】:

        猜你喜欢
        • 2017-11-06
        • 2014-01-22
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-02-17
        • 1970-01-01
        相关资源
        最近更新 更多