【问题标题】:How to use Scanner to read silently from STDIN in Java?如何使用 Scanner 从 Java 中的 STDIN 静默读取?
【发布时间】:2011-02-23 00:10:20
【问题描述】:

我想制作一个从 STDIN 静默读取密码的 Java 程序。我的意思是,不向终端输出任何按下的字符并将其隐藏在命令行历史和操作系统进程列表ps 中。

【问题讨论】:

    标签: java stdin java.util.scanner


    【解决方案1】:

    类 java.io.Console 可能有用:

    System.console().readPassword();
    

    这会从控制台读取一系列字符,而不会回显任何内容。 请注意,它仅在您使用真实控制台启动 java 应用程序时才有效。否则,System.console() 返回 null。

    【讨论】:

    • @Nazgulled:恐怕不是(至少在 Eclipse 中)...根据stackoverflow.com/questions/104254/…,从 Eclipse IDE 中打开进程控制台是不可能的。我不确定 NetBeans。
    • 刚刚测试了一下,NetBeans也是这样。
    【解决方案2】:

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

    使用上述代码的条件

    1. 如果超高安全性是您的首要任务,甚至不要将该密码存储在 String 中。从用户那里收到后立即加密。这样一来,如果某个聪明的人扫描了你的程序的内存,他们就不会在那里找到你的明文密码。

    2. 如果您尝试通过后台作业调度程序运行此程序,则System.console().readPassword() 可能会返回 NullPointerException,这是一项增强安全性的功能。它拒绝访问虚拟控制台和后台任务等恶作剧。如果您希望它与虚拟控制台一起正常工作,请参阅我在此页面上的其他答案。

    3. 如果您尝试通过 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$ 
    

    【讨论】:

      【解决方案3】:

      通过 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$
      

      【讨论】:

      • 我相信第二个条件 (System.console() != null) 在这里只能是假的,不是吗?所以 System.console().readLine() 永远不会被调用....
      • 为什么这个选项不太安全?
      • @idelvall 最后一句:“回退到使用 BufferedReader,在某些情况下,当用户键入密码时,它会将密码暴露在屏幕上”...
      【解决方案4】:

      您可能想看看java.io.Console

      它有一个 readPassword 方法,可以“从控制台读取密码或密码,并禁用回显”。

      【讨论】:

        猜你喜欢
        • 2013-11-11
        • 2012-08-05
        • 2017-01-18
        • 1970-01-01
        • 1970-01-01
        • 2023-03-15
        • 1970-01-01
        • 2011-07-07
        相关资源
        最近更新 更多