知识屋:更实用的电脑技术知识网站
所在位置:首页 > 科技  > Android

Java安全模型与简单示例

发表时间:2022-03-26来源:网络

Java语言从一开始就有安全上的考虑,如何保证物联网下载的Java程序是安全的。

Java安全模型进化

Java将执行程序分为本地和远程两种,本地默认是可信的,而远程被看作是不授信的。对于授信的本地代码,可以访问一切本地资源,而对于非授信的远程代码,则做权限的限定。
Java的安全机制在不同的JDK版本逐步演化,

JDK 1.0 安全模型
在早期的Java实现中,使用沙箱机制,将Java代码限定在特定的运行范围内,严格限制对本地系统的资源访问。

以上机制,远程代码无法访问本地系统的文件,但实际往往存在这样的需求, 在Java 1.1中,增加了安全策略,运行用户指定代码对本地资源的访问权限。

JDK1.1 安全模型

JDK 1.2安全模型
增加了代码签名, 不管是本地代码还是远程代码,需要按照用户的安全策略设定,由类加载器加载到虚拟机中权限不同的运行空间。

带域的安全模型
引入域的概念,虚拟机把代码加载到不同的系统域和作用域,系统域负责与关键资源交互,应用域通过系统域部分代理对各种需要的资源进行访问,不同的受保护域,对应不同的权限,存在不同域中的类文件就具有了当前域的全部权限。

沙箱(Sandbox)机制

沙箱是限制程序运行的环境。沙箱主要限制系统资源的访问,包括CPU、内存、文件系统和网络。
Java安全沙箱机制的基本组件

字节码校验器(bytecode verifier)类装载器(class loader),类装载器在3个方面对沙箱起作用
1). 防止恶意代码去干涉善意代码
2). 守护被信任的类库边界
3). 将代码归入保护域内置的Java虚拟机的安全特性安全管理器及Java API

沙箱的元素:
1 权限
允许代码执行的操作,包括三部分:权限类型、权限名和允许的操作。
权限类型是实现了权限的Java类名(必须)
权限名,对哪类资源进行操作的资源定位。
允许的操作,指定了对目标可以执行的操作行为,比如读写。
在策略文件中配置的例子如下:

permission java.security.AllPermission; //权限类型 permission java.lang.RuntimePermission "stopThread"; //权限类型+权限名 permission java.io.FilePermission "/tmp/foo" "read"; //权限类型+权限名+允许的操作 代码源
类所在的位置,表示为URL地址保护域
组合代码源和权限,这是沙箱的基本概念。示例:代码A可以做权限B的事。策略文件
一个策略文件包含一个或多个保护域的项。策略文件包括全局和用户两种。全局位于JRE目录下的java.policy, 用户位于用户目录。
除了策略文件,另外一个重要的文件是java.security,该文件位于JRE目录中,和策略文件在同一目录,用于配置沙箱的一些参数。密钥库
cacerts, 保存密钥证书。

代码与示例演示

开发人员一般较少遇到安全相关的状况, 因为本地Java程序默认可以访问该机器的任意资源,这些权限包括:读取系统变量、文件读取和编辑、网络操作等。但在早期Applet的运行时一般会遇到Applet无法操作本地文件的权限问题(解决方法时是对文件签名)。
示例: 默认本地应用程序具备创建文件的权限。

public static void main(String[] args) { String fullFileName = "D:\\temp\\1.txt"; try { File file = new File(fullFileName); file.createNewFile(); } catch (Exception e) { e.printStackTrace(); } }

以上程序段在Eclipse和通过java命令都可以执行。
以上类文件的全路径类名是cn.osxm.jcodef.func.security.SecurityDemo,运行命令是:

java cn.osxm.jcodef.func.security.SecurityDemo

沙箱开启方式(java.security.manager)

沙箱可以通过运行参数设置和代码设置两种方式开启。
方式1.增加 -Djava.security.manager运行参数
以上示例,使用以下命令行运行

java -Djava.security.manager cn.osxm.jcodef.func.security.SecurityDemo

运行效果如下:

开启沙箱机制后,没有写入文件的权限了。
在Eclipse中,设置界面如下:

方式2: 通过System.setSecurityManager(new SecurityManager());代码进行设置
将以上代码段修改为:

public static void main(String[] args) { String fullFileName = "D:\\temp\\1.txt"; System.setSecurityManager(new SecurityManager());//开启沙箱 try { File file = new File(fullFileName); file.createNewFile(); } catch (Exception e) { e.printStackTrace(); } }

增加开启沙箱的代码后,则运行时不添加以上参数也会报" access denied"的错误。

权限是如何检查的?

开启了安全管理,JDK是在什么地方进行检查的呢? 以文件操作的文件输入流FileInputStream为例,源码如下:

可以看到,在打开输入流前,显示获取安全管理器,如果存在,则通过check()等方法检查权限。

使用策略文件设置权限(java.security.policy)

通过策略文件设置安全策略,在运行Java程序时,添加 -Djava.security.policy指定策略文件,可以运行读取指定目录下的文件。以上面例子为例,新建策略文件mypolicy.txt(策略文件一般以.policy为后缀名,但无强制要求),内容如下:

grant { permission java.io.FilePermission "D:\\temp\\*", "write"; };

以上对D盘temp目录开放写的权限。命令执行如下:

java -Djava.security.policy=D:\\devworkspace\\ecpworkspace\\jcodef\\jcodef-func\\target\\classes\\cn\\osxm\\jcodef\\func\\security\\mypolicy.txt cn.osxm.jcodef.func.security.SecurityDemo

-Djava.security.policy参数用于指定策略文件的地址,该地址也可以是http(s)的在线文件。格式是:

-Djava.security.policy=

这里虽然单独指定了策略文件,但是安全管理器还是会使用到默认的两个策略文件。如果不需要使用默认的策略文件,也就是只遵循设置的策略文件,可以使用双等于号(==)。格式如下:

-Djava.security.policy==

-Djava.security.manager和-Djava.security.policy 两个参数设置也可以同时使用,在命令行效果如下:

java -Djava.security.manager -Djava.security.policy==D:\\devworkspace\\ecpworkspace\\jcodef\\jcodef-func\\target\\classes\\cn\\osxm\\jcodef\\func\\security\\mypolicy.txt cn.osxm.jcodef.func.security.folder1.NewFileMain

域(Domain)

类、域和权限之间的关系如下图:

本地代码和远程代码虽然是在同一个JVM下,但类加载器和分配的Domain不一样,权限也就分开了。
跨域调用权限检查状况权限的交集。
Domain1 的 A.class 调用 Domain2的B.class, 而B.class需要访问系统资源。则必须Domain1和Domain2都就具有权限才能访问资源,但可以通过“特权”获取,也就是如果要满足权限,需要满足以下两个条件之一
1). 调用程序的后续对象对具备这个权限
2). 该方法标记为有访问“特权”。
特权是什么意思呢? 也就是通过AccessController.doPrivileged()方法可以突破权限的校验。以写入文件为例,代码如下:

public static void newFileWithPrivilegedAction(String fileName) { AccessController.doPrivileged(new PrivilegedAction() { @Override public String run() { String fullFileName = filePath + File.separator + fileName; File file = new File(fullFileName); try { file.createNewFile(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } return null; } }); }

JDK安全相关类和API

JDK将安全相关的类和接口放在java.security包中,该包位于JDK的rt.jar中。具体通过AccessController类的checkPermission方法检查权限,如果调用链中某个调用程序没有所需的权限,抛出AccessControlException异常。

相关类和API:

java.security.AccessController 存取控制器(Access Controller)。控制对操作系统的权限,控制的策略设定,可以由用户指定。java.security.SecurityManager完全管理器(Security Manager)。实现权限控制,比存取控制器优先级高。java.security.AccessControlContext, 访问控制上下文,基于做出是否允许访问的决定,常用于将代码标记为“特权”。java.security.Permission,访问系统资源的抽象类,比如文件权限java.io.FilePermission
收藏
  • 人气文章
  • 最新文章
  • 下载排行榜
  • 热门排行榜