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

来源:互联网 发布:谷歌输入法linux版 编辑:程序博客网 时间:2024/05/29 06:40

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 defaultgrant codeBase "file:${{java.ext.dirs}}/*" {        permission java.security.AllPermission;};// default permissions granted to all domainsgrant {         // 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.SecurityTestproperties:os.name = Windows 7java.version = 1.8.0_40java.home = C:\Program Files\Java\jre1.8.0_40user.home = C:\Users\gengmaozhang01java.ext.dirs = C:\Program Files\Java\jre1.8.0_40\lib\ext;C:\windows\Sun\Java\lib\extread file:read line: 1.0.1.0|1.0.3.255:CN|福建|None|None|CHINANET|None|Nonewrite file:write line: test java security

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

E:\workspace\proj\alg\target\classes>java -Djava.security.manager com.github.myron.security.SecurityTestproperties:os.name = Windows 7java.version = 1.8.0_40Exception 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.SecurityTestproperties:os.name = Windows 7java.version = 1.8.0_40java.home = C:\Program Files\Java\jre1.8.0_40user.home = C:\Users\gengmaozhang01java.ext.dirs = C:\Program Files\Java\jre1.8.0_40\lib\ext;C:\windows\Sun\Java\lib\extread file:read line: 1.0.1.0|1.0.3.255:CN|福建|None|None|CHINANET|None|Nonewrite 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.SecurityMessageServiceException in thread "main" java.security.AccessControlException: access denied ("com.github.myron.security.MessagePermission" "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.SecurityMessageServiceread message donewrite message done

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

0 0
原创粉丝点击