作者:mingjava 文章来源:http://www.j2medev.com/Article/ShowArticle.asp?ArticleID=271
本章将主要介绍MIDP的安全体系模型,并将结合一个具体的实例来讲述MIDP2.0安全模型的主要概念。
8.1 引入全新安全体系的原因J2ME平台的主要优势之一是平台的开放性,这使得任何人都能够编写可以运行在MIDP设备上的软件。可以从网络上匿名下载MIDlet套件,正因为如此,用户可能关心一些安全和保密问题:MIDlet能否读取保密数据并将其发送给未知服务器?它能否进行未许可呼叫而让用户付费?欺诈程序能否在设备上运行并带来潜在问题?
除了具有碎片收集和数组边界检查等Java语言的安全功能之外,MIDP1.0 规范还增加了一些安全措施。在MIDP 1.0中,安全性限制分为低级设备安全和应用级设备安全。低级安全与MIDlet套件的类文件验证有关。该验证部分是由开发人员在预验证步骤中完成,部分是在设备上完成。之所以没有完全像JVM那样完全在设备中进行验证,主要是考虑到MIDP设备的中央处理器和内存都比较有限。
为了进一步增强安全性,MIDP1.0 规范还规定MIDlet套件运行在“沙箱”中,此“沙箱”能够将可用API限制在一个有限集合中。这其中有一些附加限制,例如不允许用户自定义类加载器以及禁止加入新的native函数。这些限制是应用级设备安全的一部分。
由于MIDP2.0以后陆续引入了很多的可选包,其中一部分涉及到敏感API的访问。原有的沙箱模型不能够满足用户的需要。为了在用户的使用方便与安全性方面取得平衡, MIDP2.0引入了全新的安全模型。
8.2 实例展示MIDP2安全模型在MIDP版本2.0中,安全模型得到改善,允许MIDlet访问敏感的API。例如,创建HTTP连接就是敏感操作之一,因为它可能涉及用户付费。MIDP 2.0引入了信任和非信任MIDlet的概念。非信任MIDlet套件对受限API的访问受到限制,它需要用户根据设备安全策略进行许可。另一方面,信任MIDlet套件可以根据安全策略自动获得一些许可。
为了更加形象的把MIDP2.0的安全模型展示给读者,我们首先来看一个通过HTTP连接读取数据的例子,最终把读取的数据长度显示出来。我们使用的运行环境是WTK,首先我们使用Ktoolbar新建一个项目命名为http,创建一个MIDlet为com.j2medev.security.HttpMIDlet。源代码如下:
package com.j2medev.security;
import java.io.*;
import javax.microedition.io.*;
import javax.microedition.lcdui.*;
import javax.microedition.midlet.*;
public class HttpMIDlet extends MIDlet implements Runnable, CommandListener
{
private final TextField text = new TextField("http://www.j2medev.com", "", 256, TextField.ANY);
private final Form form = new Form("HTTP Result");
private final Command exitCommand = new Command("Exit", Command.EXIT, 1);
private final Command okCommand = new Command("Load", Command.OK, 1);
public HttpMIDlet()
{
}
public void startApp()
{
if (Display.getDisplay(this).getCurrent() == null)
{
form.setCommandListener(this);
form.addCommand(exitCommand);
form.addCommand(okCommand);
form.append(text);
Display.getDisplay(this).setCurrent(form);
}
}
public void pauseApp()
{
}
public void destroyApp(boolean unconditional)
{
}
public void run()
{
// do an action that requires permission, e.g. HTTP connection
try
{
String url =text.getString();
HttpConnection connection = (HttpConnection) Connector.open(url);
InputStream in = connection.openInputStream();
int counter = 0;
int ch;
while ((ch = in.read()) != -1)
{
counter++;
}
in.close();
connection.close();
text.setString("Bytes read: " + counter);
} catch (IOException e)
{
text.setString("IOException: " + e.getMessage());
} catch (SecurityException e)
{
text.setString("SecurityException: " + e.getMessage());
}
}
public void commandAction(Command command, Displayable displayable)
{
if (command == exitCommand)
{
notifyDestroyed();
} else if (command == okCommand)
{
new Thread(this).start();
}
}
}
编译、运行应用程序会出现如下的界面。如果你访问你本机的HTTP测试服务器,请在文本框中输入http://localhost。
图一
当你选择load按钮的时候,会弹出如下一个界面。
图二
这里我们不选择Yes而是选择No,会弹出下面的界面。
图三
我们回头看看源代码就会明白,当我们选择No的时候,导致了系统抛出SecurityException,HttpMIDlet捕捉到了这个异常并把它显示在了文本框中。为什么系统会抛出SecurityException呢?这要首先从敏感操作说起,在MIDP2.0中的敏感操作基本都是和网络连接相联系的,比如通过HTTP协议联网等等。这些操作可能会让用户付费甚至存在安全隐患。因此系统会询问用户,如果用户许可的话那么操作会继续进行。如果用户不许可系统就会抛出SecurityException。下面我们列出在MIDP2.0中定义的许可:
l javax.microedition.io.Connector.http
l javax.microedition.io.Connector.socket
l javax.microedition.io.Connector.https
l javax.microedition.io.Connector.ssl
l javax.microedition.io.Connector.datagram
l javax.microedition.io.Connector.serversocket
l javax.microedition.io.Connector.datagramreceiver
l javax.microedition.io.Connector.comm
l javax.microedition.io.PushRegistry
请读者注意,虽然这些许可的名称和类名很相似,但是还是不一样的,不要混淆。如果当系统询问我们是否要联网的时候我们选择Yes的话,MIDlet会读取指定的url并把字节数显示在文本框,如下图所示:
图四
至此,我们对MIDP2.0的安全模型有了一定的感性认识。下一节中将对这一模型中重要的概念加以阐述。
8.3 MIDP2安全体系的重要概念8.3.1 许可许可用来保护对敏感API的访问,这并不难理解。应用程序通过对敏感API提出许可申请来试图获得相应的权限。
8.3.2 保护域与许可相关联的一个概念就是保护域。保护域就是一组许可、以及作用在这组许可上的交互模式。一个设备上有多个保护域,MIDlet都是运行在不同的保护域中的。不同的设备提供的保护域可能是不同的。
值得庆幸的是,MIDP规范定义了非可信域的推荐行为。原则上非可信域提供较少的许可,并且对许可的确认要经过用户的显式的操作。规范规定至少提供对HTTP、HTTPS的请求。也就是说可能出现如下的情况:你的设备有蓝牙能力,但并不对非可信域开放这个API。规范还规定了非可信域的用户交互模式(又称授权模式):blanket(总是允许)、session(第一次询问)和oneshot(每次询问)。不过不是每个设备都开放这三种交互模式给非可信域里的每个敏感API。例如Nokia手机在非可信域对FO API的交互模式只有oneshot(每次询问),这意味着运行在这个域的MIDlet每次调用这个API都要求用户确认。
其他的保护域的行为则由设备决定。
下面看看在WTK附带的模拟器里提供了几个保护域。再次强调,很有可能这会和你在实际设备中看到的有所区别。WTK中提供了四种类型的保护域:非信任、信任、最小和最大。一般我们的MIDlet都是运行在非信任保护域中的,这也就是为什么当我们进行敏感操作的时候,系统总会弹出一个对话框询问我们是不是要进行下一步操作的原因。我们可以更改MIDlet的保护域,从Ktoolbar选择edit->preferences->security然后选择trusted
这样当我们再次运行HttpMIDlet的时候,你会发现系统并没有询问用户来获得许可,而是直接进行了联网操作。这说明WTK模拟器的“trusted”保护域对HTTP操作的默认授权是Allowed,也就是说不需要用户的参与。
为了让你更清醒地认识一下保护域的概念,而不仅仅是停留在WTK的模拟器上,这里简单的介绍一下Nokia手机上的保护域。Nokia的保护与分为四种:1)设备制造商域 2)运营商域 3)值得信任的第三方域(对应WTK中的trusted域) 4)非信任的域。并且Nokia规定了只要程序不运行在非信任域上,就可以无需用户请求提示,对MIDP2中定义的API进行访问。之所以要告诉读者这点,就是希望读者在目标设备的保护域行为和WTK模拟器不同时,参考各家厂商的文档。
8.3.3 对许可的申请如果你用到了敏感API,你肯定会关心如何申请许可。许可必须要写入到jad属性文件的,使用的属性名称为MIDlet-Permissions和MIDlet-Permissions-opt。前者用于程序运行必需的许可申请,后者用于可选的附加许可申请。区分这两个原则就是,如果没有前者所规定的许可,应用程序应该不能运行;如果缺少后者所规定的许可,应用程序应该减少不必要的功能,保证程序以一种缩水的方式运行。
那么把许可写入到jad文件有什么好处呢?事实上当你把许可写入jad文件的时候是告诉了Application Management System(AMS)如果要成功运行这个MIDlet套件需要进行什么操作并得到什么许可。如果AMS本来就不允许这样的操作,那么它会拒绝安装这个应用程序。而不是等到用户安装后才发现这根本不能运行成功。
也许你认为编写这两个字段过于繁琐,幸运的是我们可是使用wtk提供的功能直接进行设置,选择settings—>permissions。
8.3.4 两种MIDlet理解了保护域的概念就不难理解MIDP2.0安全体系结构定义的两种MIDlet——非信任MIDlet和信任MIDlet。
对于设备无法验证JAR文件来源和完整性的MIDlet套件,MIDP 2.0规范将其定义为非信任。非信任MIDlet运行在非信任保护域上。根据我们前面对非信任保护域的讨论,我们得知这并非表示MIDlet无法安装或执行;而是根据设备上保护域的是实现,要么API不能访问,要么对受限操作的访问需要显式用户许可。缺省情况下,所有MIDP 1.0的 MIDlet均为非信任的。
如果设备能够验证MIDlet套件的真实性和完整性并将其分配到一个保护域,MIDlet套件则被称作信任MIDlet套件。根据其保护域的行为,信任MIDlet套件将获得所请求的许可。例如,如果请求javax.microedition.io.Connector.http许可,且保护域已经将许可设置为trusted,那么无需用户确认即可打开HTTP连接。不要认为信任MIDlet套件一定运行在信任保护域上。信任MIDlet套件可分配给任何保护域,信任保护域只是其中一种,或者它在设备上干脆叫做别的名字。另外,推荐安全策略仅仅建议信任MIDlet对MIDP2的API调用不需要用户参与。所以如果你的信任MIDlet在使用某个非MIDP2规定的敏感API时出现了用户显式确认提示,请不要惊讶。不过一般出现这种情况都会有blanket(总是允许)模式供用户选择。
8.3.5 如何成为一个可信任MIDlet了解了以上的信息后,相信每个调用敏感API的开发者都希望自己的应用成为一个可信任的MIDlet,以便让应用运行流畅。然而如何将一个MIDlet套件验证成为可信任套件并为其分配一个什么样的保护域全在设备的实现上。通常的设备是利用数字签名技术来实现这一点的。
取得数字签名是一个测试加认证的过程。测试需要一家专业公司而认证需要一个可信任组织,并且这一过程需要一定的时间和一笔费用。认证是程序发布之前才进行的工作,没有认证并不影响我们在模拟器中将应用作为可信任套件来进行测试。正因为这一详细过程超出了本章关注的范畴,所以这里没有讲述关于数字签名的部分。www.j2medev.com会另外撰文介绍这一过程。有兴趣的读者可以去www.javaverified.com了解这一过程,或者咨询目标设备的开发商。本章的主要目的是了解MIDP2.0安全体系和其主要概念,希望对你有所帮助。