暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

Java安全管理器-SecurityManager

蹲厕所的熊 2018-06-19
1386

蹲厕所的熊 转载请注明原创出处,谢谢!

前言

相信很多人在看JDK、Spring、Tomcat源码的时候会发现一个类的踪影,它就是SecurityManager。它经常在代码中以这样的方式出现:

  1. SecurityManager sm = getSecurityManager();

  2. if (sm != null) {

  3.    sm.checkPropertyAccess(key);

  4. }

这个功能在我们写代码的时候可以说几乎不会用上,但是为了知识体系的完整,我们还是需要了解什么是SecurityManager。

SecurityManager:安全管理器,它是防范恶意攻击的主要安全卫士。它通过执行运行阶段检查和访问授权,以实施应用所需的安全策略,从而保护资源免受恶意操作的攻击。而它需要根据提供的Java安全策略文件(java policy file)来进行防护。

开启安全管理

默认我们系统中直接运行的Java程序都没有开启SecurityManager,开启它只需要在JVM启动参数中加上 -Djava.security.manager
即可,JVM会在程序启动的时候在 sun.misc.Launcher
类中进行初始化。

  1. public Launcher() {

  2.    // ...ignore


  3.    // 获取配置的JVM参数 -Djava.security.manager

  4.    String var2 = System.getProperty("java.security.manager");

  5.    if (var2 != null) {

  6.        SecurityManager var3 = null;

  7.        if (!"".equals(var2) && !"default".equals(var2)) {

  8.            try {

  9.                var3 = (SecurityManager)this.loader.loadClass(var2).newInstance();

  10.            } catch (Exception var5) {}

  11.        } else {

  12.            // 使用默认的SecurityManager

  13.            var3 = new SecurityManager();

  14.        }

  15.        // 设置安全管理器

  16.        System.setSecurityManager(var3);

  17.    }

  18. }

既然系统也是通过System.setSecurityManager的方式设置安全管理器的,我们在测试的时候也可以手动设置,但是还是推荐使用启动参数的方式来进行设置。

policy file

默认开启安全管理类后,JVM会先去 ${java.home}/jre/lib/security
下找到 java.security
获取到其中的一段配置:

  1. # The default is to have a single system-wide policy file,

  2. # and a policy file in the user's home directory.

  3. policy.url.1=file:${java.home}/lib/security/java.policy

  4. policy.url.2=file:${user.home}/.java.policy

这段配置就是policy文件的目标位置,默认位置为 ${java.home}/lib/security/java.policy

打开此文件:

  1. // Standard extensions get all permissions by default


  2. grant codeBase "file:${{java.ext.dirs}}/*" {

  3.        permission java.security.AllPermission;

  4. };


  5. // default permissions granted to all domains


  6. grant {

  7.        // Allows any thread to stop itself using the java.lang.Thread.stop()

  8.        // method that takes no argument.

  9.        // Note that this permission is granted by default only to remain

  10.        // backwards compatible.

  11.        // It is strongly recommended that you either remove this permission

  12.        // from this policy file or further restrict it to code sources

  13.        // that you specify, because Thread.stop() is potentially unsafe.

  14.        // See the API specification of java.lang.Thread.stop() for more

  15.        // information.

  16.        permission java.lang.RuntimePermission "stopThread";


  17.        // allows anyone to listen on dynamic ports

  18.        permission java.net.SocketPermission "localhost:0", "listen";


  19.        // "standard" properies that can be read by anyone


  20.        permission java.util.PropertyPermission "java.version", "read";

  21.        permission java.util.PropertyPermission "java.vendor", "read";

  22.        permission java.util.PropertyPermission "java.vendor.url", "read";

  23.        permission java.util.PropertyPermission "java.class.version", "read";

  24.        permission java.util.PropertyPermission "os.name", "read";

  25.        permission java.util.PropertyPermission "os.version", "read";

  26.        permission java.util.PropertyPermission "os.arch", "read";

  27.        permission java.util.PropertyPermission "file.separator", "read";

  28.        permission java.util.PropertyPermission "path.separator", "read";

  29.        permission java.util.PropertyPermission "line.separator", "read";


  30.        permission java.util.PropertyPermission "java.specification.version", "read";

  31.        permission java.util.PropertyPermission "java.specification.vendor", "read";

  32.        permission java.util.PropertyPermission "java.specification.name", "read";


  33.        permission java.util.PropertyPermission "java.vm.specification.version", "read";

  34.        permission java.util.PropertyPermission "java.vm.specification.vendor", "read";

  35.        permission java.util.PropertyPermission "java.vm.specification.name", "read";

  36.        permission java.util.PropertyPermission "java.vm.version", "read";

  37.        permission java.util.PropertyPermission "java.vm.vendor", "read";

  38.        permission java.util.PropertyPermission "java.vm.name", "read";

  39. };

文件中分两部分授权:

  1. ext下的文件全部授权。

  2. 其他文件授予特定的权限,比如线程可以调用 stop
     方法(permission java.lang.RuntimePermission "stopThread"),可以读取系统的 java.version
     属性(permission java.util.PropertyPermission "java.version", "read")等等。

我们写一个例子尝试授权是否能生效:

  1. public static void main(String[] args) throws Exception {

  2.    Thread t = new Thread(new Runnable() {

  3.        @Override

  4.        public void run() {

  5.            try {

  6.                Thread.sleep(1000);

  7.            } catch (InterruptedException e) {

  8.                e.printStackTrace();

  9.            }

  10.        }

  11.    });

  12.    t.start();


  13.    t.stop();

  14.    System.out.println("stop finish");

  15. }

注释掉java.policy里stopThread的那行,执行main方法,会出现拒绝访问的exception:

  1. Exception in thread "main" java.security.AccessControlException: access denied ("java.lang.RuntimePermission" "stopThread")

  2.    at java.security.AccessControlContext.checkPermission(AccessControlContext.java:472)

  3.    at java.security.AccessController.checkPermission(AccessController.java:884)

  4.    at java.lang.SecurityManager.checkPermission(SecurityManager.java:549)

  5.    at java.lang.Thread.stop(Thread.java:843)

  6.    at com.github.SecurityManagerTest.main(SecurityManagerTest.java:38)

当然,我们也可以使用自己定义的policy文件,只需要在JVM的启动参数中加上 -Djava.security.policy=/Users/Benjamin/Desktop/my.policy
即可。等号后面是自定义的policy文件地址。



如果读完觉得有收获的话,欢迎点赞、关注、加公众号【蹲厕所的熊】,查阅更多精彩历史!!!

文章转载自蹲厕所的熊,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论