Java 防止JVM写入System.out或读取System.in

Java 防止JVM写入System.out或读取System.in,java,security,io,permissions,jvm,Java,Security,Io,Permissions,Jvm,JVM下是否有(暂时)阻止完全访问System.out、System.in和System.err的方法 在创建了一个完全不授予权限的空白策略之后,我想在下面的函数中执行一些工作我希望调用System.out.println之类的函数失败,但它们没有失败。我能做些什么,还是我有点太过控制狂了 编辑#1:按照PixelDream先生的建议使用System.setOut,我将权限保持在最低限度,以确保run()中的代码也不能调用System.setOut或玩弄java.io.FileDescripto

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

在创建了一个完全不授予权限的空白策略之后,我想在下面的函数中执行一些工作我希望调用System.out.println之类的函数失败,但它们没有失败。我能做些什么,还是我有点太过控制狂了

编辑#1:按照PixelDream先生的建议使用
System.setOut
,我将权限保持在最低限度,以确保
run()中的代码也不能调用
System.setOut
或玩弄
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)));
编辑#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)));
//创建几乎不允许执行代码的空白权限
java.security.Permissions perm=新建java.security.Permissions();
//应用这些权限的CodeSource域(所有文件)
java.security.CodeSource=new java.security.CodeSource(new java.net.URL(“文件:/*”),
无效);
//保护域
java.security.ProtectionDomain=new java.security.ProtectionDomain(代码,perm);
//AccessControlContext
java.security.ProtectionDomain[]domains=new java.security.ProtectionDomain[1];
域[0]=域;
java.security.AccessControlContext上下文=
新的java.security.AccessControlContext(域);
//不要引用标准输出,它可以直接使用
//PrintStream standardOut=System.out;
//将输出重定向到虚拟流
setIn(新的ByteArrayInputStream(新的字节[0]);
系统放样(新打印流(新ByteArrayOutputStream());
System.setErr(新的PrintStream(newbytearrayoutputstream());
//根据给定的安全上下文执行操作
java.security.AccessController.doPrivileged(新java.security.PrivilegedAction(){
公开募捐{
//做一些工作,副作用和所有,但没有任何I/O
System.out.println(“将不打印!”);
//尝试从文件描述符(0、1、2)直接访问System.out
java.io.PrintStream myOut=
新的java.io.PrintStream(新的java.io.FileOutputStream(java.io.FileDescriptor.out));
//缺少权限java.lang.RuntimePermission“setIO”
//将抛出java.security.AccessControlException
系统放样(myOut);
//缺少权限java.lang.RuntimePermission“writeFileDescriptor”
println(“将抛出java.security.AccessControlException!”);
}
},上下文);
//现在,将旧的流设置回有输出
setIn(新的java.io.FileInputStream(java.io.FileDescriptor.in));
系统放样(
新的java.io.PrintStream(新的java.io.FileOutputStream(java.io.FileDescriptor.out));
System.setErr(
新的java.io.PrintStream(新的java.io.FileOutputStream(java.io.FileDescriptor.err));

我认为暂时没有办法做到这一点,但在JVM重新启动之前,您可以通过
close()
对它们进行如下操作来防止它们写入或读取:

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 !");
}

而且没有输出。

艾略特·弗里希的回答会起作用,但你做了之后就不能收到输出。如果要暂时禁用输出,请使用以下代码:

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,这要求我捕获异常。您的解决方案,通过提供一个临时的虚拟流,避免了执行代码的失败,是令人满意的。当然,就资源而言,没有什么可以阻止执行的代码以各种方式在堆中膨胀。感谢您总结您的想法,当然也感谢您接受我的回答。很高兴提供帮助。请注意,您的代码可以,但如果没有适当的策略,将无法包含恶意代码。我相应地更新了我的问题。“我是不是太喜欢控制了?”也许,你为什么要阻止它?长话短说,我使用System.in/System.out在这个受限制的子JVM和它的父JVM之间进行通信。子JVM将用户提供的javascript代码提交给Nashorn,并通过System.out将结果返回给父JVM。如果javascript代码也打印出来,它可能会扰乱我的通信渠道。