Java中如何从配置文件读取密码并传递给需root权限的进程
我有一个secrets.properties配置文件,里面包含USER_PW=xxx配置项,希望将该密码传递给需要root权限的执行进程,但尝试两种方式均失败:
- 第一种用管道传递密码,结果密码直接打印到终端,并未通过管道传给sudo;
- 第二种想用
<<<传递密码,终端中正确的命令是sudo -S <<< "password" echo Test,但在ProcessBuilder里无论怎么加引号都无法实现,仍会触发sudo的密码提示。
以下是两段问题代码:
第一段代码:
// Process Builder ProcessBuilder pb = new ProcessBuilder(); String cmd = "cp"; String tableName = "password_entries.ibd"; String source = properties.getProperty("DB_PATH"); String target = "."; String userPassword = secrets.getProperty("USER_PW"); try { pb.inheritIO(); // elevate privileges to root pb.command("echo", userPassword, "|", "sudo", "-S", "echo", "test"); pb.start().waitFor(); // cp to host pb.command("sudo", "-S", cmd, source + tableName, target); pb.start().waitFor(); } catch (IOException | InterruptedException e) { throw new RuntimeException(e); }
第二段代码:
// Process Builder ProcessBuilder pb = new ProcessBuilder(); String cmd = "cp"; String tableName = "password_entries.ibd"; String source = properties.getProperty("DB_PATH"); String target = "."; String userPassword = secrets.getProperty("USER_PW"); try { pb.inheritIO(); // elevate privileges to root pb.command("sudo", "-S", "<<<", userPassword, "echo", "test"); pb.start().waitFor(); // cp to host pb.command("sudo", "-S", cmd, source + tableName, target); pb.start().waitFor(); } catch (IOException | InterruptedException e) { throw new RuntimeException(e); }
问题根源
ProcessBuilder是直接启动进程的工具,不解析管道|、here-string<<<这类shell专属语法。你之前的代码里,|和<<<都被当成了命令的普通参数,自然达不到预期效果。
正确实现方式
推荐用直接向sudo的输入流写入密码的方式,安全且可靠,不会把密码暴露在进程列表中:
ProcessBuilder pb = new ProcessBuilder(); String cmd = "cp"; String tableName = "password_entries.ibd"; String source = properties.getProperty("DB_PATH"); String target = "."; String userPassword = secrets.getProperty("USER_PW"); try { // 测试sudo权限 pb.command("sudo", "-S", "echo", "test"); // 只继承输出和错误流,手动控制输入流 pb.redirectError(ProcessBuilder.Redirect.INHERIT); pb.redirectOutput(ProcessBuilder.Redirect.INHERIT); Process testProcess = pb.start(); // 向sudo输入密码,必须加换行(sudo需要回车确认) try (OutputStream os = testProcess.getOutputStream()) { os.write((userPassword + "\n").getBytes()); os.flush(); } testProcess.waitFor(); // 执行cp命令 pb.command("sudo", "-S", cmd, source + tableName, target); Process cpProcess = pb.start(); try (OutputStream os = cpProcess.getOutputStream()) { os.write((userPassword + "\n").getBytes()); os.flush(); } cpProcess.waitFor(); } catch (IOException | InterruptedException e) { throw new RuntimeException(e); }
如果非要用shell语法(不推荐,密码可能通过进程列表泄露),可以让bash执行整个命令:
ProcessBuilder pb = new ProcessBuilder(); String cmd = "cp"; String tableName = "password_entries.ibd"; String source = properties.getProperty("DB_PATH"); String target = "."; String userPassword = secrets.getProperty("USER_PW"); try { // 测试命令:用bash执行管道逻辑 String testCmd = String.format("echo '%s' | sudo -S echo test", userPassword.replace("'", "'\\''")); pb.command("/bin/bash", "-c", testCmd); pb.inheritIO(); pb.start().waitFor(); // cp命令 String cpCmd = String.format("echo '%s' | sudo -S %s %s%s %s", userPassword.replace("'", "'\\''"), cmd, source, tableName, target); pb.command("/bin/bash", "-c", cpCmd); pb.start().waitFor(); } catch (IOException | InterruptedException e) { throw new RuntimeException(e); }
注意要转义密码里的单引号,避免shell解析出错。
内容的提问来源于stack exchange,提问作者max23
相关产品推荐
相关产品推荐

