[Java Security]Java资源访问的安全控制

Java资源访问的安全控制

在JDK的API中经常会看到SecurityManager的应用,例如System.getProperty

public static String getProperty(String key) {
    checkKey(key);
    SecurityManager sm = getSecurityManager();
    if (sm != null) {
        sm.checkPropertyAccess(key);
    }
    return props.getProperty(key);
}

不了解Java安全体系的话,可能并不知道中间几行代码的具体作用。本文先简单介绍下Java安全体系中的资源访问控制机制。

1. 资源访问控制

要控制Java程序的资源访问权限,主要有两点:
一是,定义访问策略,即java policy文件,简单的说就是资源访问授权,默认的policy文件为$JAVA_HOME/jre/lib/security/java.policy,内容如下:

// Standard extensions get all permissions by default

grant codeBase "file:${{java.ext.dirs}}/*" {
        permission java.security.AllPermission;
};

// default permissions granted to all domains

grant { 
        // Allows any thread to stop itself using the java.lang.Thread.stop()
        // method that takes no argument.
        // Note that this permission is granted by default only to remain
        // backwards compatible.
        // It is strongly recommended that you either remove this permission
        // from this policy file or further restrict it to code sources
        // that you specify, because Thread.stop() is potentially unsafe.
        // See the API specification of java.lang.Thread.stop() for more
        // information.
        permission java.lang.RuntimePermission "stopThread";

        // allows anyone to listen on un-privileged ports
        permission java.net.SocketPermission "localhost:1024-", "listen";

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

        permission java.util.PropertyPermission "java.version", "read";
        permission java.util.PropertyPermission "java.vendor", "read";
        permission java.util.PropertyPermission "java.vendor.url", "read";
        permission java.util.PropertyPermission "java.class.version", "read";
        permission java.util.PropertyPermission "os.name", "read";
        permission java.util.PropertyPermission "os.version", "read";
        permission java.util.PropertyPermission "os.arch", "read";
        permission java.util.PropertyPermission "file.separator", "read";
        permission java.util.PropertyPermission "path.separator", "read";
        permission java.util.PropertyPermission "line.separator", "read";

        permission java.util.PropertyPermission "java.specification.version", "read";
        permission java.util.PropertyPermission "java.specification.vendor", "read";
        permission java.util.PropertyPermission "java.specification.name", "read";

        permission java.util.PropertyPermission "java.vm.specification.version", "read";
        permission java.util.PropertyPermission "java.vm.specification.vendor", "read";
        permission java.util.PropertyPermission "java.vm.specification.name", "read";
        permission java.util.PropertyPermission "java.vm.version", "read";
        permission java.util.PropertyPermission "java.vm.vendor", "read";
        permission java.util.PropertyPermission "java.vm.name", "read";
};

授予JDK的ext目录下代码全部访问权限,授予其余任意代码的一系列默认权限。
使用Java自带的policytool工具可以创建Policy文件,具体参考Policy File Creation and Management

二是,启动SecurityManager,默认情况下Java是不启动安全检查的。运行Java程序需带上-Djava.security.manager参数即可启动安全校验,例如:

java -Djava.security.manager SecurityTest

只此两步即可开启资源访问的授权控制。

2. 访问控制示例

编写一段代码,完成读取系统属性、读文件、写文件三个操作,示例如下:

public static void main(String[] args) throws Exception {
    // properties
    System.out.println("properties:");
    String[] properties = { "os.name", "java.version", "java.home", "user.home", "java.ext.dirs" };
    for (String prop : properties) {
        String value = System.getProperty(prop);
        System.out.println(prop + " = " + value);
    }

    // read file
    System.out.println();
    System.out.println("read file:");
    String file = "E:\\download\\col_iplib.txt";
    BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(file)));
    String line = reader.readLine();
    System.out.println("read line: " + line);
    reader.close();

    // write file
    System.out.println();
    System.out.println("write file:");
    file = "E:\\download\\security-test.txt";
    BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file)));
    line = "test java security";
    writer.write(line);
    writer.newLine();
    System.out.println("write line: " + line);
    writer.close();
}

在不开启安全检查时,可以正常运行,结果如下:

E:\workspace\proj\alg\target\classes>java com.github.myron.security.SecurityTest
properties:
os.name = Windows 7
java.version = 1.8.0_40
java.home = C:\Program Files\Java\jre1.8.0_40
user.home = C:\Users\gengmaozhang01
java.ext.dirs = C:\Program Files\Java\jre1.8.0_40\lib\ext;C:\windows\Sun\Java\lib\ext

read file:
read line: 1.0.1.0|1.0.3.255:CN|福建|None|None|CHINANET|None|None

write file:
write line: test java security

当开启安全检查时,即会报错。

E:\workspace\proj\alg\target\classes>java -Djava.security.manager com.github.myron.security.SecurityTest
properties:
os.name = Windows 7
java.version = 1.8.0_40
Exception in thread "main" java.security.AccessControlException: access denied ("java.util.PropertyPermission" "java.home" "read")
        at java.security.AccessControlContext.checkPermission(Unknown Source)
        at java.security.AccessController.checkPermission(Unknown Source)
        at java.lang.SecurityManager.checkPermission(Unknown Source)
        at java.lang.SecurityManager.checkPropertyAccess(Unknown Source)
        at java.lang.System.getProperty(Unknown Source)
        at com.github.myron.security.SecurityTest.main(SecurityTest.java:30)

因为Java默认的java.policy文件并未授予所有程序读取java.home的权限,及文件读写权限。

使用policytool工具创建自己的policy文件,授予上述系统属性、文件读写的权限,如下:
这里写图片描述
生成的policy文件如下:

/* AUTOMATICALLY GENERATED ON Sun Oct 23 20:30:42 CST 2016*/
/* DO NOT EDIT */

grant codeBase "file:/E:/workspace/proj/alg/target/classes/*" {
  permission java.io.FilePermission "<<ALL FILES>>", "read, write";
  permission java.util.PropertyPermission "java.home", "read";
  permission java.util.PropertyPermission "user.home", "write, read";
  permission java.util.PropertyPermission "java.ext.dirs", "read";
};

使用-Djava.security.policy参数指定该policy策略,执行正常:

E:\workspace\proj\alg\target\classes>java -Djava.security.manager -Djava.security.policy=E:/download/my.java.policy com.github.myron.security.SecurityTest
properties:
os.name = Windows 7
java.version = 1.8.0_40
java.home = C:\Program Files\Java\jre1.8.0_40
user.home = C:\Users\gengmaozhang01
java.ext.dirs = C:\Program Files\Java\jre1.8.0_40\lib\ext;C:\windows\Sun\Java\lib\ext

read file:
read line: 1.0.1.0|1.0.3.255:CN|福建|None|None|CHINANET|None|None

write file:
write line: test java security

3. 自定义权限控制

在具体项目中,除了常见的系统资源,还有其他业务资源需要进行访问控制,这里就以消息服务为例来演示自定义的权限控制。

首先,定义自己的资源权限,如下:

public class MessagePermission extends BasicPermission {

    private static final long serialVersionUID = -6179037573716029507L;

    public static final String MESSAGE_READ_ACTION = "readMessage";
    public static final String MESSAGE_WRITE_ACTION = "writeMessage";

    private String actions;

    public MessagePermission(String name) {
        super(name);
    }

    public MessagePermission(String name, String actions) {
        // NOTE: actions is ignored by BasicPermission
        super(name, actions);
        this.actions = actions;
    }

    @Override
    public String getActions() {
        return actions;
    }

    // 简单的Actions比较实现,更精细的实现可参考PropertyPermission
    @Override
    public boolean implies(Permission p) {
        if (super.implies(p)) {
            MessagePermission mp = (MessagePermission) p;
            if (mp.getActions() == null || mp.getActions().isEmpty()) {
                return true;
            }
            if (this.actions == null || this.actions.isEmpty()) {
                return false;
            }
            if (this.actions.contains(mp.getActions())) {
                return true;
            }
            return false;
        }
        return false;
    }

}

然后,编写有安全校验的消息读写程序,代码如下:

public class SecurityMessageService {

    public static final String MESSAGE_NAME = "SecurityMessage";

    public void readMessage() {
        SecurityManager sm = System.getSecurityManager();
        if (sm != null) {
            sm.checkPermission(new MessagePermission(MESSAGE_NAME, MessagePermission.MESSAGE_READ_ACTION));
        }
        // do something
        System.out.println("read message done");
    }

    public void writeMessage() {
        SecurityManager sm = System.getSecurityManager();
        if (sm != null) {
            sm.checkPermission(new MessagePermission(MESSAGE_NAME, MessagePermission.MESSAGE_WRITE_ACTION));
        }
        // do something
        System.out.println("write message done");
    }

    public static void main(String[] args) {
        SecurityMessageService messageService = new SecurityMessageService();

        // read
        messageService.readMessage();
        // write
        messageService.writeMessage();
    }

}

直接开启安全检查执行,抛出了无消息读写权限的异常:

E:\workspace\proj\alg\target\classes>java -Djava.security.manager com.github.myron.security.SecurityMessageService
Exception in thread "main" java.security.AccessControlException: access denied ("com.github.myron.security.MessagePermis
sion" "SecurityMessage" "readMessage")
        at java.security.AccessControlContext.checkPermission(Unknown Source)
        at java.security.AccessController.checkPermission(Unknown Source)
        at java.lang.SecurityManager.checkPermission(Unknown Source)
        at com.github.myron.security.SecurityMessageService.readMessage(SecurityMessageService.java:17)
        at com.github.myron.security.SecurityMessageService.main(SecurityMessageService.java:36)

最后,创建policy策略文件,授予消息读写权限,如下:

/* AUTOMATICALLY GENERATED ON Sun Oct 23 22:17:00 CST 2016*/
/* DO NOT EDIT */

grant codeBase "file:/E:/workspace/proj/alg/target/classes/*" {
  permission com.github.myron.security.MessagePermission "SecurityMessage", "readMessage,writeMessage";
};

执行正常完成,结果如下:

E:\workspace\proj\alg\target\classes>java -Djava.security.manager -Djava.security.policy=E:/download/message.policy com.github.myron.security.SecurityMessageService
read message done
write message done

参考:
1. Trail: Security Features in Java SE
2. 自定义java.policy配置
3. Java程序访问权限控制(policy文件)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值