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,也就是常说的字节码文件。

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有了一个整体结构上的说明。以及一些常用代码的解释,看完这篇文章,相信以往对一些有疑惑的代码,现在也应该可以明白七八分了。

时间: 2024-10-25 05:48:37

Java Se:Java Security的相关文章

Java、Java SE、Java ME、Java EE

java SE:Java Standard Edition,标准版,开发桌面程序应用.通常说的Java.也是核心.java EE:Java Enterprise Edition,企业版,开发JavaWeb应用程序.java ME:Java Micro Edition,微型版,开发手机等电子产品的应用程序. Q:Java是一种解释型语言.所以效率低,提高性能有2个方法:1.Java语言源程序编写完成后,先使用Java伪编译器进行伪编译,将其转换为中间码(也称为字节码)再解释.2.提供一种“准实时”

JAVA SE、JAVA EE、JAVA ME的联系与区别

Java 平台有三个版本,这使软件开发人员.服务提供商和设备生产商可以针对特定的市场进行开发: * Java SE(Java Platform,Standard Edition).Java SE 以前称为 J2SE. 它允许开发和部署在桌面.服务器.嵌入式环境和实时环境中使用的 Java 应用程序. Java SE 包含了支持 Java Web 服务开发的类,并为 Java Platform,Enterprise Edition(Java EE)提供基础. * Java EE(Java Plat

JAVA SE、JAVA EE、JAVA ME 三者区别

Java 平台有三个版本,这使软件开发人员.服务提供商和设备生产商可以针对特定的市场进行开发:     * Java SE(Java Platform,Standard Edition).Java SE 以前称为 J2SE.它允许开发和部署在桌面.服务器.嵌入式环境和实时环境中使用的 Java 应用程序.Java SE 包含了支持 Java Web 服务开发的类,并为 Java Platform,Enterprise Edition(Java EE)提供基础.     * Java EE(Jav

Java SE和Java EE应用的性能调优

凡事预则立,不预则废,和许多事情一样,Java性能调优的成功,离不开行动计划.方法或策略以及特定的领域背景知识.为了在Java性能调优工作中有所成就,你得超越"花似雾中看"的状态,进入"悠然见南山"或者已然是"一览众山小"的境界. 这三个境界的说法可能让你有些糊涂吧,下面进一步解释. 花似雾中看(I don't know what I don't know).有时候下达的任务会涉及你所不熟悉的问题域.理解陌生问题域首先面临的困难就是如何竭尽所能地

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

我们平时使用的一些软件,有一部分需要Java环境的支持,但是SUN那么多的产品,让人眼花缭乱的版本号,前看后看都差不多的缩写,让我们选择起来的时候常常望而却步,只好跟着感觉走.所以下面我要介绍的就是那些让大家困惑的东西,首先让我们看看SUN的产品之多:下载地址:http://developers.sun.com/downloads/ 哈哈还没有展开它们的子选项呢,让人眼花缭乱,下面介绍大家使用的比较广泛的名词吧:(一)J2SEJava2平台标准版(Java2 Platform Standard

24. Java SE 、 Java EE 、JavaME 、 JavaWeb 直接的区别和联系

这个是在别人博客抄的,并不是本人撰写 Java是一门编程语言.Java分为三大版本,SE即标准版,包含了Java核心类库,主要用来开发桌面应用:EE即企业版,包含SE,又有扩展部分(Servlet,JDBC等),主要用来开发分布式网络程序:ME即微型版,包含了SE中部分类库,又有自己扩展部分,主要用来做移动类.嵌入式开发. Java SE(Java Platform,Standard Edition).Java SE 以前称为 J2SE.它允许开发和部署在桌面.服务器.嵌入式环境和实时环境中使用

Java--- J2EE、Java SE、Java EE、Java ME 区别

java SE=Java Standard EditionJava EE=Java Enterprise EditionJava ME=Java Mobile Edition SE主要用于桌面程序,控制台开发(JFC)EE企业级开发(JSP,EJB)ME嵌入式开发(手机,小家电) 目前,Java 2平台有3个版本,它们是适用于小型设备和智能卡的Java 2平台Micro版(Java 2 Platform Micro Edition,J2ME).适用于桌面系统的Java 2平台标准版(Java 2

Java SE、Java EE、Java ME

Java SE(Java Platform,Standard Edition).Java SE 以前称为 J2SE.它允许开发和部署在桌面.服务器.嵌入式环境和实时环境中使用的 Java 应用程序.Java SE 包含了支持 Java Web 服务开发的类,并为 Java Platform,Enterprise Edition(Java EE)提供基础. Java EE(Java Platform,Enterprise Edition).这个版本以前称为 J2EE.企业版本帮助开发和部署可移植.

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

现在一个个来分析 1. Java SE(Java Platform,Standard Edition).Java SE 以前称为 J2SE.它允许开发和部署在桌面.服务器.嵌入式环境和实时环境中使用的 Java 应用程序.Java SE 包含了支持 Java Web 服务开发的类,并为 Java Platform,Enterprise Edition(Java EE)提供基础. 2. Java EE(Java Platform,Enterprise Edition).这个版本以前称为 J2EE.