Files
netdisk-fast-download/parser/doc/security/DOS_FIX_SUMMARY.md
2025-11-30 02:07:56 +08:00

6.7 KiB
Raw Blame History

🔐 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

修复代码

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. ⚠️ 必要时重启服务释放被阻塞的线程

修复代码

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次

// 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个解析器

// 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
审核状态: ⚠️ 待人工审核
优先级: 🔴 高 (建议尽快部署)