我们通常使用一个 String 类型变量来保存用户提交的密码等敏感信息,但实际上这是不安全的做法。
从 String 类的签名可以看到,String 的对象都是不可变的,也就是说 String 对象一旦被创建就不能通过任何方法(除了使用反射)对它进行修改,直到其被垃圾回收器回收(这段时间这个 String 对象通常会存在于常量池中)。这也就意味着在 String 对象被创建到垃圾回收器对它进行回收的这段时间,一旦内存被 dump,那么密码等敏感信息将以明文的形式暴露。
另外,我们可能在编程中无意的将密码打印到了日志中,这也可能因为日志文件被盗取而导致敏感信息被泄露。最后,在 Java 官方文档中对基于密码的加密这部分也建议不使用 String 对象来保存密码。
那么我们该使用什么方式来保存密码这类敏感信息呢?正确的选择是使用 char 数组。因为使用数组我们能够在对敏感信息的业务逻辑处理完成后及时的将其设置为其他任何值,这样就可以清楚掉我们的密码信息。同样,如果我们无意中对密码进行了日志打印,那么 char 数组输出的也是内存地址而不是我们的敏感数据。
需要注意的是,即使使用 char 数组来保存敏感信息依然不能保证绝对的安全,因为在内存中可能还会存在这些数据的零散碎片。更加安全的做法是对保存的敏感信息进行 hash,且最好是加盐 hash,这样能够更进一步的提高信息的安全性。但不得不说,没有绝对的安全,只能更可靠的安全防护方式。
文档:https://docs.oracle.com/javase/8/docs/technotes/guides/security/crypto/CryptoSpec.html#PBEEx