【问题标题】:Preventing the JVM from writing to System.out or reading from System.in防止 JVM 写入 System.out 或从 System.in 读取
【发布时间】:2014-10-08 13:51:44
【问题描述】:

JVM 下是否有办法(暂时)阻止对 System.out、System.in 和 System.err 的完全访问?

创建一个完全不授予权限的空白策略后,我想在下面的函数中执行一些工作。 我希望对 System.out.println 等的调用失败,但他们没有。有什么我可以做的,还是我有点控制狂? p>

编辑 #1: 按照 MrPixelDream 的使用 System.setOut 的建议,我将权限保持在最低限度,以确保 run() 中的代码也不能调用 System.setOut 或与 @ 胡闹987654324@.

编辑#2:另外,由于恶意代码可以简单地执行standardOutput.println,我宁愿根本不保留对System.out 的引用,而是使用java.io.FileDescriptor.out 将其设置回来。

// Create blank permissions that barely allow executing code
java.security.Permissions perm = new java.security.Permissions();

// CodeSource domain for which these permissions apply (all files)
java.security.CodeSource code = new java.security.CodeSource(new java.net.URL("file:/*"),
                                                             null);

// ProtectionDomain
java.security.ProtectionDomain domain = new java.security.ProtectionDomain(code, perm);

// AccessControlContext
java.security.ProtectionDomain[] domains = new java.security.ProtectionDomain[1];
domains[0] = domain;

java.security.AccessControlContext context =
  new java.security.AccessControlContext(domains);

// DON'T keep reference to standard output, it could be used directly
// PrintStream standardOut = System.out;

// Redirect output to dummy stream
System.setIn(new ByteArrayInputStream(new byte[0]));
System.setOut(new PrintStream(new ByteArrayOutputStream()));
System.setErr(new PrintStream(new ByteArrayOutputStream()));

// Do an action, subject to the given security context
java.security.AccessController.doPrivileged(new java.security.PrivilegedAction<Void>() {

  public Void run() {

    // Do some work, side effects and all, but no I/O whatsoever
    System.out.println("Will not print !");

    // Try to fool around System.out with direct access from file descriptors (0, 1, 2)
    java.io.PrintStream myOut =
      new java.io.PrintStream(new java.io.FileOutputStream(java.io.FileDescriptor.out));

    // Missing permission java.lang.RuntimePermission "setIO"
    // Will throw java.security.AccessControlException
    System.setOut(myOut);

    // Missing permission java.lang.RuntimePermission "writeFileDescriptor"
    myOut.println("Will throw java.security.AccessControlException !");

  }

}, context);

// Now set back the old streams to have output again
System.setIn(new java.io.FileInputStream(java.io.FileDescriptor.in));
System.setOut(
  new java.io.PrintStream(new java.io.FileOutputStream(java.io.FileDescriptor.out)));
System.setErr(
  new java.io.PrintStream(new java.io.FileOutputStream(java.io.FileDescriptor.err)));

【问题讨论】:

  • “我是不是太控制狂了?”也许,你为什么要阻止它?
  • 长话短说,我正在使用 System.in/System.out 在这个受限的子 JVM 和它的父 JVM 之间进行通信。子 JVM 将用户提供的 javascript 代码提交给 Nashorn,并通过 System.out 将结果返回给父 JVM。如果 JavaScript 代码也要打印,它可能会扰乱我的沟通渠道。

标签: java security io permissions jvm


【解决方案1】:

我不相信有办法暂时做到这一点,但你可以阻止他们写入或读取,直到 JVM 重新启动,close()ing 他们用类似的东西,

public static void main(String[] args) {
    try {
        System.in.close();
    } catch (IOException e) {
        e.printStackTrace();
    }
    System.err.close();
    System.out.close();
    System.out.println("Must not print !");
}

并且有没有输出。

【讨论】:

    【解决方案2】:

    Elliott Frisch 的答案可以解决问题,但执行后您无法收到输出。如果您打算暂时静音输出,请使用以下代码:

    public class RedirectedOutput {
    
        public static void main(String[] args) {
            // Save the old output stream to have the chance to set it back later
            InputStream standardIn  = System.in;
            PrintStream standardOut = System.out;
            PrintStream standardErr = System.err;
    
            // Set useless streams
            System.setIn(new ByteArrayInputStream(new byte[0]));
            System.setOut(new PrintStream(new ByteArrayOutputStream()));
            System.setErr(new PrintStream(new ByteArrayOutputStream()));
    
            // Will not be shown
            System.out.println("Hello World");
    
            // Now set back the old streams to have output again
            System.setIn(standardIn);
            System.setOut(standardOut);
            System.setErr(standardErr);
    
            // Will be shown again
            System.out.println("Finally we got the Hello");
        }
    
    }
    

    你可以试试这个应该是完全可运行的例子。它应该是不言自明的。您正在使用setIn()setOut()setErr() 更改流,并在之前保存它以便能够将其重新设置。

    但如果您不需要任何输出,那么您最好使用 Elliott 的代码,因为我想它对资源更好。

    【讨论】:

    • 自从 Elliot 的回答以来,我得出了类似的结果,但我将 System.out 设置为 null,这需要我捕获异常。您的解决方案通过提供临时虚拟流,避免了执行代码的失败并且令人满意。当然,就资源而言,没有什么能阻止执行的代码以各种方式膨胀堆。
    • 感谢您总结您的想法,当然也感谢您接受我的回答。很高兴能提供帮助。
    • 请注意,如果没有适当的策略,您的代码可以,但无法包含流氓代码。我已经相应地更新了我的问题。
    猜你喜欢
    • 1970-01-01
    • 2022-10-12
    • 2017-04-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-08-25
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多