How to use Scanner to read silently from STDIN in Java?

戏子无情 提交于 2019-11-29 17:44:35

问题


I want to make a Java program that reads a Password from STDIN silently. I mean, without outputting any pressed chars to the terminal and keeping it hidden from commandline history and the operating system processlist ps.


回答1:


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.




回答2:


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$



回答3:


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".




回答4:


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

  1. 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.

  2. 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.

  3. 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$ 


来源:https://stackoverflow.com/questions/2893218/how-to-use-scanner-to-read-silently-from-stdin-in-java

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!