纯JAVA实现Online Judge--3.SecurityManager安全管理器
来源:互联网 发布:如何更改淘宝会员名 编辑:程序博客网 时间:2024/05/18 17:02
前言
上一篇的博文中,我们通过自己编译用户提交的代码,再通过自定制的类加载器将编译出来后的class信息加载进JVM中,最后再通过反射调用用户代码的main,实现了运行用户代码的目的。具体如何运行用户的代码的部分,将会在后面的博客(多线程跑题)中展开述说,里面将介绍我如何利用多线程的方式,同时对同一份用户代码跑多份测试用例,提升效率的同时,如何解决多线程中遇到的冲突问题。
现在首先要解决的是安全问题,既然我们运行用户提交的代码了,这就存在一个风险,如果用户想恶意攻击我们的服务器怎么办?比如用户在提交的代码中,打开远程连接连上远程的服务器,打开网络连接不断下载东西,再或者不断新建文件并写入大量数据,更有甚者直接调用System.exit(status);退出JAVA虚拟机等等。
因为我们直接运行了未知的代码,我们就必须保证我们的服务器安全,不然我们的系统都还没判题几个就被别人搞垮了。我们利用JAVA实现这个安全管理还是挺容易的,因为JAVA提供了SecurityManager安全管理器。每一个JAVA程序在启动的时候,其实内部就设置了一个默认SecurityManager,我们这里只需要继承它,并复写相应的方法即可。
SecurityManager安全管理器
首先,我们先贴上我们安全管理器的代码,然后再稍微分析一下:
package cn.superman.sandbox.core.securityManager;import java.io.FilePermission;import java.lang.reflect.ReflectPermission;import java.security.Permission;import java.security.SecurityPermission;import java.util.PropertyPermission;import java.util.logging.LoggingPermission;import cn.superman.sandbox.constant.ConstantParameter;public class SandboxSecurityManager extends SecurityManager {/** * 防止有人非法退出虚拟机 */@Overridepublic void checkExit(int status) {if (status != ConstantParameter.EXIT_VALUE) {throw new RuntimeException("非法退出,不允许退出虚拟机");}super.checkExit(status);}@Overridepublic void checkPermission(Permission perm) {conformPermissionToSandbox(perm);}@Overridepublic void checkPermission(Permission perm, Object context) {conformPermissionToSandbox(perm);}/** * 只给与必要的权限(比如读取,获取某些信息等),避免提交者进行非法操作。 * * @param perm */private void conformPermissionToSandbox(Permission perm) {if (perm instanceof SecurityPermission) {if (perm.getName().startsWith("getProperty")) {return;}} else if (perm instanceof PropertyPermission) {if (perm.getActions().equals("read")) {return;}} else if (perm instanceof FilePermission) {if (perm.getActions().equals("read")) {return;}} else if (perm instanceof RuntimePermission|| perm instanceof ReflectPermission|| perm instanceof LoggingPermission) {return;}throw new SecurityException(perm.toString() + "无法使用该权限");}}
设置时机
我们在我们的沙箱初始化完成后,并在接收外界数据之前,对其进行设置。至于为什么是这个时机呢?因为我们的沙箱在初始化时就需要用到一定我们限制的权限,比如打开socket等,因此我们要在初始化完成后,因为我们要开始对外服务了(可能需要运行用户的代码了),这个时候就要保证我们沙箱的安全了,所以我们要在开始接收外界数据之前,设置这个安全管理器。
设置的代码很简单:
System.setSecurityManager(new SandboxSecurityManager());
重点内容
其实从代码中可以看出,我们重点做的就是复写checkPermission和checkExit。
复写checkExit是为了防止用户恶意调用System.exit(status);代码退出我们的虚拟机,当我们发现用户恶意调用时,但是他们传过来的数值不对时,我们就直接拒绝他这个请求,并且抛出异常通知上层认定这份代码是非法的。至于正确的退出值是多少,我们可以在程序初始化时,通过随机函数自动生成一个等方式来确立。。
复写checkPermission函数主要是为了,动态捕获用户代码在运行时请求了哪些权限,对于合法符合业务逻辑的权限,我们直接返回即可,给予放行(如反射,读取文件等)。对于非法的权限,我们通过抛出异常的方式,通知上层该用户代码有违法操作,直接判定该份代码为非法。
权限有很多种,大家可以通过查看JDK文档或者其他博文的方式深入理解,下面给出一个权限控制的大概简图:
预告
本篇博文介绍的内容,还不能完全的防止用户提交的恶意代码,因为用户还有可能提交一些死循环的代码,当我们沙箱运行这样的代码时,就会有一个线程陷入死循环,导致服务器的CPU资源被占据不放。当然,排除死循环方式,用户运行的代码也有可能会超时,这个时候我们除了判定用户的代码运行超时之外,我们还要终止运行该线程,尽快释放资源(因为已经得出结果了嘛)。
因此,在下篇博文中,我将会介绍我如何结合OJ的业务逻辑,强行终止(杀死)正在运行的线程。做到限时运行。
- 纯JAVA实现Online Judge--3.SecurityManager安全管理器
- Java 安全管理器--SecurityManager
- Java 安全管理器--SecurityManager
- Java安全管理器SecurityManager
- Java安全管理器SecurityManager
- COPY Java安全管理器SecurityManager
- java安全管理器SecurityManager入门
- 纯JAVA实现Online Judge--1.前言简介
- 纯JAVA实现Online Judge--5.并行运行
- 纯JAVA实现Online Judge--6.完整源码
- Java安全管理器——SecurityManager
- Java安全管理器——SecurityManager
- Java安全管理器——SecurityManager
- Java安全管理器——SecurityManager
- Java安全管理器——SecurityManager
- Java安全管理器——SecurityManager
- Java安全管理器——SecurityManager
- 纯JAVA实现Online Judge--2.代码编译与类加载
- 捕获程序弹出的异常窗口,不让程序弹出异常窗口
- 使用Python中os读取含特殊字符路径的简单办法
- Qt5.5.1使用MySQL之艰难历程
- 利用iTextsharp进行PDF页码旋转
- Notification详解
- 纯JAVA实现Online Judge--3.SecurityManager安全管理器
- SVN 常见错误:
- jquery02
- webUploaderer 插件
- Git(GitHub)学习笔记
- C++之MFC从exe应用转成dll简洁快速方法
- 设计模式(单一职责)——桥模式
- kettle学习之连接数据库资源库执行sql时报错
- linux 的 dd命令详解,dd与cp的区别