How to use Scanner to read silently from STDIN in Java?
I want to make a Java program that reads a Password from STDI开发者_开发百科N silently. I mean, without outputting any pressed chars to the terminal and keeping it hidden from commandline history and the operating system processlist ps
.
The class java.io.Console may be useful:
System.console().readPassword();
This reads a sequence of chars from the console, without echoing anything. Note that it only works when you launch your java application with a real console. Otherwise, System.console() returns null.
A less secure option to get the password via STDIN that works with background jobs, virtual consoles, and normal consoles:
This is more compatible and less secure, it should work with your virtual console in your IDE, for background processes that don't have a TTY, and normal consoles. When a console is not found, it falls back to use a BufferedReader which will expose the password to screen as the user types it in some cases.
Java Code:
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();
}
}
Here's what it looks like through through the Eclipse virtual console:
Hey Eric, enter password to arm the nuclear wessels>12345
Exposing the password now: '12345'
Program Sisko 197 ready for implementation on your command
Here's what it looks like through the normal console.
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$
You might want to give java.io.Console a look
It has a readPassword method which "Reads a password or passphrase from the console with echoing disabled".
Most secure option for Java to get a password with STDIN:
This demonstration is with Java on an Ubuntu 12.10 terminal. Grabbing the password with STDIN is a good idea security wise, since the password is not exposed to command line history or within the processlist with ps
. The password letters typed are thrown away and not stored.
Java Code:
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.
}
}
Conditions if you use the above code
If super high security is your top priority don't even store that password in a
String
. Encrypt it immediately after receiving it from the user. That way if some clever person scans the memory of your program, they won't find your plaintext password there.If you try to run this program through a background job scheduler, then it is possible that
System.console().readPassword()
will return a NullPointerException which is a feature to enhance security. It denies access to shenanigans like virtual consoles and background tasks. If you want it to work right with virtual consoles see my other answer on this page.If you try to run this code through an IDE like Eclipse, Netbeans or any other virtual console, then
System.console().readPassword()
will throw a NullPointerException because no real console is found, and the program will halt. This is a feature, not a bug.
What is looks like on the console:
el@apollo:/home/el/test$ java Runner
Enter password:
Here we expose our password to STDOUT: foobarpassword
el@apollo:/home/el/test$
精彩评论