Java Se:Java Security
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,也就是常说的字节码文件。
2)ClassLoader加载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的更多相关文章
- java的几个版本以及jre,jdk等概念——【转载】JDK、Java SE、Java EE、Java ME我该选
我们平时使用的一些软件,有一部分需要Java环境的支持,但是SUN那么多的产品,让人眼花缭乱的版本号,前看后看都差不多的缩写,让我们选择起来的时候常常望而却步,只好跟着感觉走.所以下面我要介绍的就是那 ...
- 浅谈Java SE、Java EE、Java ME三者的区别
本文把JAVA SE.JAVA EE.JAVA ME拿来做下区别,同时也分享一下作者的一些成果.目前的Java平台根据软件开发人员.服务提供商和设备生产商可以针对特定的市场可以分为三个版本JAVA S ...
- 转 Java笔记:Java内存模型
Java笔记:Java内存模型 2014.04.09 | Comments 1. 基本概念 <深入理解Java内存模型>详细讲解了java的内存模型,这里对其中的一些基本概念做个简单的笔记 ...
- Java、Java SE、Java Web和Java EE的区别
刚接触Java对这些概念上的东西有点模糊,查了很多资料,想把它分享出来,要是哪里不对请大家指正(^_^) 1.Java 毫无疑问这就是门语言和C.C++.C#一样没什么好说的. 2.Java SE和J ...
- Java SE、Java EE、Java ME三者的区别
1. Java SE(Java Platform,Standard Edition).Java SE 以前称为 J2SE.它允许开发和部署在桌面.服务器.嵌入式环境和实时环境中使用的 Java 应用程 ...
- Java SE、Java EE、Java ME
Java SE(Java Platform,Standard Edition).Java SE 以前称为 J2SE.它允许开发和部署在桌面.服务器.嵌入式环境和实时环境中使用的 Java 应用程序.J ...
- Java SE、Java EE和Java ME有什么区别?
Java现在已不仅仅是一种语言,从广义上说,它代表了一个技术体系.该体系根据应用方向的不同主要分为Java SE.Java EE和Java ME的3个部分. 1998年12月份Sun公司公布的Java ...
- Java基础:Java的四种引用
在Java基础:java虚拟机(JVM)中,我们提到了Java的四种引用.包括:强引用,软引用,弱引用,虚引用.这篇博客将详细的讲解一下这四种引用. 1. 强引用 2. 软引用 3. 弱引用 4. 虚 ...
- Java SE、Java EE、Java ME 三者区别
现在一个个来分析 1. Java SE(Java Platform,Standard Edition).Java SE 以前称为 J2SE.它允许开发和部署在桌面.服务器.嵌入式环境和实时环境中使用的 ...
随机推荐
- Mysql 大小写问题
今天发布程序的时候,日志报错找不到表,但是系统中已经存在表,最后发现是sql大小写的问题,mysql默认设置导致这些执行失败. 1.用ROOT登录,修改/etc/my.cnf 2.在[mysqld]下 ...
- x8086汇编在显存中显示字符串
题目:在屏幕中间显示绿色,绿底红色,白底蓝色的字符串‘welcome to masm!’ 80X25彩色字符模式显示缓冲区的结构: 在内存地址结构中,B8000H~BFFFFH共32KB的空间,为80 ...
- 《构建高性能web站点》随笔 无处不在的性能问题
前言– 追寻大牛的足迹,无处不在的“性能”问题. 最近在读郭欣大牛的<构建高性能Web站点>,读完收益颇多.作者从HTTP.多级缓存.服务器并发策略.数据库.负载均衡.分布式文件系统多个方 ...
- [小北De编程手记] : Lesson 02 玩转 xUnit.Net 之 基本UnitTest & 数据驱动
关于<玩转 xUnit.Net>系列文章,我想跟大家分享的不是简单的运行一下测试用例或是介绍一下标签怎么使用(这样的文章网上很多).上一篇<Lesson 01 玩转 xUnit.Ne ...
- Linux更改主机名-适用于abuntu
今天复制了个ubuntu虚拟机,于是想更改下主机名以作区别.这是搜到的比较完整的资料,适用abuntu,不过其他linux系统还有待求证. 1.查看主机名 在Ubuntu系统中,快速查看主机名有多种方 ...
- linux常用命令之查阅文件
CAT cat – concatenate print files 连续的输出文件内容 用法 cat [-nbA] file 选项 -n line number 输出行号 -b line number ...
- Squire – 简洁的 HTML5 富文本编辑器
Squire 是一个简洁的 HTML5 富文本编辑器,它提供了强大的跨浏览器的标准化,超级轻巧灵活.它是建立在现在和未来并作为研究,因此并不支持那些古老的浏览器. 在线演示 源码下载 您可能 ...
- 【干货分享】Node.js 中文学习资料和教程导航
这篇文章来自 Github 上的一位开发者收集整理的 Node.js 中文学习资料和教程导航.Node 是一个服务器端 JavaScript 解释器,它将改变服务器应该如何工作的概念,它的目标是帮助程 ...
- QQ拼音输入法 该到放弃的时候了
一直使用QQ拼音的纯净版,后来给了搜狗了,纯净版和普通版已经变成同一个版本了... 不过. 不过,2016.03.16更新版本后,重启后居然还弹出这样的窗口: 不知道怎么设置,每次重启后就弹出! 卸载 ...
- ionic + cordova 使用 cordova-plugin-crosswalk-webview 中的一些个坑
1) 在使用Web Audio API 时,无法使用 AudioContext.decodeAudioData() 对MP3文件进行解码 2)使用Cordova-plugin-weibosdk 插件时 ...