1. 方法定义

public static SecurityManager getSecurityManager()
  • 返回当前安装的 SecurityManager 对象
  • 如果没有安装安全管理器,则返回 null

2. 功能说明

  • 安全策略执行者:安全管理器定义应用程序的安全策略
  • 权限检查入口:控制对敏感资源的访问(文件、网络、系统属性等)
  • 访问控制决策:通过 checkPermission() 方法决定是否允许操作
  • 默认状态:标准Java应用默认不安装安全管理器

3. 示例代码

基本使用
public class SecurityManagerDemo {
    public static void main(String[] args) {
        // 获取当前安全管理器
        SecurityManager sm = System.getSecurityManager();
        
        if (sm != null) {
            System.out.println("SecurityManager installed: " + sm.getClass().getName());
            
            // 检查文件读取权限
            try {
                sm.checkRead("/etc/passwd");
                System.out.println("File read allowed");
            } catch (SecurityException e) {
                System.err.println("File read denied: " + e.getMessage());
            }
        } else {
            System.out.println("No SecurityManager installed");
        }
    }
}
自定义安全管理器
class CustomSecurityManager extends SecurityManager {
    @Override
    public void checkRead(String file) {
        if (file.contains("secret")) {
            throw new SecurityException("Access to secret files denied");
        }
    }
}

public class CustomSecurityDemo {
    public static void main(String[] args) {
        // 安装自定义安全管理器
        System.setSecurityManager(new CustomSecurityManager());
        
        try {
            // 尝试读取敏感文件
            new FileInputStream("secret_data.txt");
        } catch (IOException | SecurityException e) {
            System.err.println("操作被阻止: " + e.getMessage());
        }
    }
}

4. 使用技巧

  • 权限检查封装:在关键操作前主动检查权限

    SecurityManager sm = System.getSecurityManager();
    if (sm != null) {
        sm.checkPermission(new FilePermission("/data/*", "read"));
    }
    
  • 沙箱环境检测:判断代码是否在受限环境中运行

    boolean inSandbox = (System.getSecurityManager() != null);
    
  • 临时权限检查:绕过安全检查(仅用于测试)

    SecurityManager original = System.getSecurityManager();
    try {
        System.setSecurityManager(null);
        // 执行需要权限的操作
    } finally {
        System.setSecurityManager(original);
    }
    

5. 常见错误

  1. 空指针异常

    System.getSecurityManager().checkExit(0); // 可能抛出NPE
    

    修复

    SecurityManager sm = System.getSecurityManager();
    if (sm != null) sm.checkExit(0);
    
  2. 过度权限限制

    // 自定义管理器错误实现
    public void checkRead(String file) {
        // 忘记调用super,导致所有访问被拒绝
        throw new SecurityException("Denied by default");
    }
    
  3. 策略文件不匹配

    # policy文件错误配置
    grant {
        permission java.io.FilePermission "/tmp/-", "read"; # 缺少分号
    };
    

6. 注意事项

  • 安装时机:安全管理器必须在应用启动早期安装(setSecurityManager() 只能调用一次)
  • 策略文件:通过 -Djava.security.policy=file.policy 指定权限规则
  • 权限继承:未明确允许的操作默认被拒绝
  • 模块系统冲突:Java 9+ 中与模块系统的权限模型存在兼容性问题

7. 最佳实践与性能优化

  1. 最小权限原则

    // 精确控制权限范围
    sm.checkPermission(new FilePermission("/app/logs/-", "read,write"));
    
  2. 缓存安全检查结果

    // 避免重复检查
    private static final boolean FILE_ACCESS_ALLOWED = 
        checkPermission("java.io.FilePermission", "/data", "read");
    
    private static boolean checkPermission(String type, String name, String action) {
        SecurityManager sm = System.getSecurityManager();
        if (sm == null) return true;
        try {
            sm.checkPermission((Permission)Class.forName(type)
                .getConstructor(String.class, String.class)
                .newInstance(name, action));
            return true;
        } catch (SecurityException e) {
            return false;
        } catch (Exception e) {
            return false; // 处理反射异常
        }
    }
    
  3. 现代替代方案(Java 9+)

    // 使用模块系统替代安全管理器
    module com.example.app {
        requires java.base;
        exports com.example.api;
        opens com.example.internal to trusted.module;
    }
    
  4. 性能敏感操作

    • 将安全检查移出热代码路径
    • 在初始化阶段预先检查权限

8. 安全管理器生命周期

graph TD
    A[应用启动] --> B{安全管理器已安装?}
    B -->|否| C[默认无限制访问]
    B -->|是| D[创建SecurityManager]
    D --> E[加载policy文件]
    E --> F[建立权限映射]
    F --> G[运行时权限检查]
    G --> H{操作请求}
    H -->|允许| I[执行操作]
    H -->|拒绝| J[抛出SecurityException]

9. 策略文件示例

security.policy

// 基础授权
grant {
    // 允许读取所有文件
    permission java.io.FilePermission "<<ALL FILES>>", "read";
    
    // 允许监听特定端口
    permission java.net.SocketPermission "localhost:8080", "listen";
    
    // 允许设置特定系统属性
    permission java.util.PropertyPermission "app.*", "write";
};

10. 总结

关键点 说明
核心作用 执行Java安全策略,控制对敏感资源的访问
默认状态 未安装(返回null),应用拥有完全权限
安装方式 System.setSecurityManager()-Djava.security.manager 启动参数
权限决策 通过 checkPermission() 实现基于策略文件的访问控制
典型应用场景 应用沙箱、插件系统、第三方代码执行环境
Java版本演进 Java 17中标记为过时,Java 21中默认禁用,推荐使用模块系统替代
性能影响 每次安全检查都有开销,需谨慎设计

现代Java开发建议

  1. 新项目:优先使用Java模块系统(JPMS)实现隔离
  2. 旧系统迁移
    // 使用条件兼容
    if (System.getSecurityManager() != null) {
        sm.checkPermission(new RuntimePermission("customPermission"));
    }
    
  3. 必要场景:仅在小范围代码使用,避免全局安全管理器
  4. 策略配置:遵循最小权限原则,精确指定所需权限