Java应用程序的安全沙箱机制是什么
发布时间 - 2023-05-16 00:00:00 点击率:次如果你经常阅读源码,你会发现 java 的源码中到处都有类似于下面这一段代码
class File {
// 判断一个磁盘文件是否存在
public boolean exists() {
SecurityManager security = System.getSecurityManager();
if (security != null) {
security.checkRead(path);
}
...
}
}
这明显是一个安全检查代码,检查的是你是否有访问磁盘路径的权限,为什么 Java 语言需要这样的安全检查代码呢?我们再看看客户端套接字的 connect 函数源码,它需要检查用户是否有connect 某个网络地址的权限
class Socket {
public void connect(SocketAddress endpoint, int timeout) {
...
SecurityManager security = System.getSecurityManager();
if (security != null) {
if (epoint.isUnresolved())
security.checkConnect(epoint.getHostName(), port);
else
security.checkConnect(addr.getHostAddress(), port);
}
}
...
}
}
再看服务端套接字的源码,它会检查端口的监听权限
class ServerSocket {
public void bind(SocketAddress endpoint, int backlog) {
...
SecurityManager security = System.getSecurityManager();
if (security != null)
security.checkListen(epoint.getPort());
...
}
}
似乎所有和 IO 操作有关的方法调用都需要进行安全检查。看起来IO操作相关的权限检查是可理解的,用户进程不能随意访问所有的IO资源。但是连环境变量都不让随意读,而且限制的还不是所有环境变量,而是某个具体的环境变量,这安全检查是不是有点过了?
class System {
public static String getenv(String name) {
SecurityManager sm = getSecurityManager();
if (sm != null) {
sm.checkPermission(new RuntimePermission("getenv."+name));
}
return ProcessEnvironment.getenv(name);
}
}
这是因为 Java 的安全检查管理器和操作系统的权限检查不是一个概念,Java 编写的不只是服务端应用程序,它还可以作为客户端跑在浏览器上(Applet),它还可以以 app 的形式跑在手机上(J2ME),针对不同的平台 JVM 会使用不同的安全策略。通常情况下,针对 Applet 的限制非常严格,一般不允许 Applet 操作本地文件。执行具体 IO 操作前,一旦 Java 的安全检查通过,操作系统仍会进行权限检查。
我们平时在本地运行 java 程序时通常都不会默认打开安全检查器,需要执行 jvm 参数才会打开
$ java -Djava.security.manager xxx
$ java -Djava.security.manager -DDjava.security.policy="${policypath}"
因为安全限制条件可以定制,所以还需要提供具体的安全策略文件路径,默认的策略文件路径是 JAVA_HOME/jre/lib/security/java.policy,下面让我们来看看这个文件里都写了些什么
// 内置扩展库授权规则
// 表示 JAVA_HOME/jre/lib/ext/ 目录下的类库可以全权访问任意资源
// 包含 javax.swing.*, javax.xml.*, javax.crypto.* 等等
grant codeBase "file:${{java.ext.dirs}}/*" {
permission java.security.AllPermission;
};
// 其它类库授权规则
grant {
// 允许线程调用自己的 stop 方法自杀
permission java.lang.RuntimePermission "stopThread";
// 允许程序监听 localhost 的随机可用端口,不允许随意订制端口
permission java.net.SocketPermission "localhost:0", "listen";
// 限制获取系统属性,下面一系列的配置都是只允许读部分内置属性
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";
};
grant 如果提供了 codeBase 参数就是针对具体的类库来配置权限规则,如果没有指定 codeBase 就是针对所有其它类库配置的规则。
安全检查没有通过,那就会抛出 java.security.AccessControlException 异常。即使通过了安全检查,操作系统的权限检查也有可能失败,此时将会抛出其他类型的异常。
如果按照上面所配置的规则,使用默认安全策略的 JVM 将无法访问本地文件,因为授权规则使用的是白名单。如果需要访问本地文件,可以增加下面的规则
permission java.io.FilePermission "/etc/passwd", "read";
permission java.io.FilePermission "/etc/shadow", "read,write";
permission java.io.FilePermission "/xyz", "read,write,delete";
// 允许读所有文件
permission java.io.FilePermission "*", "read";
Permission 的配置参数正好对应了它的构造器参数
public FilePermission(String path, String actions) {
super(path);
init(getMask(actions));
}
Java 默认安全规则分为几大模块,每个模块都有各自的配置参数
其中 AllPermission 表示打开所有权限。还有一个不速之客 HibernatePermission,它并不是内置的权限模块,它是 Hibernate 框架为自己订制的,这意味着安全规则是支持自定义扩展的。要扩展很容易,只需编写一个 Permission 子类,并实现其四个抽象方法。
abstract class Permission {
// 权限名称,对于文件来说就是文件名,对于套接字来说就是套接字地址
// 它的意义是子类可定制的
private String name;
// 当前权限对象是否隐含了 other 权限
// 比如 AllPermission 的这个方法总是返回 true
public abstract boolean implies(Permission o
ther);
// equals 和 hashcode 用于权限比较
public abstract boolean equals(Object obj);
public abstract int hashCode();
// 权限选项 read,write,xxx
public abstract String getActions();
}
class CustomPermission extends Permission {
private String actions;
CustomPermission(string name, string actions) {
super(name)
this.actions = actions;
}
...
}
JVM 启动时会将 profile 里面定义的权限规则加载到权限池中,用户程序在特定的 API 方法里使用权限池来判断是否包含调用这个 API 的权限,最终会落实到调用权限池中每一个权限对象的 implies 方法来判断是否具备指定权限。
class CustomAPI {
public void someMethod() {
SecurityManager sec = System.getSecurityManager();
if(sec != null) {
sec.CheckPermission(new CustomPermission("xname", "xactions"));
}
...
}
}
启用安全检查,将会降低程序的执行效率,如果 profile 里面定义的权限规则特别多,那么检查效率就会很慢,使用时注意安全检查要省着点使用。
沙箱的安全检查点非常多,下面列举一些常见的场景
文件操作
套接字操作
线程和线程组
类加载器控制
反射控制
线程堆栈信息获取
网络代理控制
Cookie 读写控制
如果你的服务端程序开启了安全检查,就需要在 policy 配置文件里打开很多安全设置,非常繁琐,而且配置多了,检查的性能也会产生一定损耗。这点有点类似 Android 的应用权限设置,在每个 Android 应用的配置文件里都需要罗列出一系列应用子权限。不过用 Java 来编写服务端程序似乎开启安全检查没有任何必要。
# java
相关栏目:
【
网站优化151355 】
【
网络推广146373 】
【
网络技术251813 】
【
AI营销90571 】
相关推荐:
如何快速生成ASP一键建站模板并优化安全性?
Laravel怎么返回JSON格式数据_Laravel API资源Response响应格式化【技巧】
在线教育网站制作平台,山西立德教育官网?
b2c电商网站制作流程,b2c水平综合的电商平台?
phpredis提高消息队列的实时性方法(推荐)
高防网站服务器:DDoS防御与BGP线路的AI智能防护方案
Laravel如何与Pusher实现实时通信?(WebSocket示例)
Laravel如何使用软删除(Soft Deletes)功能_Eloquent软删除与数据恢复方法
轻松掌握MySQL函数中的last_insert_id()
Python进程池调度策略_任务分发说明【指导】
如何快速生成凡客建站的专业级图册?
如何在搬瓦工VPS快速搭建网站?
Laravel怎么导出Excel文件_Laravel Excel插件使用教程
php 三元运算符实例详细介绍
Swift中switch语句区间和元组模式匹配
如何在景安服务器上快速搭建个人网站?
免费网站制作appp,免费制作app哪个平台好?
Laravel控制器是什么_Laravel MVC架构中Controller的作用与实践
详解ASP.NET 生成二维码实例(采用ThoughtWorks.QRCode和QrCode.Net两种方式)
专业型网站制作公司有哪些,我设计专业的,谁给推荐几个设计师兼职类的网站?
C++用Dijkstra(迪杰斯特拉)算法求最短路径
如何快速查询域名建站关键信息?
PythonWeb开发入门教程_Flask快速构建Web应用
Laravel如何实现多语言支持_Laravel本地化与国际化(i18n)配置教程
Laravel怎么实现搜索高亮功能_Laravel结合Scout与Algolia全文检索【实战】
Laravel Blade组件怎么用_Laravel可复用视图组件的创建与使用
详解jQuery中的事件
如何在景安云服务器上绑定域名并配置虚拟主机?
如何在Windows 2008云服务器安全搭建网站?
瓜子二手车官方网站在线入口 瓜子二手车网页版官网通道入口
如何快速搭建自助建站会员专属系统?
Laravel如何部署到服务器_线上部署Laravel项目的完整流程与步骤
,交易猫的商品怎么发布到网站上去?
javascript中的数组方法有哪些_如何利用数组方法简化数据处理
如何用PHP工具快速搭建高效网站?
Laravel如何配置任务调度?(Cron Job示例)
如何在阿里云高效完成企业建站全流程?
大连 网站制作,大连天途有线官网?
高端企业智能建站程序:SEO优化与响应式模板定制开发
Midjourney怎么调整光影效果_Midjourney光影调整方法【指南】
canvas 画布在主流浏览器中的尺寸限制详细介绍
Laravel如何实现API资源集合?(Resource Collection教程)
Win11怎么关闭透明效果_Windows11辅助功能视觉效果设置
Laravel如何实现多级无限分类_Laravel递归模型关联与树状数据输出【方法】
非常酷的网站设计制作软件,酷培ai教育官方网站?
Laravel Artisan命令怎么自定义_创建自己的Laravel命令行工具完全指南
Laravel怎么进行浏览器测试_Laravel Dusk自动化浏览器测试入门
历史网站制作软件,华为如何找回被删除的网站?
Laravel的Blade指令怎么自定义_创建你自己的Laravel Blade Directives
Thinkphp 中 distinct 的用法解析
上一篇:WPF气泡提示框的简单制作
上一篇:WPF气泡提示框的简单制作


ther);