js演练场漏洞修复

This commit is contained in:
q
2025-11-30 02:07:56 +08:00
parent 49b8501e86
commit f750aa68e8
9 changed files with 1198 additions and 19 deletions

View File

@@ -0,0 +1,189 @@
# ⚠️ Nashorn引擎限制说明
## 问题描述
Nashorn JavaScript引擎Java 8-14自带**无法中断正在执行的JavaScript代码**。
这是Nashorn引擎的一个已知限制无法通过编程方式解决。
## 具体表现
### 症状
当JavaScript代码包含无限循环时
```javascript
while(true) {
var x = 1 + 1;
}
```
会出现以下情况:
1. ✅ 30秒后客户端收到超时错误
2. ❌ Worker线程继续执行无限循环
3. ❌ 线程被永久阻塞,无法释放
4. ❌ 日志持续输出线程阻塞警告
### 日志示例
```
WARN -> [-thread-checker] i.vertx.core.impl.BlockedThreadChecker:
Thread Thread[playground-executor-1,5,main] has been blocked for 60249 ms, time limit is 60000 ms
```
## 为什么无法中断?
### 尝试过的方案
1.`Thread.interrupt()` - Nashorn不响应中断信号
2.`Future.cancel(true)` - 无法强制停止Nashorn
3.`ExecutorService.shutdownNow()` - 只能停止整个线程池
4.`ScriptContext.setErrorWriter()` - 无法注入中断逻辑
5. ❌ 自定义ClassFilter - 无法过滤语言关键字
### 根本原因
- Nashorn使用JVM字节码执行JavaScript
- 无限循环被编译成JVM字节码级别的跳转
- 没有安全点Safepoint可以插入中断检查
- `while(true)` 不会调用任何Java方法完全在JVM栈内执行
## 现有防护措施
### 1. ✅ 客户端超时(已实现)
```java
executionFuture.toCompletionStage()
.toCompletableFuture()
.orTimeout(30, TimeUnit.SECONDS)
```
- 30秒后返回错误给用户
- 用户知道脚本超时
- 但线程仍被阻塞
### 2. ✅ 前端危险代码检测(已实现)
```javascript
// 检测无限循环模式
/while\s*\(\s*true\s*\)/gi
/for\s*\(\s*;\s*;\s*\)/gi
```
- 执行前警告用户
- 需要用户确认
- 依赖用户自觉
### 3. ✅ Worker线程池隔离
- 使用独立的 `playground-executor` 线程池
- 最多16个线程
- 不影响主服务的事件循环
### 4. ✅ 代码长度限制
- 最大128KB代码
- 减少内存消耗
- 但无法防止无限循环
## 影响范围
### 最坏情况
- 16个恶意请求可以耗尽所有Worker线程
- 后续所有Playground请求会等待
- 主服务不受影响(独立线程池)
- 需要重启服务才能恢复
### 实际影响
- 取决于使用场景
- 如果是公开服务,有被滥用风险
- 如果是内部工具,风险较低
## 解决方案
### 短期方案(已实施)
1. ✅ 前端检测和警告
2. ✅ 超时返回错误
3. ✅ 文档说明限制
4. ⚠️ 监控线程阻塞告警
5. ⚠️ 限流已有RateLimiter
### 中期方案(建议)
1. 添加IP黑名单机制
2. 添加滥用检测同一IP多次触发超时
3. 考虑添加验证码
4. 定期重启被阻塞的线程池
### 长期方案(需大量工作)
1. **迁移到GraalVM JavaScript引擎**
- 支持CPU时间限制
- 可以强制中断
- 更好的性能
- 但需要额外依赖
2. **使用独立进程执行**
- 完全隔离
- 可以强制杀死进程
- 但复杂度高
3. **代码静态分析**
- 分析AST检测循环
- 注入超时检查代码
- 但可能被绕过
## 运维建议
### 监控指标
```bash
# 监控线程阻塞告警
tail -f logs/*/run.log | grep "Thread blocked"
# 监控超时频率
tail -f logs/*/run.log | grep "JavaScript执行超时"
```
### 告警阈值
- 单个IP 1小时内超时 >3次 → 警告
- Worker线程阻塞 >80% → 严重
- 持续阻塞 >5分钟 → 考虑重启
### 应急方案
```bash
# 重启服务释放被阻塞的线程
./bin/stop.sh
./bin/run.sh
```
## 用户建议
### ✅ 建议的代码模式
```javascript
// 使用有限循环
for(var i = 0; i < 1000; i++) {
// 处理逻辑
}
// 使用超时保护
var maxIterations = 10000;
var count = 0;
while(condition && count++ < maxIterations) {
// 处理逻辑
}
```
### ❌ 禁止的代码模式
```javascript
// 无限循环
while(true) { }
for(;;) { }
// 无退出条件的循环
while(someCondition) {
// someCondition永远为true
}
// 递归炸弹
function boom() { return boom(); }
```
## 相关链接
- [Nashorn Engine Issues](https://github.com/openjdk/nashorn/issues)
- [GraalVM JavaScript](https://www.graalvm.org/javascript/)
- [Java Script Engine Comparison](https://benchmarksgame-team.pages.debian.net/benchmarksgame/)
---
**最后更新**: 2025-11-29
**状态**: ⚠️ 已知限制,已采取缓解措施
**建议**: 如需更严格的控制考虑迁移到GraalVM JavaScript引擎