在Java中,保存密码的最佳方式是什么?

3
我有两个类“用户资料”和“指纹资料”,它们都扩展了一个抽象类“资料”。 资料:
/**
 * Template for User profiles or Fingerprint profiles
 */
public abstract class Profile {

    /**
     * Profile Name
     */
    private String name;

    /**
     * Profile id
     */
    private int id;

    /**
     * Set the name of this profile
     * @param name
     */
    public void setProfileName(String name) {
        this.name = name;
    }

    /**
     * Set the id of this profile
     * @param name
     */
    public void setIdNumber(int id) {
        this.id = id;
    }

    /**
     * Get the name of this profile
     */
    public String getProfileName() {

        return name;

    }

    /**
     * Get the id of this profile
     */
    public int getIdNumber() {
        return id;
    }

}

我的下一节课是用户资料。
public class UserProfile extends Profile {

    /**
     * Users password
     */
    private char[] password;

    /**
     * Set User password
     * @param password
     */
    public void setPassword(char[] password){

        this.password = password;

    }

    /**
     * Get User password
     */
    public char[] getPassword(){

        return password;

    }

}

看起来这个类很可疑,像这样检索密码似乎完全是错误的(即使get方法是私有的)。
当我创建我的FingerPrintProfile类时,似乎也会遇到同样的问题,因为它包含一个“FingerprintData”对象,它本质上也需要保密。
有人知道一种安全的方法,或者最好是一种解决这种情况的常用模式吗?
谢谢!
额外的问题:
我创建了一个抽象类,为两种类型的配置文件提供模板,似乎指纹数据和文本密码之间存在共同点。然而,不可能创建一个抽象字段“密码”,它可能是字符数组或FingerprintData对象。有什么想法吗?

密码是否已加密? - Vincent Ramdhanie
不,密码没有加密,你看到的是我目前的开发阶段。 - TomSelleck
3个回答

8

在处理密码时,您可能应该使用某种加密形式,以便密码不以明文形式存储。您可以在这里了解其工作原理。

这里是一个Java实现Bcrypt的链接,它至少可以让您开始入门。


5
使用“对象思维”代替。您当前的设计根本不是面向对象编程。您应该暴露个人资料的行为,而不是设置和获取密码。例如:
interface Profile {
  void rename(String name);
  String identity();
  boolean authenticate(char[] password)
}

在面向对象编程中,getter和setter是一种反模式。


那么我应该在具体类中填写名称/密码字段吗? - TomSelleck
每个类是否可以有不同的身份验证方法,例如指纹识别和用户密码? - TomSelleck
1
你需要根据实现来决定authenticate()如何使用提供的密码进行用户身份验证(或拒绝)。重点是你的类不应该通过getter暴露密码,而是应该封装它并公开行为。 - yegor256
这是我首选的方法,因为它允许您实现加密密码(而不是明文密码)而无需更改API。 - Jin Kim
嗯,获取器/设置器确实是一种反模式,但我也认为OO应该模拟现实世界,在现实世界中,通常我会将凭据交给某种验证器,他们会查看包含我的用户配置文件的凭据并说:“是的,这看起来合法。” 我不知道在其他国家是否也是这样。 ;) - Hakanai

5
有没有人知道一种安全的方法,或者最好的一种模式来解决这样的情况?
你需要问自己“安全性有多高?”
如果在同一个JVM中执行了不受信任的代码,它可能会获取到密码。但是为什么要允许这种情况发生呢?
你无法保护内存数据免受在同一个JVM中以完全特权运行的不受信任的代码的攻击。
如果你小心谨慎,可以通过创建自定义的权限并使用SecurityManager检查调用者是否具有所需的权限来保护数据免受在安全沙箱中运行的不受信任的代码的攻击。(还需要做其他一些事情...)
尽管如此,“最佳实践”处理密码的方式是创建和存储一个使用(真正)安全的哈希算法进行加密的种子哈希值。你也可以在这里做同样的事情。问题是,如果你确实需要明文密码,那么这种方法行不通......因为哈希的整个思想就是使恢复密码变得困难。但反过来,如果密码曾经以明文形式存在,坏人就有可能窃取它。
加密密码并不能保证免受JVM中不受信任的代码的攻击。在时间、精力和不受信任的人与坏人之间的隐蔽信息通道的作用下,可以恢复使用的密钥和算法,并因此解密数据。而且坏人可能通过核心转储或读取JVM进程的分页文件来获取信息。
底线是,如果你的平台安全性受到破坏(无论是JVM还是操作系统),你不能保证保存在明文或加密中的密码仍然是安全的。

谢谢回复,这就是我所说的“看起来”不对的地方。一个对象的字段可以以明文形式保存密码,这似乎并不正确。如果操作系统不存储密码,那么我的应用程序为什么要这样做呢? - TomSelleck

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接