Java 防止JVM写入System.out或读取System.in
JVM下是否有(暂时)阻止完全访问System.out、System.in和System.err的方法 在创建了一个完全不授予权限的空白策略之后,我想在下面的函数中执行一些工作我希望调用System.out.println之类的函数失败,但它们没有失败。我能做些什么,还是我有点太过控制狂了 编辑#1:按照PixelDream先生的建议使用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
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代码也打印出来,它可能会扰乱我的通信渠道。