目录
作为一种诞生于互联网兴起时代的语言,Java从一开始就带有安全上的考虑,
如何保证通过互联网下载到本地的Java程序是安全的,如何对Java程序访问本地资源权限进行有限授权
,这些安全角度的考虑一开始就影响到Java语言的设计与实现。可以说Java在这些方面的探索与经验,对后来的一些语言与产品都带来了积极影响。
一、JDK的安全模型
在Java中将执行程序分成本地和远程两种
,本地代码默认视为可信任的,而远程代码则被看作是不受信的。
1.1 JDK1.0 安全模型
对于授信的本地代码,可以访问一切本地资源。而对于非授信的远程代码在早期的JDK1.0实现中,安全依赖于沙箱 (Sandbox) 机制。沙箱机制就是将Java代码限定在虚拟机 (JVM) 特定的运行范围中,并且严格限制代码对本地系统的资源访问,通过这样的措施来保证对远程代码的有效隔离,防止对本地系统造成破坏。
1.2 JDK1.1 安全模型
JDK1.0安全模型如此严格的安全机制也给程序的功能扩展带来障碍,比如当用户希望远程代码访问本地系统的文件时候,就无法实现。因此,在后续的JDK1.1版本中,针对安全机制做了改进,增加了安全策略,允许用户指定代码对本地资源的访问权限。
1.3 JDK 1.2 安全模型
在JDK 1.2 版本中,再次改进了安全机制,增加了代码签名。不论本地代码或是远程代码,都会按照用户的安全策略设定,由类加载器加载到虚拟机中权限不同的运行空间,来实现差异化的代码执行权限控制。
1.4 最新安全模型
当前最新的安全机制实现,则引入了域 (Domain) 的概念。虚拟机会把所有代码加载到不同的系统域和应用域,系统域部分专门负责与关键资源进行交互,而各个应用域部分则通过系统域的部分代理来对各种需要的资源进行访问。虚拟机中,不同的受保护域 (Protected Domain),对应不一样的权限 (Permission)。存在于不同域中的类文件,具有了当前域的全部权限。
以上提到的都是基本的Java安全模型概念,在应用开发中还有一些关于安全的复杂用法,其中最常用到的API就是doPrivileged
。doPrivileged 方法能够使一段受信任代码获得更大的权限,甚至比调用它的应用程序还要多,可做到临时访问更多的资源。有时候这是非常必要的,可以应付一些特殊的应用场景。例如,应用程序可能无法直接访问某些系统资源,但这样的应用程序必须得到这些资源才能够完成功能。下面内容会详细讲解一下安全相关的方法使用。
二、AccessController
类java.security.AccessController
提供了一个默认安全策略
执行机制,在线程调用方法时,会使用栈检查决定潜在不安全操作
是否被允许。
AccessController
核心方法是checkPermission
静态方法,方法决定一个特定的操作能否被允许。如果访问请求被允许,checkPermission
会安静的返回,如果拒绝,将会抛出一个AccessControlException
。
2.1 方法摘要
2.2 栗子
策略文件
// 对目录中只授权读权限
grant codebase "file://d:/test"
{
permission java.io.FilePermission "d:/tes/*", "read";
};
测试代码
/**
* AccessController权限校验
* 启动命令: -Djava.security.manager
* -Djava.security.policy=acc.policy
*/
public class AccessMain {
public static void main(String[] args) throws PrivilegedActionException {
String filePath = "d:/test/touch-file.txt";
boolean createFlag = AccessController.doPrivileged(new PrivilegedExceptionAction<Boolean>() {
@Override
public Boolean run() throws Exception {
return touchFile(filePath);
}
});
System.out.println("create flag:" + createFlag);
}
private static boolean touchFile(String fileAbsolutePath) throws IOException {
File touchFile = new File(fileAbsolutePath);
return touchFile.createNewFile();
}
}
执行结果
Launcher failed - "Dump Threads" and "Exit" actions are unavailable
(access denied ("java.io.FilePermission" "bin\breakgen64.dll" "read"))
Exception in thread "main" java.security.AccessControlException:
access denied ("java.io.FilePermission" "d:\test\touch-file.txt" "write")
at java.security.AccessControlContext.checkPermission(AccessControlContext.java:472)
at java.security.AccessController.checkPermission(AccessController.java:886)
at java.lang.SecurityManager.checkPermission(SecurityManager.java:549)
at java.lang.SecurityManager.checkWrite(SecurityManager.java:979)
at java.io.File.createNewFile(File.java:1008)
at pojo.AccessMain.touchFile(AccessMain.java:29)
at pojo.AccessMain.access$000(AccessMain.java:14)
at pojo.AccessMain$1.run(AccessMain.java:21)
at pojo.AccessMain$1.run(AccessMain.java:18)
at java.security.AccessController.doPrivileged(Native Method)
at pojo.AccessMain.main(AccessMain.java:18)
Process finished with exit code 1