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. setcookie第三个值为什么写0

  2. 禅道 Rest API 开发

    在老的 PHP 系统中使用 PHP 5.3以后的库 所谓老的系统,是指没有使用PHP 5.3以上命名空间(namespace)特性编码的系统. 但是,只要你的系统运行在 PHP 5.3及以上的环境,在 ...

  3. Scalaz(16)- Monad:依赖注入-Dependency Injection By Reader Monad

    在上一篇讨论里我们简单的介绍了一下Cake Pattern和Reader Monad是如何实现依赖注入的.主要还是从方法上示范了如何用Cake Pattern和Reader在编程过程中解析依赖和注入依 ...

  4. Java集合源码分析(三)LinkedList

    LinkedList简介 LinkedList是基于双向循环链表(从源码中可以很容易看出)实现的,除了可以当做链表来操作外,它还可以当做栈.队列和双端队列来使用. LinkedList同样是非线程安全 ...

  5. SDL制作拼图游戏

    看完教程第三集后,好像自己能用这个来写一个简单的拼图游戏,第一次写出个带界面的游戏,好有成就感. 图片是自己慢慢截左上部分8个脸. #include <stdio.h> #include ...

  6. [asp.net mvc 奇淫巧技] 01 - 封装上下文 - 在View中获取自定义的上下文

    我们在asp.net 开发中已经封装了最强大的HttpContext,我们可以在HttpContext中可以获取到几乎任何想获取的东西,也可以在HttpContext写入需要返回客户端的信息.但是这些 ...

  7. bootstrap字体图标在谷歌显示正常,在火狐显示异常的问题

    bootstrap字体图标的使用 现在有很多的网站支持字体图标,我所知道的有bootstrap,fontawesome,iconmoon,等等,可能还有其他我并不知道 bootstrap只要你的文件夹 ...

  8. Debug - 支持浏览器和 Node 平台的全端调试工具

    Debug 是一个跟踪调试消息的 JavaScript 库.因为它只是对 console.log 的包装,所以支持 Node 和浏览器.它允许你过滤日志输出而不需要改变你的源代码,也输出时间差异,可以 ...

  9. go语言循环语句 for

    Go语言中的循环语句只支持for关键字,而不支持while和do-while结构. sum := 0 for i := 0; i < 10; i++ { sum += i } 无限循环的写法: ...

  10. Java Web 三层架构详解

    java 三层架构ssh 一个spring2.5+hibernate3.2+struts2.0组合框架,使用spring的 IoC来管理应用的 所有bean,包括struts2的 action,充分发 ...