Java API中有很多都使用了SecurityManager,这到底是什么玩意?最近看公司的产品的源码,也有不少SecurityManager、AccessControlContext等相关的代码,只是知道它们与安全有关,但是它们到底是怎么一回事呢?Spring也有一个Security框架,与Java Security有什么关联呢?另外有经验的开发人员调试程序时可能会查看ProtectionDomain、CodeSource,这两者又是什么呢?

Java Sandbox

提到Java Security,就不得不说Java Sandbox模型。

Java2 Security Model:

Java2平台上,加载类时,会形成不同的sandbox,同时也会根据相关的security policy,为这些sandbox生成不同的安全策略,这些安全策略会在应用程序执行时,进行检查,以保护资源被恶意的操作。

这张图指出了Java应用程序的真实的执行过程。

1) 编译期强制规则验证,而后生成class file

Java的强制性规则有:

A:  private, protected, default, public 。这个都知道,是关系到可见性,是对应用程序中内存资源的保护。

B:  final的变量初始化后不能被改变

C:  变量要先初始化后使用

以及一些其他的规则,通过这些规则验证后,就生成class file,也就是常说的字节码文件。

2ClassLoader加载class file后定义类生成Class对象

类加载器也是一道坎,不是说你让它加载,它就加载的,它也是要进行验证的。

假如骇客写了一些java文件编译后放到classpath目录下,或者是将jdk中自带某些核心API反编译后进行某些修改,覆盖原有文件,这样对程序的危害可以极大的。所以类加载时,也是有必要进行检查的。

从这张图片可以看出在类加载器定义类的过程也会对字节码进行检查的,下面可以看一下ClassLoader中defineClass的过程:

protected final Class<?> defineClass(String name, byte[] b, int off, int len,

               ProtectionDomain protectionDomain)

   throws ClassFormatError
{
// 检查类加载器是否初始化
check();
// 形成为该类生成protectionDomain和codesource
protectionDomain = preDefineClass(name, protectionDomain); Class c = null;
String source = defineClassSourceLocation(protectionDomain); // 真实的定义Class的过程,这个方法是native的,字节码检查的过程也是这里进行的,这里是看不到的,也是不能让我们看到的,如果我们可见,就可以自定义,这样检查就形同虚设。 try {
c = defineClass1(name, b, off, len, protectionDomain, source); } catch (ClassFormatError cfe) {
c = defineTransformedClass(name, b, off, len, protectionDomain, cfe, source);
} // 完善证书等信息
postDefineClass(c, protectionDomain);
return c; }

既然代码层面,看不到如何检查字节码的,那么至少可以来了解一下,到底做了哪些检查呢?

D:检查class file的格式是否正确,JVM Specification 中说明了class file的格式,感兴趣的话可以到官网下载看看。例如:class file要有正确的长度、魔数 等。

魔数用于确定文件类型,UNIX系统不是根据扩展名来确定文件类型的,就是根据这个魔数来的。想要知道class file的魔数、以及是怎么定义的,可以参考《深入理解Java虚拟机》。

E: final的类没有子类

F: 原生类型的数据有无不合法的类型转换(E.G.: int to Object)

G: 引用类型的数据有无不合法的类型转换,例如将父类对象转换为子类类型。

H: 有没有操作数出现栈溢出现象

等。

其实还有两种检查,这两种是在运行时进行的:

I:  数组不能越界

J:  数据不能强制转化为其他不相干的类型

在定义类的过程中,还产生了与这个类相关联的ProtectionDomain。Java Security模块的设计如下图所示。

但并不是所有的ClassLoader都会生成ProtectionDomain。例如我前之前的一篇博客中定义的那个类加载器,又或者时bootstrapClassLoader。 只有继承了SecurClassLoader的ClassLoader在defineClass时都会生成相关联的ProtectionDomain, 一般情况下我们自定义ClassLoader时都会继承UrlClassLoader,而UrlClassLoader又继承了SecurClassLoader,所以我们定义的ClassLoader在执行defineClass时一般都会生成ProtectionDomain。

ProtectionDomain的设计模型是很重要的,接下来要说的AccessController和SecurityManager都是在ProtectionDomain的基础上才有所作为的。所以ProtectionDomain就在类加载时就确立。

默认情况下,一个jar包就对应一个ProtectionDomain。

网上关于Java Security方面的教程,说的最多莫过于Policy了,因为它是配置安全策略的。我们可能不会去定义Permission(Java中定义的Permission已经够我们使用),但是我们不可或缺的要去配置安全策略,来使用这些Permission为我们服务。

3)应用程序访问相关资源

3.1 SecurityManager#checkPermission()

Java提供了安全模型,我们在程序中如何使用呢?

一般来说都是通过SecurityManager来完成的,使用方式为:

SecurityManager sm = getSecurityManager();
if (sm != null) {
// sm.checkPermission();
}

例如:

System.getProperty(String key)

public static String getProperty(String key) {
checkKey(key);
SecurityManager sm = getSecurityManager();
if (sm != null) {
sm.checkPropertyAccess(key);
}
return props.getProperty(key);
}

例如:

public FileInputStream(File file) throws FileNotFoundException {
String name = (file != null ? file.getPath() : null);
SecurityManager security = System.getSecurityManager();
if (security != null) {
security.checkRead(name);
}
if (name == null) {
throw new NullPointerException();
}
fd = new FileDescriptor();
open(name);
}

默认情况下,我们的程序并没有开启Java的安全策略。想要看看开启安全策略后你的应用程序会是什么样的,可以使用JVM参数:-Djava.security.manager 。

如果要使用代码来开启,可以使用System.setSecurityManager(securitymanager)来启动。

在代码中只要像上面那样简单的写上两三行代码就可以检查相应的权限了。那么它们的执行过程是什么呢?

SecurityManager中所有检查权限相关的方法都会调用SecurityManager的checkPermission方法,下面的这个时序图说明了SecurityManager#checkPermission(Permission)的执行过程。

从这个图上也能看到最后还是Permission#implies起作用的。

3.2 AccessController.doPrivileged()

有时我们还会在代码中看到使用AccessController.doPrivileged()方法的,这个又是做什么呢?

假设有下列一个应用场景:有一个ProtectionDomain的CodeSource是com目录,在它下面有三个目录:core,moduleA,web,在这个 ProtectionDomain中,对所有的文件都有read权限,只有web目录下的resource目录下的文件,可以有write权限。现在有一需求,要在core目录下的某个文件有write权限。

/com
|--core
|--moduleA
|--web
|--bean
|--service
|--dao
|--resource

我们的程序中肯定会这样写:new FileOutputStream(File file)。上面已经粘出来FileInputStream(File file)实现过程。也就是说检查对该文件有无读权限。那么对应的FileOutputStream中肯定也会有检查是否有写权限的过程。上面的描述中已经知道,对于core下没有写权限的,所以我们的需求是无法满足的。那怎么办呢?

AccessController.doPrivileged()就可以帮肋完成上述任务。

FileOutputStream fos=null;
String filepath=”./com/core/xx”;
fos=AccessController.doPrivileged(new PriviliegedAction(){
public FileOutputStream run(){
return new FileOutputStream(filepath);
}
});
if(fos!=null){
// xxxxxxxx
}

这到底是怎么回事呢?下面贴Java API中AccessController描述中的一段话:

A caller can be marked as being "privileged" (see doPrivileged and below). When making access control decisions, the checkPermission method stops checking if it reaches a caller that was marked as "privileged" via a doPrivileged call without a context argument (see below for information about a context argument). If that caller's domain has the specified permission, no further checking is done and checkPermission returns quietly, indicating that the requested access is allowed. If that domain does not have the specified permission, an exception is thrown, as usual.

这段话大意就是说:

如果使用了doPrivileged方法将调用者标记为privileged,在执行AccessController.checkPermission()做检查时,当检查到这个调用者时,就会终止检查,然后只作一个判断:如果caller所在的域有指定的权限就可以了。

SecurityManager#checkPermission实际上就是调用了AccessController.checkPermission(),所以这个解决方案对于SecurityManager#checkPermission也是适用的。

就暂说到这里吧,Java Security还有很多细节的东西没有提到。本文只是对Java Security有了一个整体结构上的说明。以及一些常用代码的解释,看完这篇文章,相信以往对一些有疑惑的代码,现在也应该可以明白七八分了。

Java Se:Java Security的更多相关文章

  1. java的几个版本以及jre,jdk等概念——【转载】JDK、Java SE、Java EE、Java ME我该选

    我们平时使用的一些软件,有一部分需要Java环境的支持,但是SUN那么多的产品,让人眼花缭乱的版本号,前看后看都差不多的缩写,让我们选择起来的时候常常望而却步,只好跟着感觉走.所以下面我要介绍的就是那 ...

  2. 浅谈Java SE、Java EE、Java ME三者的区别

    本文把JAVA SE.JAVA EE.JAVA ME拿来做下区别,同时也分享一下作者的一些成果.目前的Java平台根据软件开发人员.服务提供商和设备生产商可以针对特定的市场可以分为三个版本JAVA S ...

  3. 转 Java笔记:Java内存模型

    Java笔记:Java内存模型 2014.04.09 | Comments 1. 基本概念 <深入理解Java内存模型>详细讲解了java的内存模型,这里对其中的一些基本概念做个简单的笔记 ...

  4. Java、Java SE、Java Web和Java EE的区别

    刚接触Java对这些概念上的东西有点模糊,查了很多资料,想把它分享出来,要是哪里不对请大家指正(^_^) 1.Java 毫无疑问这就是门语言和C.C++.C#一样没什么好说的. 2.Java SE和J ...

  5. Java SE、Java EE、Java ME三者的区别

    1. Java SE(Java Platform,Standard Edition).Java SE 以前称为 J2SE.它允许开发和部署在桌面.服务器.嵌入式环境和实时环境中使用的 Java 应用程 ...

  6. Java SE、Java EE、Java ME

    Java SE(Java Platform,Standard Edition).Java SE 以前称为 J2SE.它允许开发和部署在桌面.服务器.嵌入式环境和实时环境中使用的 Java 应用程序.J ...

  7. Java SE、Java EE和Java ME有什么区别?

    Java现在已不仅仅是一种语言,从广义上说,它代表了一个技术体系.该体系根据应用方向的不同主要分为Java SE.Java EE和Java ME的3个部分. 1998年12月份Sun公司公布的Java ...

  8. Java基础:Java的四种引用

    在Java基础:java虚拟机(JVM)中,我们提到了Java的四种引用.包括:强引用,软引用,弱引用,虚引用.这篇博客将详细的讲解一下这四种引用. 1. 强引用 2. 软引用 3. 弱引用 4. 虚 ...

  9. Java SE、Java EE、Java ME 三者区别

    现在一个个来分析 1. Java SE(Java Platform,Standard Edition).Java SE 以前称为 J2SE.它允许开发和部署在桌面.服务器.嵌入式环境和实时环境中使用的 ...

随机推荐

  1. iOS阶段学习第15天笔记(NSArray与NSMutableArray 数组)

    iOS学习(OC语言)知识点整理 一.OC中的数组 1)数组:也是一个对象,数组中存放的是对象的地址,可以存放任意类型对象的地址,只能是对象不能是具体的数值,数组是有序的,      可以存放重复的元 ...

  2. 从NavigationController 下的UITableView中移除 header

    this.AutomaticallyAdjustsScrollViewInsets = false; 解析:AutomaticallyAdjustsScrollViewInsets为系统自动为适应na ...

  3. mysql-databaseython 3.4.0 with MySQL database

    Phttp://shttp://stackoverflow.com/questions/23376103/python-3-4-0-with-mysql-databasetackoverflow.co ...

  4. Spring面试基本问题(1)

    1.什么是Spring框架?Spring框架有哪些主要模块? Spring框架是一个为Java应用程序的开发提供了综合.广泛的基础性支持的Java平台.Spring帮助开发者解决了开发中基础性的问题, ...

  5. sql server和mysql中分别实现分页功能

    MySQL 在MySQL中,可以用 Limit 来查询第 m 列到第 n 列的记录, 例如: select * from tablename limit m, n sql="select * ...

  6. Redis-持久化

    Redis 持久化 Redis 提供了不同持久化范围的选项: RDB 持久化以指定的时间间隔执行数据集的即时点(point-in-time)快照. AOF 持久化在服务端记录每次收到的写操作,在服务器 ...

  7. HTML5 Canvas 实现的9个 Loading 效果

    Sonic.js 是一个很小的 JavaScript 类,用于创建基于 HTML5 画布的加载图像.更强大的是 Sonic.js 还提供了基于现成的例子的创建工具,可以帮助你实现更多自定义的(Load ...

  8. jquery实现输入框实时输入触发事件代码

    $('.aa').bind('input propertychange', function() { searchProductClassbyName(); }); function searchPr ...

  9. HTML标签的嵌套规则

    我在平时在写html文档的时候,发现不太清楚标签之间的嵌套规则,经常是想到什么标签就用那些,后来发现有些标签嵌套却是错误的.通过网上找资料,了解了html标签的嵌套规则. 一.HTML 标签包括 块级 ...

  10. ABAP中的Table Control编程

          SAP中,Table Control是在Screen中用的最广泛的控件之一了,可以实现对多行数据的编辑.       简单来说,Table Control是一组屏幕元素在Screen上的重 ...