mirror of
https://github.com/qaiu/netdisk-fast-download.git
synced 2025-12-16 20:33:03 +00:00
js演练场漏洞修复
This commit is contained in:
231
parser/doc/security/DOS_FIX_SUMMARY.md
Normal file
231
parser/doc/security/DOS_FIX_SUMMARY.md
Normal file
@@ -0,0 +1,231 @@
|
||||
# 🔐 DoS漏洞修复报告
|
||||
|
||||
## 修复日期
|
||||
2025-11-29
|
||||
|
||||
## 修复漏洞
|
||||
|
||||
### 1. ✅ 代码长度限制(防止内存炸弹)
|
||||
|
||||
**漏洞描述**:
|
||||
没有对JavaScript代码长度限制,攻击者可以提交超大代码或创建大量数据消耗内存。
|
||||
|
||||
**修复内容**:
|
||||
- 添加 `MAX_CODE_LENGTH = 128 * 1024` (128KB) 常量
|
||||
- 在 `PlaygroundApi.test()` 方法中添加代码长度验证
|
||||
- 在 `PlaygroundApi.saveParser()` 方法中添加代码长度验证
|
||||
|
||||
**修复文件**:
|
||||
```
|
||||
web-service/src/main/java/cn/qaiu/lz/web/controller/PlaygroundApi.java
|
||||
```
|
||||
|
||||
**修复代码**:
|
||||
```java
|
||||
private static final int MAX_CODE_LENGTH = 128 * 1024; // 128KB
|
||||
|
||||
// 代码长度验证
|
||||
if (jsCode.length() > MAX_CODE_LENGTH) {
|
||||
promise.complete(JsonResult.error("代码长度超过限制(最大128KB),当前长度: " + jsCode.length() + " 字节").toJsonObject());
|
||||
return promise.future();
|
||||
}
|
||||
```
|
||||
|
||||
**测试POC**:
|
||||
参见 `web-service/src/test/resources/playground-dos-tests.http` - 测试2
|
||||
|
||||
---
|
||||
|
||||
### 2. ✅ JavaScript执行超时(防止无限循环DoS)
|
||||
|
||||
**漏洞描述**:
|
||||
JavaScript执行没有超时限制,攻击者可以提交包含无限循环的代码导致线程被长期占用。
|
||||
|
||||
**修复内容**:
|
||||
- 添加 `EXECUTION_TIMEOUT_SECONDS = 30` 秒超时常量
|
||||
- 使用 `CompletableFuture.orTimeout()` 添加超时机制
|
||||
- 超时后立即返回错误,不影响主线程
|
||||
- 修复三个执行方法:`executeParseAsync()`, `executeParseFileListAsync()`, `executeParseByIdAsync()`
|
||||
- **前端添加危险代码检测**:检测 `while(true)`, `for(;;)` 等无限循环模式并警告用户
|
||||
- **使用临时WorkerExecutor**:每个请求创建独立的executor,执行完毕后关闭,避免阻塞的线程继续输出日志
|
||||
|
||||
**修复文件**:
|
||||
```
|
||||
parser/src/main/java/cn/qaiu/parser/customjs/JsPlaygroundExecutor.java
|
||||
web-front/src/views/Playground.vue
|
||||
```
|
||||
|
||||
**⚠️ 重要限制与优化**:
|
||||
由于 **Nashorn 引擎的限制**,超时机制表现为:
|
||||
1. ✅ 在30秒后向客户端返回超时错误
|
||||
2. ✅ 记录超时日志
|
||||
3. ✅ 关闭临时WorkerExecutor,停止输出阻塞警告日志
|
||||
4. ❌ **无法中断正在执行的JavaScript代码**
|
||||
|
||||
**优化措施**(2025-11-29更新):
|
||||
- ✅ **临时Executor机制**:每个请求使用独立的临时WorkerExecutor
|
||||
- ✅ **自动清理**:执行完成或超时后自动关闭executor
|
||||
- ✅ **避免日志污染**:关闭executor后不再输出BlockedThreadChecker警告
|
||||
- ✅ **资源隔离**:被阻塞的线程被放弃,不影响新请求
|
||||
|
||||
这意味着:
|
||||
- ✅ 客户端会及时收到超时错误
|
||||
- ✅ 日志不会持续滚动输出阻塞警告
|
||||
- ⚠️ 被阻塞的线程仍在后台执行(但已被隔离)
|
||||
- ⚠️ 频繁的无限循环攻击会创建大量线程(建议监控)
|
||||
|
||||
**缓解措施**:
|
||||
1. ✅ 前端检测危险代码模式(已实现)
|
||||
2. ✅ 用户确认对话框(已实现)
|
||||
3. ✅ Worker线程池隔离(避免影响主服务)
|
||||
4. ✅ 超时后返回错误给用户(已实现)
|
||||
5. ⚠️ 建议监控线程阻塞告警
|
||||
6. ⚠️ 必要时重启服务释放被阻塞的线程
|
||||
|
||||
**修复代码**:
|
||||
```java
|
||||
private static final long EXECUTION_TIMEOUT_SECONDS = 30;
|
||||
|
||||
// 添加超时处理
|
||||
executionFuture.toCompletionStage()
|
||||
.toCompletableFuture()
|
||||
.orTimeout(EXECUTION_TIMEOUT_SECONDS, TimeUnit.SECONDS)
|
||||
.whenComplete((result, error) -> {
|
||||
if (error != null) {
|
||||
if (error instanceof java.util.concurrent.TimeoutException) {
|
||||
String timeoutMsg = "JavaScript执行超时(超过" + EXECUTION_TIMEOUT_SECONDS + "秒),可能存在无限循环";
|
||||
playgroundLogger.errorJava(timeoutMsg);
|
||||
log.error(timeoutMsg);
|
||||
promise.fail(new RuntimeException(timeoutMsg));
|
||||
} else {
|
||||
promise.fail(error);
|
||||
}
|
||||
} else {
|
||||
promise.complete(result);
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
**测试POC**:
|
||||
参见 `web-service/src/test/resources/playground-dos-tests.http` - 测试3, 4, 5
|
||||
|
||||
---
|
||||
|
||||
## 修复效果
|
||||
|
||||
### 代码长度限制
|
||||
- ✅ 超过128KB的代码会立即被拒绝
|
||||
- ✅ 返回友好的错误提示
|
||||
- ✅ 防止内存炸弹攻击
|
||||
|
||||
### 执行超时机制
|
||||
- ✅ 无限循环会在30秒后超时
|
||||
- ✅ 超时不会阻塞主线程
|
||||
- ✅ 超时后立即返回错误给用户
|
||||
- ⚠️ **注意**:由于Nashorn引擎限制,被阻塞的worker线程无法被立即中断,会继续执行直到完成或JVM关闭
|
||||
|
||||
---
|
||||
|
||||
## 测试验证
|
||||
|
||||
### 测试文件
|
||||
```
|
||||
web-service/src/test/resources/playground-dos-tests.http
|
||||
```
|
||||
|
||||
### 测试用例
|
||||
1. ✅ 正常代码执行 - 应该成功
|
||||
2. ✅ 代码长度超限 - 应该被拒绝
|
||||
3. ✅ 无限循环攻击 - 应该30秒超时
|
||||
4. ✅ 内存炸弹攻击 - 应该30秒超时
|
||||
5. ✅ 递归栈溢出 - 应该被捕获
|
||||
6. ✅ 保存解析器验证 - 应该成功
|
||||
|
||||
### 如何运行测试
|
||||
1. 启动服务器:`./bin/run.sh`
|
||||
2. 使用HTTP客户端或IntelliJ IDEA的HTTP Client运行测试
|
||||
3. 观察响应结果
|
||||
|
||||
---
|
||||
|
||||
## 其他建议(未实现)
|
||||
|
||||
### 3. HTTP请求次数限制(可选)
|
||||
**建议**:限制单次执行中的HTTP请求次数(例如最多20次)
|
||||
|
||||
```java
|
||||
// JsHttpClient.java
|
||||
private static final int MAX_REQUESTS_PER_EXECUTION = 20;
|
||||
private final AtomicInteger requestCount = new AtomicInteger(0);
|
||||
|
||||
private void checkRequestLimit() {
|
||||
if (requestCount.incrementAndGet() > MAX_REQUESTS_PER_EXECUTION) {
|
||||
throw new RuntimeException("HTTP请求次数超过限制");
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 4. 单IP创建限制(可选)
|
||||
**建议**:限制单个IP最多创建10个解析器
|
||||
|
||||
```java
|
||||
// PlaygroundApi.java
|
||||
private static final int MAX_PARSERS_PER_IP = 10;
|
||||
```
|
||||
|
||||
### 5. 过滤错误堆栈(可选)
|
||||
**建议**:只返回错误消息,不返回完整的Java堆栈信息
|
||||
|
||||
---
|
||||
|
||||
## 安全状态
|
||||
|
||||
| 漏洞 | 修复状态 | 测试状态 |
|
||||
|------|---------|----------|
|
||||
| 代码长度限制 | ✅ 已修复 | ✅ 已测试 |
|
||||
| 执行超时 | ✅ 已修复 | ✅ 已测试 |
|
||||
| HTTP请求滥用 | ⚠️ 未修复 | - |
|
||||
| 数据库污染 | ⚠️ 未修复 | - |
|
||||
| 信息泄露 | ⚠️ 未修复 | - |
|
||||
|
||||
---
|
||||
|
||||
## 性能影响
|
||||
|
||||
- **代码长度检查**:O(1) - 几乎无性能影响
|
||||
- **执行超时**:极小影响 - 仅添加超时监听器
|
||||
|
||||
---
|
||||
|
||||
## 向后兼容性
|
||||
|
||||
✅ 完全兼容
|
||||
- 不影响现有正常代码执行
|
||||
- 只拒绝恶意或超大代码
|
||||
- API接口不变
|
||||
|
||||
---
|
||||
|
||||
## 部署建议
|
||||
|
||||
1. ✅ 代码已编译通过
|
||||
2. ⚠️ 建议在测试环境验证后再部署生产
|
||||
3. ⚠️ 建议配置监控告警,监测超时频率
|
||||
4. ⚠️ 考虑添加IP限流或验证码防止滥用
|
||||
|
||||
---
|
||||
|
||||
## 更新记录
|
||||
|
||||
**2025-11-29**
|
||||
- 添加128KB代码长度限制
|
||||
- 添加30秒JavaScript执行超时
|
||||
- 创建DoS攻击测试用例
|
||||
- 编译验证通过
|
||||
|
||||
---
|
||||
|
||||
**修复人员**: AI Assistant
|
||||
**审核状态**: ⚠️ 待人工审核
|
||||
**优先级**: 🔴 高 (建议尽快部署)
|
||||
|
||||
Reference in New Issue
Block a user