Java 代理学习笔记 —— Java Security Manager解析

  • 简述
  • 示例及分析
  • Security Manager具体工作机制
  • Permission项目简述

简述

在第一篇文章,Java 代理学习笔记 —— 从反射开始里曾经提到过,在不启用Security Manager的情况下,我们可以直接通过反射来改变字段是否可以获取,再通过反射得到私有变量的值。那么,Security Manager是什么呢?对反射又有什么影响呢?

这篇文章将会介绍Java中的Security Manager。

在Orcale关于Security Manager的文档中,有如下描述

A security manager is an object that defines a security policy for an application. This policy specifies actions that are unsafe or sensitive. Any actions not allowed by the security policy cause a SecurityException to be thrown. An application can also query its security manager to discover which actions are allowed.

从上面可以知道,Security manager定义了应用的安全策略。在这些定义好的安全策略中,我们声明哪些操作是不安全或者是敏感的。所有违反了安全策略的操作都将会导致安全异常的抛出。

在java程序中,Security manager默认是不会被启用的,要启用Security Manager,我们需要增加如下的Java虚拟机参数。

-Djava.security.manager

示例及分析

还是回到第一篇文章的示例代码中

package reflectionSample;

import java.lang.reflect.*;

public class ReflectionMain {
    public static void main(String args[]) {
        try {
            Class clazz = Class.forName("reflectionSample.User");


            Field nameField = clazz.getDeclaredField("name");

            //获取name这个变量的类型全称
            System.out.println(nameField.getType().toGenericString());//public final class java.lang.String

            //获取name变量的声明全称
            System.out.println(nameField.toGenericString()); //private java.lang.String reflectionSample.User.name

            //设置User中name的值
            User u = new User();

            nameField.setAccessible(true);

            nameField.set(u, "testName"); 

            System.out.println(nameField.get(u)); //testName

        } catch (Exception e) {
            e.printStackTrace();
        } 
    }
}

当我们增加虚拟机参数后,会抛出如下异常


java.security.AccessControlException: access denied ("java.lang.reflect.ReflectPermission" "suppressAccessChecks")
    at java.security.AccessControlContext.checkPermission(AccessControlContext.java:457)
    at java.security.AccessController.checkPermission(AccessController.java:884)
    at java.lang.SecurityManager.checkPermission(SecurityManager.java:549)
    at java.lang.reflect.AccessibleObject.setAccessible(AccessibleObject.java:128)
    at reflectionSample.ReflectionMain.main(ReflectionMain.java:22)

这是由于默认的Security Manager启用的是白名单机制,也就是说,所有没有赋予权限的操作,都会导致异常的抛出。

那么,默认的配置文件,又在哪里呢?

%JAVA_HOME%\jre\lib\security\java.security 其中有两行非常重要的

# The default is to have a single system-wide policy file,
# and a policy file in the user's home directory.
policy.url.1=file:${java.home}/lib/security/java.policy
policy.url.2=file:${user.home}/.java.policy

以上,就指明了系统默认的policy文件读取的地方。

我们再打开java.policy,可以看到里面有如下的赋予权限的语句

grant codeBase "file:${java.home}/../lib/jvmx.jar" {
    permission java.security.AllPermission;
};

policy文件就是由这些授权项组成,授权项的语法规则如下所示:

grant signedBy "signer_names", codeBase "URL" {
    permission "permission_class_name" "target_name", "action",
        signedBy "signer_names";
    ....
    permission "permission_class_name" "target_name", "action",
        signedBy "signer_names";
  };
字段名称 字段作用 是否必须 备注
signedBy 表示使用的证书别名 若没有,则不会进行密钥验证
codeBase 代码的原位置 若没有,则默认授权项会应用到所有文件
permission_class_name 授权项具体类名
target_name 授权项的具体内容 由具体授权类决定
action 被授权的操作 不一定 需要根据具体的授权类以及授权内容决定

而对于codeBase,又有相应的语法规则 (示例: codeBase “file:/C:/java/” )
- 属性扩展 可支持 ${user.dir}等变量读取 如 codeBase “file:${user.dir}” ,但只支持单层属性扩展,不支持多层属性扩展。 如 codeBase “file:${user.dir ${dir}}是不会生效的。
- 支持模糊匹配 通过 * 匹配目录下所有文件(不包含子目录) 通过 - 匹配目录下所有文件以及子目录中所有文件

知道了这些授权项的存在以及写法之后,我们就可以自定义授权项以及policy文件啦。

通过增加JVM参数-Djava.security.policy=C:/etc/java.policy来指定自定义的java policy文件。如果想要查看security相关的log,可以增加JVM参数-Djava.security.debug=all

自定义的java.policy

grant codeBase "file:${user.dir}/-"{
        permission java.lang.reflect.ReflectPermission "suppressAccessChecks";
};

为文件增加了权限,就能够顺利执行啦~

Security Manager具体工作机制

说到Security Manager的工作机制,最重要的就是Security Manager里面的checkPermission方法,我们通过传入不同的Permission项目,来进行检查。

在检查的时候,我们会具体地调用AccessController里面的getStackAccessControlContext方法,这个native方法将会检查当前的调用栈中有无违反权限的操作,如果有,就会抛出异常。

Permission项目简述

在Java原生的代码中,有如下的Permission继承关系

Java 代理学习笔记 —— Java Security Manager解析_第1张图片

再列举一些常用的Permission项目以及他们的可选值

Permission项目 target name action
java.io.FilePermission 文件目录 read, write, execute, delete
java.net.SocketPermission 主机名或者ip地址 accept, connect, listen, resolve
java.util.PropertyPermission 具体系统属性 read, write
java.lang.reflect.ReflectPermission suppressAccessChecks N/A
java.security.AllPermission N/A N/A
java.lang.RuntimePermission exitVM 等 N/A

要查看更加详细的Permission项目,可以直接到Oracale api文档中查询

你可能感兴趣的:(学习笔记,-,Java)