Java安全管理器之SecurityManager

什么是Java安全管理器

就是Java应运行时,会使用安全管理器,检查应用的访问权限和策略,保护资源别被攻击。当安全管理器检测到违反安全策略的操作时,JVM将引发AccessControlException或SecurityException。
当运行外部的java应用的时候,会使用SecurityManager来对外部运行的java代码权限进行控制。

  • 策略:类加载器会使用Policy类,来分配java应用的权限和操作动作(Read、Write)。
  • 保护域:保护域是为每一个java类型分配的,授予java代码权限。

默认的安全管理器配置文件是 $JAVA_HOME/jre/lib/security/java.policy

## jdk8

// 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 dynamic ports
        permission java.net.SocketPermission "localhost:0", "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";
};

Java安全管理器启动方式

  • 方式1,编码方式启动(不推荐)
    继承SecurityManager类,然后设置到系统中
System.setSecurityManager(new SecurityManager());
  • 方式2,jvm参数启动
    如果不需要指定策略,那么也是可以的
-Djava.security.manager -Djava.security.policy="F:/gen/sunpeiyu.policy"

编码方式启动校验

SecurityManager支持的check检查方法

1. 文件和文件夹相关
  • checkRead(String file)
    • 检查是否有读取指定文件的权限。
    • 示例:SecurityManager sm = System.getSecurityManager(); sm.checkRead("example.txt");
  • checkWrite(String file)
    • 检查是否有写入指定文件的权限。
    • 示例:sm.checkWrite("example.txt");
  • checkDelete(String file)
    • 检查是否有删除指定文件的权限。
    • 示例:sm.checkDelete("example.txt");
  • checkAccess(FileDescriptor fd)
    • 检查是否有访问指定文件描述符的权限。
    • 示例:sm.checkAccess(FileDescriptor.out);
2. 系统属性相关
  • checkPropertyAccess(String key)
    • 检查是否有访问指定系统属性的权限。
    • 示例:sm.checkPropertyAccess("java.version");
  • checkSystemClipboardAccess()
    • 检查是否有访问系统剪贴板的权限。
    • 示例:sm.checkSystemClipboardAccess();
3. 线程和线程组相关
  • checkAccess(Thread t)
    • 检查是否有访问指定线程的权限。
    • 示例:sm.checkAccess(Thread.currentThread());
  • checkAccess(ThreadGroup g)
    • 检查是否有访问指定线程组的权限。
    • 示例:sm.checkAccess(Thread.currentThread().getThreadGroup());
4. 网络相关
  • checkConnect(String host, int port)
    • 检查是否有连接到指定主机和端口的权限。
    • 示例:sm.checkConnect("www.example.com", 80);
  • checkListen(int port)
    • 检查是否有监听指定端口的权限。
    • 示例:sm.checkListen(8080);
  • checkAccept(String host, int port)
    • 检查是否有接受来自指定主机和端口的连接的权限。
    • 示例:sm.checkAccept("localhost", 8080);
5. 类加载器相关
  • checkPackageAccess(String pkg)
    • 检查是否有访问指定包的权限。
    • 示例:sm.checkPackageAccess("java.lang");
  • checkPackageDefinition(String pkg)
    • 检查是否有定义指定包的权限。
    • 示例:sm.checkPackageDefinition("com.example.myapp");
6. 其他
  • checkExit(int status)
    • 检查是否有退出虚拟机的权限。
    • 示例:sm.checkExit(0);
  • checkPrintJobAccess()
    • 检查是否有访问打印任务的权限。
    • 示例:sm.checkPrintJobAccess();
  • checkAwtEventQueueAccess()
    • 检查是否有访问 AWT 事件队列的权限。
    • 示例:sm.checkAwtEventQueueAccess();

SecurityManager自带的方法检查文件权限

-Djava.security.manager -Djava.security.policy="F:/gen/sunpeiyu.policy"
public class Son {

    public void checkFileReadPermission(String path) {
        SecurityManager securityManager = System.getSecurityManager();
        securityManager.checkRead(path);
    }

    public static void main(String[] args) {
        try {
            new Son().checkFileReadPermission("F:\\gen\\dest.txt");
        } catch (SecurityException e) {
            System.out.println("不存在文件读取权限");
        }
    }
}

image

policy文件控制授权策略

自定义编写授权策略文件

F:/gen/sunpeiyu.policy

-Djava.security.manager -Djava.security.policy="F:/gen/sunpeiyu.policy"
grant {
	permission java.io.FilePermission "F:\\gen\\dest.txt", "read,write";
};
public class Son {

    public void checkFileReadPermission(String path) {
        SecurityManager securityManager = System.getSecurityManager();
        securityManager.checkRead(path);
    }

    public static void main(String[] args) {
        try {
            new Son().checkFileReadPermission("F:\\gen\\dest.txt");
            System.out.println("文件读取已授权");
        } catch (SecurityException e) {
            System.out.println("不存在文件读取权限");
        }
    }
}

image

policy文件配置语法

  • 给所有程序赋予权限
grant { 
    permission java.security.AllPermission;
};
  • 指定文件夹下的.class类赋予读取指定文件夹下的文件权限
// F:/java_item/test/target/classes/com/sunpy文件夹下的class有读写C:\\Users\\Administrator\\Desktop\\test\\下的文件的权限
grant codebase "file:F:/java_item/test/target/classes/com/sunpy/-"
{
permission java.io.FilePermission
"C:\\Users\\Administrator\\Desktop\\test\\*", "read,write";
};

policy文件授权更小的粒度

权限目标名称权限所允许的操作允许此权限所带来的风险
createClassLoader创建类加载器授予该权限极其危险。能够实例化自己的类加载器的恶意应用程序可能会在系统中装载自己的恶意类。这些新加载的类可能被类加载器置于任意保护域中,从而自动将该域的权限授予这些类。
getClassLoader类加载器的获取(即调用类的类加载器)这将授予攻击者得到具体类的加载器的权限。这很危险,由于攻击者能够访问类的类加载器,所以攻击者能够加载其他可用于该类加载器的类。通常攻击者不具备这些类的访问权限。
setContextClassLoader线程使用的上下文类加载器的设置在需要查找可能不存在于系统类加载器中的资源时,系统代码和扩展部分会使用上下文类加载器。授予 setContextClassLoader 权限将允许代码改变特定线程(包括系统线程)使用的上下文类加载器。
enableContextClassLoaderOverride线程上下文类加载器方法的子类实现在需要查找可能不存在于系统类加载器中的资源时,系统代码和扩展部分会使用上下文类加载器。授予 enableContextClassLoaderOverride 权限将允许线程的子类重写某些方法,这些方法用于得到或设置特定线程的上下文类加载器。
setSecurityManager设置安全管理器(可能会替换现有的)安全管理器是允许应用程序实现安全策略的类。授予 setSecurityManager 权限将通过安装一个不同的、可能限制更少的安全管理器,来允许代码改变所用的安全管理器,因此可跳过原有安全管理器所强制执行的某些检查。
createSecurityManager创建新的安全管理器授予代码对受保护的、敏感方法的访问权,可能会泄露有关其他类或执行堆栈的信息。
getenv.{variable name}读取指定环境变量的值此权限允许代码读取特定环境变量的值或确定它是否存在。如果该变量含有机密数据,则这项授权是很危险的。
exitVM.{exit status}暂停带有指定退出状态的 Java 虚拟机此权限允许攻击者通过自动强制暂停虚拟机来发起一次拒绝服务攻击。注意:自动为那些从应用程序类路径加载的全部代码授予 "exitVM.*" 权限,从而使这些应用程序能够自行中止。此外,"exitVM" 权限等于 "exitVM.*"。
shutdownHooks虚拟机关闭钩子 (hook) 的注册与取消此权限允许攻击者注册一个妨碍虚拟机正常关闭的恶意关闭钩子 (hook)。
setFactory设置由 ServerSocket 或 Socket 使用的套接字工厂,或 URL 使用的流处理程序工厂此权限允许代码设置套接字、服务器套接字、流处理程序或 RMI 套接字工厂的实际实现。攻击者可能设置错误的实现,从而破坏数据流。
setIOSystem.out、System.in 和 System.err 的设置此权限允许改变标准系统流的值。攻击者可以改变 System.in 来监视和窃取用户输入,或将 System.err 设置为 "null" OutputStream,从而隐藏发送到 System.err 的所有错误信息。
modifyThread修改线程,例如通过调用线程的 interrupt、stop、suspend、resume、setDaemon、setPriority、setName 和 setUncaughtExceptionHandler 方法此权限允许攻击者修改系统中任意线程的行为。
stopThread通过调用线程的 stop 方法停止线程如果系统已授予代码访问该线程的权限,则此权限允许代码停止系统中的任何线程。此权限会造成一定的危险,因为该代码可能通过中止现有的线程来破坏系统。
modifyThreadGroup修改线程组,例如通过调用 ThreadGroup 的 destroygetParentresumesetDaemonsetMaxPrioritystop 和 suspend 方法此权限允许攻击者创建线程组并设置它们的运行优先级。
getProtectionDomain获取类的 ProtectionDomain此权限允许代码获得特定代码源的安全策略信息。虽然获得安全策略信息并不足以危及系统安全,但这确实会给攻击者提供了能够更好地定位攻击目标的其他信息,例如本地文件名称等。
getFileSystemAttributes获取文件系统属性此权限允许代码获得文件系统信息(如调用者可用的磁盘使用量或磁盘空间)。这存在潜在危险,因为它泄露了关于系统硬件配置的信息以及一些关于调用者写入文件特权的信息。
readFileDescriptor读取文件描述符此权限允许代码读取与文件描述符读取相关的特定文件。如果该文件包含机密数据,则此操作非常危险。
writeFileDescriptor写入文件描述符此权限允许代码写入与描述符相关的特定文件。此权限很危险,因为它可能允许恶意代码传播病毒,或者至少也会填满整个磁盘。
loadLibrary.{库名}动态链接指定的库允许 applet 具有加载本机代码库的权限是危险的,因为 Java 安全架构并未设计成可以防止恶意行为,并且也无法在本机代码的级别上防止恶意行为。
accessClassInPackage.{包名}当类加载器调用 SecurityManager 的checkPackageAccess 方法时,通过类加载器的 loadClass 方法访问指定的包此权限允许代码访问它们通常无法访问的那些包中的类。恶意代码可能利用这些类帮助它们实现破坏系统安全的企图。
defineClassInPackage.{包名}当类加载器调用 SecurityManager 的 checkPackageDefinition 方法时,通过类加载器的 defineClass 方法定义指定的包中的类。此权限允许代码在特定包中定义类。这样做很危险,因为具有此权限的恶意代码可能在受信任的包中定义恶意类,比如 java.security 或 java.lang
accessDeclaredMembers访问类的已声明成员此权限允许代码查询类的公共、受保护、默认(包)访问和私有的字段和/或方法。尽管代码可以访问私有和受保护字段和方法名称,但它不能访问私有/受保护字段数据并且不能调用任何私有方法。此外,恶意代码可能使用该信息来更好地定位攻击目标。而且,它可以调用类中的任意公共方法和/或访问公共字段。如果代码不能用这些方法和字段将对象强制转换为类/接口,那么它通常无法调用这些方法和/或访问该字段,而这可能很危险。
queuePrintJob打印作业请求的开始这可能向打印机输出敏感信息,或者只是浪费纸张。
getStackTrace获取另一个线程的堆栈追踪信息。此权限允许获取另一个线程的堆栈追踪信息。此操作可能允许执行恶意代码监视线程并发现应用程序中的弱点。
setDefaultUncaughtExceptionHandler在线程由于未捕获的异常而突然终止时,设置将要使用的默认处理程序此权限允许攻击者注册恶意的未捕获异常处理程序,可能会妨碍线程的终止
Preferences表示得到 java.util.prefs.Preferences 的访问权所需的权限。java.util.prefs.Preferences 实现了用户或系统的根,这反过来又允许获取或更新 Preferences 持久内部存储中的操作。如果运行此代码的用户具有足够的读/写内部存储的 OS 特权,则此权限就允许用户读/写优先级内部存储。实际的内部存储可能位于传统的文件系统目录中或注册表中,这取决于平台 OS。

指定的class类文件读取指定的文件

F:/gen/sunpeiyu.policy

-Djava.security.manager -Djava.security.policy="F:/gen/sunpeiyu.policy"
grant codeBase "file:F:/java_item/test/target/classes/-" {
	permission java.io.FilePermission "F:\\gen\\dest.txt", "read,write";
};
    public void readFile(String path) {
        try {
            BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(path)));
            String msg = reader.readLine();
            System.out.println("读取 " + path + " 文件内容:" + msg);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        try {
            new Son().readFile("F:\\gen\\dest.txt");
        } catch (SecurityException e) {
            System.out.println("不存在文件读取权限");
        }
    }

image

posted @ 2025-05-04 22:12  sunpeiyu  阅读(57)  评论(0)    收藏  举报