1

我在尝试在 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.");
        }
    }
}

安全测试:

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());
        }
    }

}

调用我:

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 确实存在,所以这部分肯定是有效的。

4

2 回答 2

2

问题出在您的安全管理器的 overridencheckExec中。cmd传递给的参数checkExec仅包含正在执行的命令中的第一个“单词”,因此在您的程序中,“java”是cmd参数。结果,字符串不以“java”开头,并且checkExec不执行 if 块,从而导致安全管理器进行“干净”检查。

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
}

此外,作为旁注,修改后的命令执行将导致 aStackOverflowError因为只有第一个“单词”被传递给该方法。

于 2012-08-31T03:33:38.997 回答
0

我知道代码并不意味着漂亮,但它似乎使用了黑名单方法,即“如果我们认识到这是一个不需要的模式,那么我们就会抛出一个异常。” 这对于现实世界来说不够健壮,它与实际问题有关('cmd' 不是你认为的那样)。

对于初学者,如果我们不想做一些特别的事情,在你的“if”块之后,应该有“else super.checkExec()”来运行常规处理。那会在那里解决你的问题。

于 2015-02-12T01:36:16.260 回答