OJ在线评测系统 后端判题机架构搭建 使用原生实现Java安全管理器环境隔离
原生实现安全管理器环境隔离
限制用户的操作权限 文件 网络 执行
Java安全管理器
SecurityManager 来实现更严格的限制
是 Java 提供的保护 JVM Java安全的机制 可以实现更严格的资源和操作限制
编写安全管理器 只需要继承 SecurityManager类
我们可以从这个参数perm参数拿到数据
package work.bigdata1421.dduojcodesandbox.security;
import java.security.Permission;
/**
* 默认的安全管理器
*/
public class DefaultSecurityManager extends SecurityManager{
// 检查所有的权限
@Override
public void checkPermission(Permission perm) {
System.out.println("默认不做任何限制");
super.checkPermission(perm);
}
}
接下来我们去使用这个原生的资源管理器
写一个能抛异常的
package work.bigdata1421.dduojcodesandbox.security;
import java.security.Permission;
/**
* 禁止所有的权限安全管理器
*/
public class DenySecurityManager extends SecurityManager{
// 检查所有的权限
@Override
public void checkPermission(Permission perm) {
throw new SecurityException("权限异常"+perm.getActions());
}
}
我们去尝试下怎么样让有些权限生效 有些程序不生效
这边进行了报错
实现MySecurityManager
package work.bigdata1421.dduojcodesandbox.security;
import java.security.Permission;
public class MySecurityManager extends SecurityManager {
// 检查所有的权限
@Override
public void checkPermission(Permission perm) {
// super.checkPermission(perm);
}
// 检测程序是否可执行文件
@Override
public void checkExec(String cmd) {
throw new SecurityException("checkExec 权限异常:" + cmd);
}
// 检测程序是否允许读文件
@Override
public void checkRead(String file) {
System.out.println(file);
if (file.contains("C:\\code\\yuoj-code-sandbox")) {
return;
}
// throw new SecurityException("checkRead 权限异常:" + file);
}
// 检测程序是否允许写文件
@Override
public void checkWrite(String file) {
// throw new SecurityException("checkWrite 权限异常:" + file);
}
// 检测程序是否允许删除文件
@Override
public void checkDelete(String file) {
// throw new SecurityException("checkDelete 权限异常:" + file);
}
// 检测程序是否允许连接网络
@Override
public void checkConnect(String host, int port) {
// throw new SecurityException("checkConnect 权限异常:" + host + ":" + port);
}
}
做一个测试
package work.bigdata1421.dduojcodesandbox.security;
import cn.hutool.core.io.FileUtil;
import java.nio.charset.Charset;
/**
* 测试安全管理器
*/
public class TestSecurityManager {
public static void main(String[] args) {
System.setSecurityManager(new MySecurityManager());
FileUtil.writeString("aa", "aaa", Charset.defaultCharset());
}
}
看到了哪些内容是可以读的
这边只要使用了资源管理器 默认是把所有权限都禁用的
所有权限拒绝
实际情况下 我们只需要限制子程序的权限即可
没必要限制开发者自己写的程序
在运行java程序时 指定安全管理器
String runCmd = String.format("java -Xmx256m -Djava.security.manager=MySecurityManager %s Main ", userCodeParentPath, inputArgs);
我们改造成一个单独的东西
在 Java 中,配置类通常用于集中管理应用程序的配置信息。配置类可以从外部文件(如 XML、properties 文件)或其他来源读取设置。以下是几种常见的方法来加载和使用配置类:
定义一个常量
把路径指定进来
编写安全管理器
编译安全管理器
javac -encoding utf-8 .\MySecurityManager.java
首先运行java程序的时候 指定安全管理器 路径 名称
缺点
如果要做的比较严格的权限限制 需要自己去判断哪些文件 包名需要读写 粒度太细了
安全管理器本身也是Java代码 也可能存在漏洞
还是程序上的控制 没有到系统层面进行控制
Java9 后被取代
优点
权限控制灵活 实现简单
运行环境隔离
系统层面上 把用户程序封装到沙箱里
和宿主机 我们的电脑 服务器 隔离开
Docker 容器技术能够实现 cgroup namespace