为什么 JPasswordField.getPassword() 创建一个包含密码的字符串?

2022-09-01 16:27:43

Swing 的 JPasswordField 具有返回 char 数组的 getPassword() 方法。我对此的理解是,数组可以在使用后立即归零,这样您就不会在内存中长时间徘徊敏感事物。检索密码的旧方法是使用 ,它返回一个 String 对象,但它已被弃用。getText()

所以,我的问题是为什么Java在检索过程中实际上使用它,使用???为了更清楚,我正在调试我的测试应用程序以获取其他内容**,我按照调用并敲击... in 被调用,当然,一个带有我的密码的漂亮的 String 对象已经创建,现在正在内存周围悬挂。getPassword()getText()JPasswordField

亲自尝试一下:

public class PasswordTest() {
    public static void main(String[] args) {
        JFrame frame = new JFrame();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        JPasswordField passField = new JPasswordField();
        pass.addActionListener(new ActionListener() {
            public ActionPerformed(ActionEvent evt) {
                char[] p = passField.getPassword(); // put breakpoint
                // do something with the array
            }
        });
        frame.add(passField);
        frame.setVisible(true);
        frame.pack();
    }
}

后续问题:这种“隐藏”使用是否危险?当然,如果专用攻击者已经破坏了系统,它将获得您的密码,我说的是一个不太专用的;)getText()

**我在寻找一种在不使用对象的情况下在 Swing 组件上实际显示一些敏感数据的方法时遇到了这个问题。显然,除非我愿意重写Swing API的一部分(全部?),否则没有办法做到这一点。不会发生。String


答案 1

这对我有用,并帮助您构建字符串化密码:

String passText = new String(passField.getPassword());

答案 2

实际上,这是 Sun 的实现:getPassword()

public char[] getPassword() {
    Document doc = getDocument();
    Segment txt = new Segment();
    try {
        doc.getText(0, doc.getLength(), txt); // use the non-String API
    } catch (BadLocationException e) {
        return null;
    }
    char[] retValue = new char[txt.count];
    System.arraycopy(txt.array, txt.offset, retValue, 0, txt.count);
    return retValue;
}

唯一的是对 getText(int offset, int length, Segment txt) 的调用,它调用 getChars(int where, int len, Segment txt),它反过来又将字符直接复制到 的缓冲区中。那里没有被创造。getTextSegmentStrings

然后,将 的缓冲区复制到返回值中,并在方法返回之前将其清零。Segment

换句话说:没有额外的密码副本挂在任何地方。只要您按照指示使用它,它就是完全安全的。