我在尝试在Java安全管理器中实现安全检查时遇到问题。
我似乎误解了安全管理器中checkExec()方法的用途。我认为当我的应用程序试图通过命令行调用另一个Java应用程序时会调用它,但这似乎不会发生。
以下是我想要发生的事情:使用我的自定义安全管理器的调用应用程序在命令行上执行“java SomeApp”。安全管理器检查这是否正常并执行适当的操作。
为了尝试实现这一目标,我做了以下事情:
1)创建了一个自定义安全管理器,它覆盖了checkExec方法。方法签名是“public void checkExec(String cmd)”。
2)创建了一个测试类SecurityTest。
3)SecurityTest将我的自定义安全管理器指定为其安全管理器。
4)SecurityTest然后在命令行上运行“java InvokeMe”。
5)自定义安全管理器拦截此操作并执行某些操作。
1到4很好,但5从未发生过。我已经验证我的自定义安全管理器是有效的,它已成功分配给SecurityTest,SecurityTest成功运行InvokeMe。但是,我能够辨别出自定义安全管理器中的checkExec()方法。
我哪里错了?我正在尝试做什么(让安全管理器在应用程序调用“Java SomeApp”时做某事)甚至可能吗?
感谢您的时间。
修改
以下是运行测试所产生的一些代码和输出。这是一种快速原型风格,“将其打开并清理后来”的样式代码,因此它不会很漂亮:
自定义安全管理器:
import java.util.*;
import java.io.*;
class DTESecurityManager extends SecurityManager {
// instance variables
DTESecurityManager() {
super();
//assign a bunch of variables
System.out.println("TEST 1");
}
public void checkExec(String cmd) {
if (cmd.toLowerCase().startsWith("java ")) {
if (cmd.matches("(?i).*-djava.security.manager.*")) {
throw new SecurityException("Cannot assign a security manager to invoked Java applications.");
}
StringBuffer intermediateCommand = new StringBuffer(cmd).insert(5, "-Djava.security.manager=DTESecurityManager ");
String modifiedCommand = new String(intermediateCommand);
try {
Runtime rt = Runtime.getRuntime();
Process pr = rt.exec(modifiedCommand);
} catch (Exception e) {
System.err.println("Error: " + e.getMessage());
}
try {
FileWriter fstream = new FileWriter("Verification.txt");
BufferedWriter out= new BufferedWriter(fstream);
out.write("I worked.");
out.close();
} catch (Exception e) {
System.err.println("Error: " + e.getMessage());
}
throw new SecurityException("Command was executed, but was modified to force invoked application to use this security manager.");
}
}
}
SecurityTest:
import java.io.*;
class SecurityTest {
public static void main(String[] args) {
try {
System.setSecurityManager(new DTESecurityManager());
} catch (Exception e) {
System.out.println("Error: " + e.getMessage());
}
try {
System.out.println("If we got this far, we had no problems setting our security manager.");
System.out.println("Now let's try to invoke another Java application.");
Runtime rt = Runtime.getRuntime();
Process pr = rt.exec("java InvokeMe");
System.out.println("I reached the end of my test without crashing. Now terminating.");
} catch (Exception e) {
System.out.println("Exception message: " + e.getMessage());
}
}
}
InvokeMe:
import java.io.*;
class InvokeMe {
public static void main(String[] args) {
System.out.println("I, InvokeMe, have been invoked successfully.");
try {
FileWriter fstream = new FileWriter("InvokeMeWasCalled.txt");
BufferedWriter out= new BufferedWriter(fstream);
out.write("It worked.");
out.close();
} catch (Exception e) {
System.err.println("Error: " + e.getMessage());
}
}
}
测试输出:
TEST 1
If we got this far, we had no problems setting our security manager.
Now let's try to invoke another Java application.
I reached the end of my test without crashing. Now terminating.
没有迹象表明checkExec()被调用 - 没有控制台输出,Verification.txt在我的文件系统的任何地方都不存在。 (当然,在执行这样的操作时,我不确定安全管理器子类的行为应该是什么 - 所以也许这是正常的。如果是这样的话,我需要另一种快速而肮脏的方法来测试我是否“我遇到了某些代码行。”InvokeMeWasCalled.txt确实存在,因此该部分肯定有效。
答案 0 :(得分:2)
问题出在您的安全管理员的覆盖checkExec
中。传递给cmd
的{{1}}参数仅包含正在执行的命令中的第一个“单词”,因此在您的程序中,“java”是checkExec
参数。因此,字符串不以“java”开头,cmd
不执行if块,导致安全管理器进行“干净”检查。
checkExec
另外,作为旁注,修改后的命令执行将导致public void checkExec(String cmd) {
System.out.println(cmd); // prints "java"
if (cmd.toLowerCase().startsWith("java ") { ... } // is false
// no security exception is thrown, allowing your command
}
,因为只有第一个“单词”被传递给方法。
答案 1 :(得分:0)
我知道代码不是很漂亮,但似乎是使用黑名单方法,即"如果我们认识到这是一个不需要的模式,那么我们抛出异常。&# 34;这对现实世界来说还不够强大,而且它与实际问题有关(' cmd'并不意味着你的想法)。
对于初学者来说,在' if'之后块,应该有'否则super.checkExec()'如果我们不想做一些特别的事情,可以进行常规处理。那会在那里找到你的问题。