我想制作一个从 STDIN 静默读取密码的 Java 程序。我的意思是,不向终端输出任何按下的字符,也不会将其从命令行历史和操作系统 processlist 中隐藏起来ps
。
4 回答
java.io.Console 类可能有用:
System.console().readPassword();
这会从控制台读取一系列字符,而不会回显任何内容。请注意,它仅在您使用真实控制台启动 java 应用程序时才有效。否则,System.console() 返回 null。
通过 STDIN 获取密码的不太安全的选项,适用于后台作业、虚拟控制台和普通控制台:
这更兼容但安全性更低,它应该与 IDE 中的虚拟控制台、没有 TTY 的后台进程和普通控制台一起使用。当找不到控制台时,它会回退到使用 BufferedReader,在某些情况下,当用户键入密码时,它会将密码暴露在屏幕上。
Java 代码:
import java.io.*;
public class Runner {
public static void main(String[] args) {
String username = "Eric";
try {
ReadMyPassword r = new ReadMyPassword();
char[] password = r.readPassword(
"Hey %s, enter password to arm the nuclear wessels>", username);
System.out.println("Exposing the password now: '" +
new String(password) + "'");
} catch (IOException e) {
e.printStackTrace();
}
}
}
class ReadMyPassword{
public char[] readPassword(String format, Object... args)
throws IOException {
if (System.console() != null)
return System.console().readPassword(format, args);
return this.readLine(format, args).toCharArray();
}
private String readLine(String format, Object... args) throws IOException {
if (System.console() != null) {
return System.console().readLine(format, args);
}
System.out.print(String.format(format, args));
BufferedReader reader = new BufferedReader(new InputStreamReader(
System.in));
return reader.readLine();
}
}
这是通过 Eclipse 虚拟控制台看到的样子:
Hey Eric, enter password to arm the nuclear wessels>12345
Exposing the password now: '12345'
Program Sisko 197 ready for implementation on your command
这是通过普通控制台的样子。
el@apollo:/home/el/bin$ java Runner
Hey Eric, enter password to arm the nuclear wessels>
Exposing the password now: 'abcdefg'
Program Sisko 197 ready for implementation on your command
el@apollo:/home/el/bin$
你可能想看看java.io.Console
它有一个 readPassword 方法,该方法“从禁用回显的控制台读取密码或密码”。
Java 使用 STDIN 获取密码的最安全选项:
该演示在 Ubuntu 12.10 终端上使用 Java。使用 STDIN 获取密码在安全方面是一个好主意,因为密码不会暴露给命令行历史记录或带有ps
. 键入的密码字母会被丢弃而不是存储。
Java 代码:
public class Runner {
public static void main(String[] args) {
System.out.print("Enter password: ");
String secretpassword = new String(System.console().readPassword());
System.out.println("Here we expose our password to STDOUT: "
+ secretpassword);
//Put maximum levels of encapsulation and security on this
//secretpassword variable. Destroy it in memory asap, don't leave it
//sitting around anywhere.
}
}
如果使用上述代码的条件
如果超高安全性是您的首要任务,甚至不要将该密码存储在
String
. 从用户那里收到后立即加密。这样,如果某个聪明的人扫描了您的程序的内存,他们就不会在那里找到您的明文密码。如果您尝试通过后台作业调度程序运行此程序,则可能
System.console().readPassword()
会返回 NullPointerException,这是一项增强安全性的功能。它拒绝访问虚拟控制台和后台任务等恶作剧。如果您希望它与虚拟控制台一起正常工作,请参阅我在此页面上的其他答案。如果您尝试通过 Eclipse、Netbeans 或任何其他虚拟控制台等 IDE 运行此代码,
System.console().readPassword()
则会抛出 NullPointerException,因为找不到真正的控制台,并且程序将停止。这是一个功能,而不是一个错误。
控制台上的样子:
el@apollo:/home/el/test$ java Runner
Enter password:
Here we expose our password to STDOUT: foobarpassword
el@apollo:/home/el/test$