2010-01-06 58 views
0

我想创建一个java jar applet,它将在浏览器中运行,从URL下载图像并将其显示给用户。 我的实现是:在jar中加载web图像时的安全异常

try { 
    String imageURL = "http://www.google.com/intl/en_ALL/images/logo.gif"; 
    URL url = new URL(imageURL); 
    img = ImageIO.read(url); 
    } catch (IOException e) { 
    System.out.println(e); 
    } 

但它给我一个安全异常:

java.security.AccessControlException: access denied (java.net.SocketPermission www.google.com:80 connect,resolve) 

解决方案:

我已经实现了刀 - 动作 - 耶稣的建议,并且它在网页浏览器中工作(但不使用小程序查看器)。

只有与applet查看我还是会遇到:

java.security.AccessControlException: access denied (java.net.SocketPermission www.google.com:80 connect,resolve) 

当加载网页在浏览器中,有一个信托/拒绝对话框,如果我单击信任,然后将图像显示出来。

这些是我采取的步骤:

ant makejar 
jarsigner -keystore keystore-name -storepass password -keypass password web/LoadImageApp.jar alias-name 
jarsigner -verify -verbose web/LoadImageApp.jar 
appletviewer web/index.html ## as mentioned above, this gives a security exception. instead, load the webpage in a browser. 

的输出的jarsigner -verify是:

Warning: The signer certificate will expire within six months. 

     332 Thu Jan 07 20:03:38 EST 2010 META-INF/MANIFEST.MF 
     391 Thu Jan 07 20:03:38 EST 2010 META-INF/ALIAS-NA.SF 
     1108 Thu Jan 07 20:03:38 EST 2010 META-INF/ALIAS-NA.DSA 
sm  837 Thu Jan 07 20:03:38 EST 2010 LoadImageApp$1.class 
sm  925 Thu Jan 07 20:03:38 EST 2010 LoadImageApp.class 
sm  54 Wed Jan 06 01:28:02 EST 2010 client.policy 

    s = signature was verified 
    m = entry is listed in manifest 
    k = at least one certificate was found in keystore 
    i = at least one certificate was found in identity scope 

jar verified. 

以下是完整的Java源代码(强调的概念,我删除了所有额外的异常处理/ null检查):

import java.awt.*; 
import java.awt.image.*; 
import javax.imageio.*; 
import javax.swing.*; 
import java.net.*; 
import java.security.*; 

public class LoadImageApp extends JApplet 
{ 
    private BufferedImage img; 
    private final String imageURL = "http://www.google.com/intl/en_ALL/images/logo.gif"; 

    public void init() 
    { 
    loadImage(); 
    } 

    public void paint(Graphics g) 
    { 
    if (null != img) { g.drawImage(img, 0, 0, null); } 
    } 

    public void loadImage() 
    { 
    AccessController.doPrivileged(new PrivilegedAction() 
    { 
     public Object run() 
     { 
     try 
     { 
      URL url = new URL(imageURL); 
      if (null == url) 
      { 
      throw new MalformedURLException(); 
      } 
      img = ImageIO.read(url); 
     } 
     catch (Exception e) { e.printStackTrace(); } 
     return null; 
     } 
    }); 
    } 

} 
+0

什么是上下文?它是一个小程序吗? – 2010-01-06 14:38:28

+0

(我建议不要规避安全策略,除非你真的知道你在做什么。) – 2010-01-06 14:39:12

+0

是的,我应该指定我试图在网站上制作一个小程序。 目前的解决方法是在jar中最糟糕的情况下包含所有可能使用的图像,这会导致瓶子膨胀。 – dsg 2010-01-06 20:57:49

回答

2

由于默认情况下,applet加载到沙盒安全中,因此您会遇到异常,沙盒只允许您将url连接到为该applet提供服务的域。意思是你不能创建一个到谷歌的网址,除非你的applet是由google托管的。

您需要执行以下操作才能正确连接到远程URL。

至少创建一个自签名证书,理想情况下,您有一个经过验证的证书,通过verisign或您选择的某个其他证书颁发机构(CA)进行链接。 Certificate Instructions

使用jarsigner签名你的jar。 Signing Instructions

现在你可以用在一个特权块代码如下

try 
{ 
    final String imageURL = "http://www.google.com/intl/en_ALL/images/logo.gif"; 
    URL url = (URL) AccessController.doPrivileged(new PrivilegedAction() 
    { 

     public Object run() 
     { 
      try 
      { 
       return new URL(imageURL); 
      } 
      catch (MalformedURLException e) 
      { 
       e.printStackTrace(); 
       return null; 
      } 

     } 
    }); 

    if(url == null) 
    { 
     // Something is wrong notify the user 
    } 
    else 
    { 
     // We know the url is good so continue on 
      img = ImageIO.read(url); 
    } 

} 
catch (IOException e) 
{ 
    System.out.println(e); 
} 

我导入了applet代码,我换了一些它周围,拉动IMG实例出具有块中的特权块&的返回一个网址。当我将它加载到网页浏览器时,这起作用。

import java.applet.Applet; 
import java.awt.*; 
import java.awt.image.*; 
import javax.imageio.*; 
import javax.swing.*; 

import java.io.IOException; 
import java.net.*; 
import java.security.AccessController; 
import java.security.PrivilegedAction; 

public class LoadImageApp extends Applet 
{ 
    private BufferedImage img; 
    private final String imageURL = "http://www.google.com/intl/en_ALL/images/logo.gif"; 

    public void init() 
    { 
    loadImage(); 
    } 

    public void paint(Graphics g) 
    { 
    if (null != img) { g.drawImage(img, 0, 0, null); } 
    } 

    public void loadImage() 
    { 
    URL url = (URL) AccessController.doPrivileged(new PrivilegedAction() 
    { 
     public Object run() 
     { 
     try 
     { 
      return new URL(imageURL); 
     } 
     catch (Exception e) { e.printStackTrace(); } 
     return null; 
     } 
    }); 

    try { 
     img = ImageIO.read(url); 
    } catch (IOException e) { 
    e.printStackTrace(); 
    } 

    } 
} 
+0

您的证书指令链接为TLTR,因此我遵循以下步骤:http://www.cs.princeton.edu/introcs/85application/jar/sign.html 首先修改代码,然后签署jar,然后尝试通过appletviewer执行它,我仍然遇到同样的异常。 – dsg 2010-01-06 21:04:38

+0

您需要在特权块中包装的代码中可能还有其他地方。一旦你签署你的jar,确保你的验证。用jarsigner工具。如果它被验证,那么唯一的其他问题就是你在需要许可的代码中所做的事情。 事情就像复制到剪贴板 在客户端机器上写入文件 需要权限,如果您不确定如何包装其他代码块发布它,我可以尝试和帮助更多。 – Keibosh 2010-01-07 14:00:39

+0

感谢您的承诺,KAJ!我已经在上面包含了我的源代码。 – dsg 2010-01-08 01:10:16

-1
  1. 在罐子的同一文件夹中创建一个文件叫“policy.all”
  2. 复制/粘贴在它下面的文字:

    授予{权限java.security.AllPermission;};

  3. 中启动应用程序是这样的:

    Java的罐子yourjar.jar -Djava.security.policy = policy.all

+1

除了您自己的测试之外,您不应该使用策略文件。授予所有权限是非常危险的,因为只要您授予他们访问的恶意网站权限,即可在他们选择的计算机上执行任何操作。即使使用自签名证书签名也很容易。 – Keibosh 2010-01-06 15:39:13

-1

听起来你不要尝试创建将从命令行运行的jar文件,而是将在浏览器中执行的小程序。如果这是真的,那么你几乎没有运气,因为applet只允许访问它们已经加载的服务器。如果你真的想从applet访问其他服务器,你必须签名你的applet; Google可以帮助您找到更多信息。

+0

它不会帮助他,如果他试图做一个小程序... – 2010-01-06 10:13:16

+0

当然会。如果他真的想在一个小程序中做到这一点,他现在知道他必须签署他的小程序来标记它的工作。 – Bombe 2010-01-06 11:50:21

+0

我的确在尝试制作一个将在浏览器中执行的小程序。 – dsg 2010-01-06 20:59:33

0

看来你运行的是一个applet而不是一个普通的应用程序。不允许小程序从其加载的域之外检索任何资源。这个想法是为了防止“坏”应用程序调用类似于

 
String targetURL = "http://www.foo.bar/spoof?source" + System.getProperty("...); 

或将其他类型的数据传输到未知目标。

如果您确实需要检索外部数据,您必须符号您的小程序。

+0

实际上'AppletContext.showDocument'并不局限于同源策略,比如JavaScript(可以通过调用JavaScript等价物来实现)。 'javax.jnlp'中也有类似的方法。 – 2010-01-06 14:37:52