我正在开发一个仅在客户端执行加密/解密的应用程序。我正在使用Spring,jdk 1.6+和eclipse。我开发了一个包含加密代码的Applet:
public void accessToken(){
try{
File tmpConfigFile = File.createTempFile("pkcs11", "conf");
tmpConfigFile.deleteOnExit();
PrintWriter configWriter = new PrintWriter(new FileOutputStream(tmpConfigFile), true);
configWriter.println("name=eToken");
configWriter.println("library=" + "C:\\WINDOWS\\system32\\eTPKCS11.dll");
configWriter.println("slotListIndex=0");
configWriter.println("showInfo=true");
this.pkcs11Provider = new SunPKCS11(tmpConfigFile.getAbsolutePath());
Security.addProvider(this.pkcs11Provider);
CallbackHandler cbh = new DialogCallbackHandler();
KeyStore.Builder ksBuilder = KeyStore.Builder.newInstance("PKCS11", null, new KeyStore.CallbackHandlerProtection(cbh));
KeyStore ks = ksBuilder.getKeyStore();
ks.load(null, null);
}catch(Exception e){
e.printStackTrace();
}
}
我已经创建了jar文件并对其进行了签名,当我在eclipse本地机器上运行它作为“在Java Applet上运行”时它运行良好也很正常并且当我打开包含此内容的html页面时,它会在页面加载时提示输入密码小程序,但当我点击调用此accessToken()applet方法的复选框时,它会在java控制台上给出错误,如:
java.lang.SecurityException: Unable to create temporary file
at java.io.File.checkAndCreate(Unknown Source)
at java.io.File.createTempFile(Unknown Source)
at java.io.File.createTempFile(Unknown Source)
at message.MessageApplet.accessToken(MessageApplet.java:49)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at sun.plugin.javascript.JSInvoke.invoke(Unknown Source)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at sun.plugin.javascript.JSClassLoader.invoke(Unknown Source)
at sun.plugin2.liveconnect.JavaClass$MethodInfo.invoke(Unknown Source)
at sun.plugin2.liveconnect.JavaClass$MemberBundle.invoke(Unknown Source)
at sun.plugin2.liveconnect.JavaClass.invoke0(Unknown Source)
at sun.plugin2.liveconnect.JavaClass.invoke(Unknown Source)
at sun.plugin2.main.client.LiveConnectSupport$PerAppletInfo$DefaultInvocationDelegate.invoke(Unknown Source)
at sun.plugin2.main.client.LiveConnectSupport$PerAppletInfo$3.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at sun.plugin2.main.client.LiveConnectSupport$PerAppletInfo.doObjectOp(Unknown Source)
at sun.plugin2.main.client.LiveConnectSupport$PerAppletInfo$LiveConnectWorker.run(Unknown Source)
at java.lang.Thread.run(Unknown Source)
我的html页面如下:
<SCRIPT LANGUAGE="JavaScript">
function selectedCity()
{
var elem = document.getElementById('cityRb');
if(elem.checked)
{
document.messageApplet.accessToken();
}
}
</SCRIPT></HEAD>
<BODY >
<b>This is the Applet</b>
<script src="http://www.java.com/js/deployJava.js"></script>
<script>
<!-- applet id can be used to get a reference to the applet object -->
var attributes = { id:'messageApplet', code:'message.MessageApplet', width:1, height:1} ;
var parameters = {jnlp_href: 'message-applet.jnlp'} ;
deployJava.runApplet(attributes, parameters, '1.6');
</script>
<FORM NAME="CityChoice">
<input type="radio" id="cityRb" name="City" value="Boston" onClick="selectedCity()"> Boston<br>
</form>
</BODY >
和我的JNLP文件如下:
<jnlp spec="1.0+" codebase="" href="">
<information>
<title>Message Applet</title>
<vendor>Fountainhead</vendor>
<offline-allowed/>
</information>
<update check="background"/>
<security>
<all-permissions/>
</security>
<resources>
<!-- Application Resources -->
<j2se version="1.6+"
href="http://java.sun.com/products/autodl/j2se"/>
<jar href="message.jar" main="true" />
</resources>
<applet-desc
name="Message Applet"
main-class="message.MessageApplet"
width="300"
height="300">
</applet-desc>
<update check="background"/>
</jnlp>
所有文件和jar都在同一个目录中,我的applet类在消息文件夹中 请帮帮我,我被困在这里......
答案 0 :(得分:3)
之所以发生这种情况,是因为您是通过javascript调用applet的方法。实际上,当您从javascript调用任何已签名的applet方法时,它表现为无符号,因为它们都有自己的安全沙箱,您必须在该特定沙箱中执行。现在我已经对您的代码进行了如下更改。
final File myFile = (File) AccessController.doPrivileged(new PrivilegedAction() {
public Object run(){
String fileName = System.getProperty("user.home") +
System.getProperty("file.separator") +
"pkcs11.conf";
return new File(fileName);
}});
此AccessController允许您在客户端计算机上创建文件。我的英语不好,如果有任何错误,那就很抱歉。
答案 1 :(得分:2)
如果你从(unsigned)javascript中调用一个签名小程序内的函数,你将立即打破签名。这意味着applet通常会丢失所有权限,并且无法在磁盘上写任何内容......
在页面底部查看此内容:http://docs.oracle.com/javase/tutorial/deployment/applet/security.html
注意:JavaScript代码被视为无符号代码。签名时 applet是从HTML页面中的JavaScript代码访问的,applet是 在安全沙箱中执行。这意味着签署了 applet本质上就像是一个未签名的applet。**
所以你可能必须在init()之后立即启动你的函数,然后,通过liveconnect,回调页面上的js函数从applet通知“操作完成”......
答案 2 :(得分:0)
您也需要策略文件,以允许签名的applet创建临时文件。
请为您的代码添加行号,以便人们可以关联堆栈跟踪。
我认为代码File.createTempFile("pkcs11", "conf");
正在抛出SecurityException
。
请参阅从堆栈跟踪中获取的message.MessageApplet.accessToken(MessageApplet.java:49)
。
答案 3 :(得分:0)
您始终可以通过Javascript将数据提供给applet,以便将它们存储在FIFO(先进先出)对象中,并使用applet上的计时器检查FIFO并处理请求。但我想返回失败/成功代码值并不容易......