该文章写的很烂,只是一些思路,具体细节还在实现,由于时间问题,一些细节我也没有展开详细说,后续可能还会出更具体的文章。本人也只是学习阶段,如果你对这方面有兴趣,具有一定水平,可以与我探讨java实现oj问题。
参考以下文档,如有侵权,联系删除
版权声明:本文为CSDN博主「zhaopeng.chau」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。 原文链接:Java沙箱机制的实现——安全管理器、访问控制器_zhaopeng.chau的博客-CSDN博客_有哪些方式可以实现安全控制器?
本文档是针对如何写一个安全的java沙盒,以防止oj提交代码对本机的侵害
/** * SecurityManager安全管理器,对文件的读写删除和执行、网络的连接和监听、线程的访问、以及其他包括打印剪贴板等系统资源的访问。 * 一般而言,Java程序启动时并不会自动启动安全管理器,可以通过以下两种方法启动安全管理器: * * 隐式启用,启动默认的安全管理器最简单的方式就是:直接在启动命令中添加 -Djava.security.manager 参数即可。 * 显示启用,实例化一个 java.lang.SecurityManager 或继承它的子类的对象,然后通过 System.setSecurityManager() 来设置并启动一个安全管理器。 */
不详细讲安全管理器中的ckeck方法
/** * SecurityManager 中所有 check方法的实现,都是基于 AccessController的。 * AccessController。这是一个无法实例化的类——仅仅可以使用其static方法。AccessController最重要的方法就是 * checkPermission()方法,作用是基于已经安装的Policy对象,能否得到某个权限。 */
首先了解访问控制器构造:理解4个概念:代码源、权限、策略和保护域。
代码源CodeSource:就是一个简单的类,用来声明从哪里加载类,对其进行封装。
权限Permission:Permission本身是一个抽象类,但它的一个实例代表了一个具体的权限。它是AccessController处理的基本实体。
策略Policy:策略是一组权限的总称,用于确定权限应该用于哪些代码源。代码源标识了类的来源,权限声明了具体的限制。那么策略就是将二者联合起来。Java使用了Policy对安全策略进行封装,我们可以通过java.policy文件去声明一个安全策略,-Djava.security.policy指定安全策略的地址。如果我们启动了安全管理器但没有指定一个安全策略,那么系统就用使用Java默认的安全策略。
保护域ProtectionDomain:保护域是一个代码源的一组权限,而策略是所有的代码源对应的所有的权限的关系。JVM中的每一个类都一定属于且仅属于一个保护域,这由ClassLoader在define class的时候决定。同时代码源所在保护域包含的权限集规定了一些权限,这个类就拥有这些权限。
安全。根据双亲委派原则避免核心类库被随意篡改以及系统类(作者自己写的类)被修改
如果在java进程中使用使用以上操作,通过加载class文件来获取一个class对象,然后在线程中调用对象的方法,好处就是灵活,也可以计算线程的运行时间,坏处就是堆内存是堆进程共享的,难以计算线程的内存。还有就是安全管理器只能针对全局,开启安全管理器自己本身java程序也会受到影响。
另一种思路是利用Runtime.getRuntime().exec去调用一个cmd窗口来运行另一个java程序,在main方法重定向输入文件,内存,时间,安全都解决了,但是需要用户每次都去用 new Scanner(System.in)很麻烦。
我本人也在思考要怎么实现?
用string来存
String的内部实现 通过一个字符数组来维护字符序列,其声名如下:
private final char value[];
String在内存中的最大长度理论上是int型变量的最大值,Integer.MAX_VALUE, String的字面常量的最大长度为CONSTANT_Utf8_info表决定,一般为65535.
runtime执行命令,输入流和错误流不断有流进入存储到jvm的缓存区,如果缓存区的流不被读取,填满时候会造成runtime的死锁阻塞,
最好还是用nio而不是io,因为Java IO的各种流是阻塞的。这意味着,当一个线程调用read() 或 write()时,该线程被阻塞,直到有一些数据被读取,或数据完全写入。该线程在此期间不能再干任何事情了。如果你想实现一边输入值一边获取值是行不通,因为获取值会导致阻塞,而不能进行下一次输入。
// 参数cmdArray 示例:shutdown -s -t 3600 String arr[] = {"shutdown","-s","-t","3600"}; Process process = Runtime.getRuntime().exec(arr[]); /* 注意: 在调用这个方法时,不能将命令和参数放在一起,eg:String arr[] = {"shutdown -s -t 3600"}; 这样会导致程序把“shutdown -s -t 3600”当成是一条命令的名称,然后去查找“shutdown -s -t 3600”这条命令,它当然会找不到,所以就会报错 */
-Xmx Java Heap最大值,默认值为物理内存的1/4,最佳设值应该视物理内存大小及计算机内其他内存开销而定;
-Xms Java Heap初始值,Server端JVM最好将-Xms和-Xmx设为相同值,开发测试机JVM可以保留默认值;
例如:java -Xmx128m -Xms64m -Xmn32m -Xss16m Test
内存不能太小,太小运行不起来
envp // 字符串数组,其中每个元素的环境变量的设置格式为 name=value,如果子进程应该继承当前进程的环境,则该参数为null
格式为 -Xmx=128m -Xms=128m