简体   繁体   English

在jar中加载Web图像时的安全异常

[英]security exception when loading web image in jar

I am trying to create a java jar Applet that will run in a browser, download an image from a URL, and display it to the user. 我试图创建一个将在浏览器中运行的Java jar Applet,从URL下载图像并将其显示给用户。 My implementation is: 我的实现是:

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

But it gives me a security exception: 但这给了我一个安全例外:

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

Solution: 解:

I have implemented Knife-Action-Jesus's suggestion, and it works in a web browser (but not using the applet viewer). 我已经实现了Knife-Action-Jesus的建议,并且可以在Web浏览器中使用(但不能使用applet查看器)。

Only with the applet viewer I still encounter: 仅使用applet查看器,我仍然会遇到:

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

When loading the web page in a browser, there is a Trust/Deny dialogue box, if I click Trust, then the image shows up. 在浏览器中加载网页时,有一个“信任/拒绝”对话框,如果单击“信任”,则会显示该图像。

These are the steps that I'm taking: 这些是我正在采取的步骤:

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.

The output from jarsigner -verify is: 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.

The following is the complete java source code (to emphasize the concept, I removed all that extra exception handling/null checking) : 以下是完整的Java源代码(为强调这一概念,我删除了所有多余的异常处理/空检查):

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

}

Your running into the exception because by default applets load into sandbox security, Sandbox only allows you to make url connections to the domain serving the applet. 遇到异常是因为默认情况下,小程序会加载到沙箱安全性中,因此,沙箱仅允许您与服务小程序的域建立url连接。 Meaning you cannot create a url connection to google unless you applet is hosted by google. 这意味着除非您的applet由google托管,否则您无法创建与google的url连接。

You need to do the following in order to properly connect to a remote url. 您需要执行以下操作才能正确连接到远程URL。

Create a self signed certificate at least, Ideally you have a verified certificate linking back through verisign or some other certificate authority (CA) of your choosing. 至少创建一个自签名证书,理想情况下,您具有通过verisign或您选择的其他证书颁发机构(CA)链接回的经过验证的证书。 Certificate Instructions 证书说明

Sign your jar using jarsigner. 使用jarsigner签名您的jar。 Signing Instructions 签名说明

Now you can wrap your code in a privileged block as follows 现在,您可以将代码包装在特权块中,如下所示

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

I imported your applet code, I switched some of it around, Pulling the img instantiation out of the privileged block & having the block return a url. 我导入了您的applet代码,并进行了一些切换,将img实例从特权块中拉出并让该块返回一个url。 This works when I load it into a webbrowser. 当我将其加载到Web浏览器中时,此方法有效。

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

  }
}

It seems you're running an applet instead of a normal application. 看来您正在运行的是applet,而不是普通的应用程序。 An applet is not allowed to retrieve any resources outside the domain it has been loaded from. 小程序不允许从其加载的域中检索任何资源。 The idea is to prevent "bad" applications from calling something like 这个想法是为了防止“不良”应用程序调用类似

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

or transfering other kinds of data to an unknown destination. 或将其他类型的数据传输到未知目的地。

If you really need to retrieve external data you have to sign your applet. 如果确实需要检索外部数据,则必须对小程序签名

  1. Create a file call "policy.all" in the same folder of your jar 在jar的同一文件夹中创建一个名为“ policy.all”的文件
  2. copy/paste the following text in it : 复制/粘贴以下文本:

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

  3. Start application like this : 像这样启动应用程序:

    java -jar yourjar.jar -Djava.security.policy=policy.all java -jar yourjar.jar -Djava.security.policy = policy.all

Sounds like you're not trying to create a jar file which will be run from the command line but an applet which will be executed in the browser. 听起来好像您不是要创建将通过命令行运行的jar文件,而是要在浏览器中执行的applet。 If that is true, you're pretty much out of luck because applets are only allowed to access the server they have been loaded from. 如果是这样,那么您将很不走运,因为小应用程序仅被允许访问从中加载它们的服务器。 If you really want to access other servers from an applet, you have to sign your applet; 如果您确实要从小程序访问其他服务器,则必须对小程序进行签名; Google can help you find more information. Google可以帮助您找到更多信息。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM