PrivilegedActionException 试图从 JavaScript 调用签名的 Java applet

PrivilegedActionException trying to invoke a signed Java applet from JavaScript

首先,我不是 Java 开发人员。我必须创建一个 Java 小程序来调用我从浏览器编写的本机 DLL 中的一些代码。

我使用 JNA 加载本机 DLL 并调用其方法。
我已经使用自签名证书对小程序进行了签名。
浏览器询问是否允许小程序执行
加载我的 DLL 的小程序代码包含在 AccessController.doPrivileged 块中。

像这样:

public String Test()
{
    pHelper = AccessController.doPrivileged(new PrivilegedAction<IHelper>() 
    {
        @Override
        public IHelper run() 
        {
            return (IHelper)Native.loadLibrary("Helper", IHelper.class);
        }
    });

    return "test";
}

代码在 Eclipse 中调试时工作正常。

从 JavaScript 调用时不起作用。 导致 PrivilegedActionException。

如果我删除整个 AccessController.doPrivileged 块并仅保留 return "test",则从 JavaScript 调用时代码 运行s。从 JavaScript.

调用时,任何不需要权限的代码 运行 都可以

在 Chrome 版本 40.something 和 Firefox 36 Windows 8.1 64 位上测试。 本机 DLL 和用于 运行 小程序的 JRE 都是 32 位的。

有什么建议吗?

我从来没有解开这个特别的谜团。但是,由于我的 applet 设计规范不需要公开任何需要调用以执行特权操作的 applet 方法,我找到了解决方法。

我发现在 applet init() 函数中执行特权操作会起作用。只有通过从 JavaScript 调用执行的特权操作似乎会导致问题。考虑以下代码。

public class MyApplet extends JApplet {
    private IHelper pHelper = null;
    private MyReturnedInfo pInfo = null;

    public void init() {
        pHelper = (IHelper)Native.loadLibrary("Helper", IHelper.class);
        if (pHelper != null) {
            pInfo = pHelper.GetInfo();
        }
    }

    public String GetInfoString() {
        if (pInfo != null) {
            // need to call toString to convert from native wide char to something JavaScript will be able to interpret
            return pInfo.MyInfoString.toString(); 
        }
        return null;
    }
}

加载此小程序后,从 Java脚本调用 document.myApplet.GetInfoString()(假设小程序具有 ID "myApplet")将 return 所需信息。

有趣的是,在使用 VeriSign 等受信任机构颁发的证书对小程序进行签名后,即使这样在 IE 中也不起作用,但在 FF 和Chrome。我已经看到签名的 Java 小程序在 IE 中从 JavaScript 调用时工作正常,但我想我的小程序很特别,因为它需要清单中的 all-permissions 属性,而 IE 可能不需要像那样。这是一个猜测。但是,我也从未找到真正的原因,因为我能够求助于另一种解决方法。 :) 如果您正在阅读此答案,那么我敢打赌您也对此感兴趣。

Java 小程序允许我们提供额外的参数,我们可以通过从 init() 函数内部调用 this.getParameter() 来获取这些参数。此外,如果我们允许小程序通过使用 mayscript 属性从我们的 HTML 文档调用 JavaScript 函数,我们可以轻松地将这两个事实结合起来以提供 JavaScript 函数用于在获取本机 DLL 的信息后调用小程序。

假设在我们的HTML中,我们这样定义Java脚本。

<script type="text/javascript" src="https://www.java.com/js/deployJava.js"></script>
<script type="text/javascript">
    var attributes = {
        id: "myApplet",
        name: "myApplet",
        code: "MyApplet.class",
        mayscript: "true",
        scriptable: "true",
        archive: "/path(s)/to/jar(s)",
        width: 0,
        height: 0
   };

    var params = {
        "AppletReady": "appletInitialized",
    };

    // For convenience, it's easier to deploy the applet using deployJava,
    // so it writes the applet HTML tag for us after checking if Java is installed.
    // We have included it above.
    deployJava.runApplet(attributes, params, "1.8.0");

    function appletInitialized(myString, someOtherArgument) {
        // do something with your parameters
        // NOTE: do NOT call alert() from this function! 
        // Because it will most likely cause your browser to freeze, 
        // I've found that's also one of the things Java doesn't like.
    };
</script>

然后,我们修改Java小程序代码如下。

public class MyApplet extends JApplet {
    private IHelper pHelper = null;
    private MyReturnedInfo pInfo = null;

    public void init() {
        // Read the AppletReady parameter as passed from JavaScript
        String paramKey = "AppletReady";
        String jsLoadedCallback = this.getParameter(paramKey);

        // Load the library and get the information
        pHelper = (IHelper)Native.loadLibrary("Helper", IHelper.class);
        if (pHelper != null) {
            pInfo = pHelper.GetInfo();
            if (pInfo != null && jsLoadedCallback != null) {
                // Get the window which contains "this" applet
                JSObject jsObject = JSObject.getWindow(this);

                // Call the provided JavaScript function.
                // You can use as many parameters as you need.
                jsObject.call(jsLoadedCallback, new Object[] {
                        pInfo.MyInfoString.toString(),
                        pInfo.SomeOtherStringMaybe.toString()
                });
            }
        }
    }
}

但是,如果您需要小程序在运行时动态调用您的本机 DLL 方法(即您需要小程序公开需要调用以动态执行特权操作的函数),此解决方案将不适合您和您运气不好,至少如果使用 JNA。