mirror of
https://github.com/qaiu/netdisk-fast-download.git
synced 2025-12-16 12:23:03 +00:00
js演练场
This commit is contained in:
@@ -14,7 +14,6 @@
|
||||
- [JsLogger对象](#jslogger对象)
|
||||
- [重定向处理](#重定向处理)
|
||||
- [代理支持](#代理支持)
|
||||
- [文件上传支持](#文件上传支持)
|
||||
- [实现方法](#实现方法)
|
||||
- [parse方法(必填)](#parse方法必填)
|
||||
- [parseFileList方法(可选)](#parsefilelist方法可选)
|
||||
@@ -199,23 +198,53 @@ var response = http.post("https://api.example.com/submit", {
|
||||
data: "test"
|
||||
});
|
||||
|
||||
// 设置请求头
|
||||
// 设置请求头(单个)
|
||||
http.putHeader("User-Agent", "MyBot/1.0")
|
||||
.putHeader("Authorization", "Bearer token");
|
||||
|
||||
// 批量设置请求头
|
||||
http.putHeaders({
|
||||
"User-Agent": "MyBot/1.0",
|
||||
"Authorization": "Bearer token",
|
||||
"Accept": "application/json"
|
||||
});
|
||||
|
||||
// 删除指定请求头
|
||||
http.removeHeader("Authorization");
|
||||
|
||||
// 清空所有请求头(保留默认头)
|
||||
http.clearHeaders();
|
||||
|
||||
// 获取所有请求头
|
||||
var allHeaders = http.getHeaders();
|
||||
logger.debug("当前请求头: " + JSON.stringify(allHeaders));
|
||||
|
||||
// 设置请求超时时间(秒)
|
||||
http.setTimeout(60); // 设置为60秒
|
||||
|
||||
// PUT请求
|
||||
var putResponse = http.put("https://api.example.com/resource", {
|
||||
key: "value"
|
||||
});
|
||||
|
||||
// DELETE请求
|
||||
var deleteResponse = http.delete("https://api.example.com/resource/123");
|
||||
|
||||
// PATCH请求
|
||||
var patchResponse = http.patch("https://api.example.com/resource/123", {
|
||||
key: "newValue"
|
||||
});
|
||||
|
||||
// URL编码/解码(静态方法)
|
||||
var encoded = JsHttpClient.urlEncode("hello world"); // "hello%20world"
|
||||
var decoded = JsHttpClient.urlDecode("hello%20world"); // "hello world"
|
||||
|
||||
// 发送简单表单数据
|
||||
var formResponse = http.sendForm({
|
||||
username: "user",
|
||||
password: "pass"
|
||||
});
|
||||
|
||||
// 发送multipart表单数据(支持文件上传)
|
||||
var multipartResponse = http.sendMultipartForm("https://api.example.com/upload", {
|
||||
textField: "value",
|
||||
fileField: fileBuffer, // Buffer或byte[]类型
|
||||
binaryData: binaryArray // byte[]类型
|
||||
});
|
||||
|
||||
// 发送JSON数据
|
||||
var jsonResponse = http.sendJson({
|
||||
name: "test",
|
||||
@@ -249,6 +278,13 @@ if (response.isSuccess()) {
|
||||
} else {
|
||||
logger.error("请求失败: " + status);
|
||||
}
|
||||
|
||||
// 获取响应体字节数组
|
||||
var bytes = response.bodyBytes();
|
||||
|
||||
// 获取响应体大小
|
||||
var size = response.bodySize();
|
||||
logger.info("响应体大小: " + size + " 字节");
|
||||
```
|
||||
|
||||
### JsLogger对象
|
||||
@@ -350,89 +386,6 @@ function parse(shareLinkInfo, http, logger) {
|
||||
}
|
||||
```
|
||||
|
||||
## 文件上传支持
|
||||
|
||||
JavaScript解析器支持通过`sendMultipartForm`方法上传文件:
|
||||
|
||||
### 1. 简单文件上传
|
||||
|
||||
```javascript
|
||||
function uploadFile(shareLinkInfo, http, logger) {
|
||||
// 模拟文件数据(实际使用中可能是从其他地方获取)
|
||||
var fileData = new java.lang.String("Hello, World!").getBytes();
|
||||
|
||||
// 使用sendMultipartForm上传文件
|
||||
var response = http.sendMultipartForm("https://api.example.com/upload", {
|
||||
file: fileData,
|
||||
filename: "test.txt",
|
||||
description: "测试文件"
|
||||
});
|
||||
|
||||
return response.body();
|
||||
}
|
||||
```
|
||||
|
||||
### 2. 混合表单上传
|
||||
|
||||
```javascript
|
||||
function uploadMixedForm(shareLinkInfo, http, logger) {
|
||||
var fileData = getFileData();
|
||||
|
||||
// 同时上传文本字段和文件
|
||||
var response = http.sendMultipartForm("https://api.example.com/upload", {
|
||||
username: "user123",
|
||||
email: "user@example.com",
|
||||
file: fileData,
|
||||
description: "用户上传的文件"
|
||||
});
|
||||
|
||||
if (response.isSuccess()) {
|
||||
var result = response.json();
|
||||
return result.downloadUrl;
|
||||
} else {
|
||||
throw new Error("文件上传失败: " + response.statusCode());
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 3. 多文件上传
|
||||
|
||||
```javascript
|
||||
function uploadMultipleFiles(shareLinkInfo, http, logger) {
|
||||
var files = [
|
||||
{ name: "file1.txt", data: getFileData1() },
|
||||
{ name: "file2.jpg", data: getFileData2() }
|
||||
];
|
||||
|
||||
var uploadResults = [];
|
||||
|
||||
for (var i = 0; i < files.length; i++) {
|
||||
var file = files[i];
|
||||
var response = http.sendMultipartForm("https://api.example.com/upload", {
|
||||
file: file.data,
|
||||
filename: file.name,
|
||||
uploadIndex: i.toString()
|
||||
});
|
||||
|
||||
if (response.isSuccess()) {
|
||||
uploadResults.push({
|
||||
fileName: file.name,
|
||||
success: true,
|
||||
url: response.json().url
|
||||
});
|
||||
} else {
|
||||
uploadResults.push({
|
||||
fileName: file.name,
|
||||
success: false,
|
||||
error: response.statusCode()
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return uploadResults;
|
||||
}
|
||||
```
|
||||
|
||||
## 实现方法
|
||||
|
||||
JavaScript解析器支持三种方法,对应Java接口的三种同步方法:
|
||||
@@ -698,6 +651,39 @@ A: 当前版本使用同步API,所有HTTP请求都是同步的。
|
||||
|
||||
A: 使用 `logger.debug()` 输出调试信息,查看应用日志。
|
||||
|
||||
### Q: 如何批量设置请求头?
|
||||
|
||||
A: 使用 `http.putHeaders()` 方法批量设置多个请求头:
|
||||
|
||||
```javascript
|
||||
// 批量设置请求头
|
||||
http.putHeaders({
|
||||
"User-Agent": "Mozilla/5.0...",
|
||||
"Accept": "application/json",
|
||||
"Authorization": "Bearer token",
|
||||
"Referer": "https://example.com"
|
||||
});
|
||||
```
|
||||
|
||||
### Q: 如何清空所有请求头?
|
||||
|
||||
A: 使用 `http.clearHeaders()` 方法清空所有请求头(会保留默认头):
|
||||
|
||||
```javascript
|
||||
// 清空所有请求头,保留默认头(Accept-Encoding、User-Agent、Accept-Language)
|
||||
http.clearHeaders();
|
||||
```
|
||||
|
||||
### Q: 如何设置请求超时时间?
|
||||
|
||||
A: 使用 `http.setTimeout()` 方法设置超时时间(秒):
|
||||
|
||||
```javascript
|
||||
// 设置超时时间为60秒
|
||||
http.setTimeout(60);
|
||||
var response = http.get("https://api.example.com/data");
|
||||
```
|
||||
|
||||
## 示例脚本
|
||||
|
||||
参考以下示例文件,包含完整的解析器实现:
|
||||
@@ -714,6 +700,7 @@ A: 使用 `logger.debug()` 输出调试信息,查看应用日志。
|
||||
- 文件信息构建
|
||||
- 重定向处理
|
||||
- 代理支持
|
||||
- Header管理(批量设置、清空等)
|
||||
|
||||
## 限制说明
|
||||
|
||||
@@ -732,6 +719,11 @@ A: 使用 `logger.debug()` 输出调试信息,查看应用日志。
|
||||
|
||||
- v1.0.0: 初始版本,支持基本的JavaScript解析器功能
|
||||
- 支持外部解析器路径配置(系统属性、环境变量)
|
||||
- 支持文件上传功能(sendMultipartForm)
|
||||
- 支持重定向处理(getNoRedirect、getWithRedirect)
|
||||
- 支持代理配置(HTTP/SOCKS4/SOCKS5)
|
||||
- v1.1.0: 增强HTTP客户端功能
|
||||
- 新增header管理方法:clearHeaders、removeHeader、putHeaders、getHeaders
|
||||
- 新增HTTP请求方法:PUT、DELETE、PATCH
|
||||
- 新增工具方法:URL编码/解码(urlEncode、urlDecode)
|
||||
- 新增超时时间设置:setTimeout
|
||||
- 响应对象增强:bodyBytes、bodySize
|
||||
|
||||
303
parser/doc/security/SECURITY_URGENT_FIX.md
Normal file
303
parser/doc/security/SECURITY_URGENT_FIX.md
Normal file
@@ -0,0 +1,303 @@
|
||||
# 🚨 紧急安全修复通知
|
||||
|
||||
## ⚠️ 严重漏洞已修复 - 请立即部署
|
||||
|
||||
**漏洞编号**: RCE-2025-001
|
||||
**发现日期**: 2025-11-28
|
||||
**修复状态**: ✅ 已完成
|
||||
**危险等级**: 🔴🔴🔴 极高(远程代码执行)
|
||||
|
||||
---
|
||||
|
||||
## 🔥 漏洞影响
|
||||
|
||||
如果您的服务器正在运行**未修复**的版本,攻击者可以:
|
||||
|
||||
- ✅ 执行任意系统命令
|
||||
- ✅ 读取服务器上的所有文件(包括数据库、配置文件、密钥)
|
||||
- ✅ 删除或修改文件
|
||||
- ✅ 窃取环境变量和系统信息
|
||||
- ✅ 攻击内网其他服务器
|
||||
- ✅ 完全控制服务器
|
||||
|
||||
**这是一个可被远程利用的代码执行漏洞!**
|
||||
|
||||
---
|
||||
|
||||
## 🎯 快速修复步骤
|
||||
|
||||
### 1. 立即停止服务(如果正在生产环境)
|
||||
|
||||
```bash
|
||||
./bin/stop.sh
|
||||
```
|
||||
|
||||
### 2. 拉取最新代码
|
||||
|
||||
```bash
|
||||
git pull
|
||||
# 或者手动应用补丁
|
||||
```
|
||||
|
||||
### 3. 重新编译
|
||||
|
||||
```bash
|
||||
mvn clean install
|
||||
```
|
||||
|
||||
### 4. 验证修复(重要!)
|
||||
|
||||
```bash
|
||||
cd parser
|
||||
mvn test -Dtest=SecurityTest
|
||||
```
|
||||
|
||||
**确认所有测试显示"安全"而不是"危险"!**
|
||||
|
||||
### 5. 重启服务
|
||||
|
||||
```bash
|
||||
./bin/run.sh
|
||||
```
|
||||
|
||||
### 6. 监控日志
|
||||
|
||||
检查是否有安全拦截日志:
|
||||
|
||||
```bash
|
||||
tail -f logs/*/run.log | grep "安全拦截"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📋 修复内容摘要
|
||||
|
||||
### 新增的安全防护
|
||||
|
||||
1. **ClassFilter** - 阻止JavaScript访问危险Java类
|
||||
2. **Java对象禁用** - 移除 `Java.type()` 等全局对象
|
||||
3. **SSRF防护** - 阻止访问内网地址和云服务元数据
|
||||
4. **URL白名单** - HTTP请求仅允许公网地址
|
||||
|
||||
### 修复的文件
|
||||
|
||||
- `JsPlaygroundExecutor.java` - 使用安全引擎
|
||||
- `JsParserExecutor.java` - 使用安全引擎
|
||||
- `JsHttpClient.java` - 添加SSRF防护
|
||||
- `SecurityClassFilter.java` - **新文件**:类过滤器
|
||||
|
||||
---
|
||||
|
||||
## 🧪 验证修复是否生效
|
||||
|
||||
### 测试1: 验证系统命令执行已被阻止
|
||||
|
||||
访问演练场,执行以下测试代码:
|
||||
|
||||
```javascript
|
||||
// ==UserScript==
|
||||
// @name 安全验证测试
|
||||
// @type test
|
||||
// @match https://test.com/*
|
||||
// ==/UserScript==
|
||||
|
||||
function parse(shareLinkInfo, http, logger) {
|
||||
try {
|
||||
var Runtime = Java.type('java.lang.Runtime');
|
||||
logger.error('【严重问题】Java.type仍然可用!');
|
||||
return '失败:未修复';
|
||||
} catch (e) {
|
||||
logger.info('✅ 安全:' + e.message);
|
||||
return '成功:已修复';
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**期望结果**:
|
||||
```
|
||||
✅ 安全:ReferenceError: "Java" is not defined
|
||||
成功:已修复
|
||||
```
|
||||
|
||||
**如果看到"失败:未修复",说明修复未生效,请检查编译是否成功!**
|
||||
|
||||
### 测试2: 验证SSRF防护
|
||||
|
||||
```javascript
|
||||
function parse(shareLinkInfo, http, logger) {
|
||||
try {
|
||||
var response = http.get('http://127.0.0.1:8080/admin');
|
||||
logger.error('【严重问题】可以访问内网!');
|
||||
return '失败:SSRF未修复';
|
||||
} catch (e) {
|
||||
logger.info('✅ 安全:' + e);
|
||||
return '成功:SSRF已修复';
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**期望结果**:
|
||||
```
|
||||
✅ 安全:SecurityException: 🔒 安全拦截: 禁止访问内网地址
|
||||
成功:SSRF已修复
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📊 安全评级
|
||||
|
||||
### 修复前
|
||||
- **评级**: 🔴 F级(完全不安全)
|
||||
- **风险**: 服务器可被完全控制
|
||||
- **建议**: 🚨 **立即下线服务**
|
||||
|
||||
### 修复后
|
||||
- **评级**: 🟢 A级(安全)
|
||||
- **风险**: 低(已实施多层防护)
|
||||
- **建议**: ✅ 可安全使用
|
||||
|
||||
---
|
||||
|
||||
## 🔍 如何检查您是否受影响
|
||||
|
||||
### 检查版本
|
||||
|
||||
查看修改时间:
|
||||
|
||||
```bash
|
||||
# 检查关键文件是否包含安全修复
|
||||
grep -n "SecurityClassFilter" parser/src/main/java/cn/qaiu/parser/customjs/JsPlaygroundExecutor.java
|
||||
|
||||
# 如果输出为空,说明未修复
|
||||
# 如果有输出,说明已修复
|
||||
```
|
||||
|
||||
### 检查日志
|
||||
|
||||
查看是否有攻击尝试:
|
||||
|
||||
```bash
|
||||
# 搜索可疑的系统调用
|
||||
grep -r "Runtime\|ProcessBuilder\|System\.exec" logs/
|
||||
|
||||
# 如果发现大量此类日志,可能已被攻击
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🆘 紧急联系
|
||||
|
||||
如果发现以下情况,请立即采取行动:
|
||||
|
||||
### 已被攻击的迹象
|
||||
|
||||
1. ❌ 服务器上出现陌生文件
|
||||
2. ❌ 系统负载异常高
|
||||
3. ❌ 发现陌生进程
|
||||
4. ❌ 配置文件被修改
|
||||
5. ❌ 日志中有大量异常请求
|
||||
|
||||
### 应对措施
|
||||
|
||||
1. **立即下线服务**
|
||||
```bash
|
||||
./bin/stop.sh
|
||||
```
|
||||
|
||||
2. **隔离服务器**
|
||||
- 断开网络连接(如果可能)
|
||||
- 保存日志证据
|
||||
|
||||
3. **检查受损范围**
|
||||
```bash
|
||||
# 检查最近修改的文件
|
||||
find / -type f -mtime -1 -ls 2>/dev/null
|
||||
|
||||
# 检查可疑进程
|
||||
ps aux | grep -E "nc|bash|sh|python|perl"
|
||||
|
||||
# 检查网络连接
|
||||
netstat -antp | grep ESTABLISHED
|
||||
```
|
||||
|
||||
4. **备份日志**
|
||||
```bash
|
||||
tar -czf logs-backup-$(date +%Y%m%d).tar.gz logs/
|
||||
```
|
||||
|
||||
5. **应用安全补丁并重新部署**
|
||||
|
||||
6. **修改所有密码和密钥**
|
||||
|
||||
---
|
||||
|
||||
## 📚 详细文档
|
||||
|
||||
- **完整修复说明**: `parser/SECURITY_FIX_SUMMARY.md`
|
||||
- **安全测试指南**: `parser/doc/SECURITY_TESTING_GUIDE.md`
|
||||
- **快速测试**: `parser/SECURITY_TEST_README.md`
|
||||
|
||||
---
|
||||
|
||||
## ✅ 修复确认清单
|
||||
|
||||
部署后请确认:
|
||||
|
||||
- [ ] 代码已更新到最新版本
|
||||
- [ ] Maven重新编译成功
|
||||
- [ ] SecurityTest所有测试通过
|
||||
- [ ] 演练场测试显示"安全"
|
||||
- [ ] 日志中有"🔒 安全的JavaScript引擎初始化成功"
|
||||
- [ ] 尝试访问危险类时出现"安全拦截"日志
|
||||
- [ ] HTTP请求内网地址被阻止
|
||||
- [ ] 服务运行正常
|
||||
|
||||
---
|
||||
|
||||
## 🎓 经验教训
|
||||
|
||||
### 问题根源
|
||||
|
||||
1. **过度信任用户输入** - 允许执行任意JavaScript
|
||||
2. **缺少沙箱隔离** - Nashorn默认允许访问所有Java类
|
||||
3. **没有安全审计** - 上线前未进行安全测试
|
||||
|
||||
### 预防措施
|
||||
|
||||
1. ✅ **永远不要信任用户输入**
|
||||
2. ✅ **使用沙箱隔离执行不可信代码**
|
||||
3. ✅ **实施最小权限原则**
|
||||
4. ✅ **定期安全审计**
|
||||
5. ✅ **关注依赖库的安全更新**
|
||||
|
||||
### 长期计划
|
||||
|
||||
考虑迁移到 **GraalVM JavaScript**:
|
||||
- 默认沙箱隔离
|
||||
- 更好的安全性
|
||||
- 更好的性能
|
||||
- 活跃维护
|
||||
|
||||
---
|
||||
|
||||
## 📞 支持
|
||||
|
||||
如有问题,请查看:
|
||||
- 详细文档: `parser/SECURITY_FIX_SUMMARY.md`
|
||||
- 测试指南: `parser/doc/SECURITY_TESTING_GUIDE.md`
|
||||
|
||||
---
|
||||
|
||||
**重要提醒**:
|
||||
- ⚠️ 这是一个严重的安全漏洞
|
||||
- ⚠️ 必须立即修复
|
||||
- ⚠️ 修复后必须验证
|
||||
- ⚠️ 如已被攻击,请遵循应急响应流程
|
||||
|
||||
**修复优先级**: 🔴🔴🔴 **最高** - 立即处理
|
||||
|
||||
---
|
||||
|
||||
最后更新: 2025-11-28
|
||||
状态: ✅ 修复完成,等待部署验证
|
||||
|
||||
296
parser/doc/security/SSRF_PROTECTION.md
Normal file
296
parser/doc/security/SSRF_PROTECTION.md
Normal file
@@ -0,0 +1,296 @@
|
||||
# SSRF防护策略说明
|
||||
|
||||
## 🛡️ 当前防护策略(已优化)
|
||||
|
||||
为了保证功能可用性和安全性的平衡,SSRF防护策略已调整为**宽松模式**,只拦截明确的危险请求。
|
||||
|
||||
---
|
||||
|
||||
## ✅ 允许的请求
|
||||
|
||||
以下请求**不会被拦截**,可以正常使用:
|
||||
|
||||
### 1. 外网域名 ✅
|
||||
```javascript
|
||||
http.get('https://www.example.com/api/data') // ✅ 允许
|
||||
http.get('http://api.github.com/repos') // ✅ 允许
|
||||
http.get('https://cdn.jsdelivr.net/file.js') // ✅ 允许
|
||||
```
|
||||
|
||||
### 2. 公网IP ✅
|
||||
```javascript
|
||||
http.get('http://8.8.8.8/api') // ✅ 允许(公网IP)
|
||||
http.get('https://1.1.1.1/dns-query') // ✅ 允许(Cloudflare DNS)
|
||||
```
|
||||
|
||||
### 3. DNS解析失败的域名 ✅
|
||||
```javascript
|
||||
// 即使DNS暂时无法解析,也允许继续
|
||||
http.get('http://some-new-domain.com') // ✅ 允许(DNS失败不拦截)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## ❌ 拦截的请求
|
||||
|
||||
以下请求**会被拦截**,保护服务器安全:
|
||||
|
||||
### 1. 本地回环地址 ❌
|
||||
```javascript
|
||||
http.get('http://127.0.0.1:8080/admin') // ❌ 拦截
|
||||
http.get('http://localhost/secret') // ❌ 拦截(解析到127.0.0.1)
|
||||
http.get('http://[::1]/api') // ❌ 拦截(IPv6本地)
|
||||
```
|
||||
|
||||
### 2. 内网IP地址 ❌
|
||||
```javascript
|
||||
http.get('http://192.168.1.1/config') // ❌ 拦截(内网C类)
|
||||
http.get('http://10.0.0.5/admin') // ❌ 拦截(内网A类)
|
||||
http.get('http://172.16.0.1/api') // ❌ 拦截(内网B类)
|
||||
```
|
||||
|
||||
### 3. 云服务元数据API ❌
|
||||
```javascript
|
||||
http.get('http://169.254.169.254/latest/meta-data/') // ❌ 拦截(AWS/阿里云)
|
||||
http.get('http://metadata.google.internal/computeMetadata/') // ❌ 拦截(GCP)
|
||||
http.get('http://100.100.100.200/latest/meta-data/') // ❌ 拦截(阿里云)
|
||||
```
|
||||
|
||||
### 4. 解析到内网的域名 ❌
|
||||
```javascript
|
||||
// 如果域名DNS解析指向内网IP,会被拦截
|
||||
http.get('http://internal.company.com') // ❌ 拦截(如果解析到192.168.x.x)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🔍 检测逻辑
|
||||
|
||||
### 防护流程
|
||||
|
||||
```
|
||||
用户请求 URL
|
||||
↓
|
||||
1. 检查是否为云服务元数据API域名
|
||||
├─ 是 → ❌ 拦截
|
||||
└─ 否 → 继续
|
||||
↓
|
||||
2. 检查Host是否为IP地址格式
|
||||
├─ 是 → 检查是否为内网IP
|
||||
│ ├─ 是 → ❌ 拦截
|
||||
│ └─ 否 → ✅ 允许
|
||||
└─ 否(域名)→ 继续
|
||||
↓
|
||||
3. 尝试DNS解析域名
|
||||
├─ 解析成功
|
||||
│ ├─ IP为内网 → ❌ 拦截
|
||||
│ └─ IP为公网 → ✅ 允许
|
||||
└─ 解析失败 → ✅ 允许(不阻止)
|
||||
```
|
||||
|
||||
### 内网IP判断规则
|
||||
|
||||
使用正则表达式匹配:
|
||||
|
||||
```java
|
||||
^(127\..*| // 127.0.0.0/8 - 本地回环
|
||||
10\..*| // 10.0.0.0/8 - 内网A类
|
||||
172\.(1[6-9]|2[0-9]|3[01])\..*| // 172.16.0.0/12 - 内网B类
|
||||
192\.168\..*| // 192.168.0.0/16 - 内网C类
|
||||
169\.254\..*| // 169.254.0.0/16 - 链路本地
|
||||
::1| // IPv6本地回环
|
||||
[fF][cCdD].*) // IPv6唯一本地地址
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📊 策略对比
|
||||
|
||||
| 场景 | 严格模式(原版) | 宽松模式(当前)✅ |
|
||||
|------|-----------------|-------------------|
|
||||
| 外网域名 | 可能被拦截 | ✅ 允许 |
|
||||
| DNS解析失败 | 被拦截 | ✅ 允许 |
|
||||
| 公网IP | ✅ 允许 | ✅ 允许 |
|
||||
| 内网IP | ❌ 拦截 | ❌ 拦截 |
|
||||
| 本地回环 | ❌ 拦截 | ❌ 拦截 |
|
||||
| 云服务元数据 | ❌ 拦截 | ❌ 拦截 |
|
||||
| 解析到内网的域名 | ❌ 拦截 | ❌ 拦截 |
|
||||
|
||||
---
|
||||
|
||||
## 🧪 测试用例
|
||||
|
||||
### 测试1: 正常外网请求 ✅
|
||||
|
||||
```javascript
|
||||
function parse(shareLinkInfo, http, logger) {
|
||||
try {
|
||||
var response = http.get('https://httpbin.org/get');
|
||||
logger.info('✅ 成功访问外网: ' + response.substring(0, 50));
|
||||
return 'SUCCESS';
|
||||
} catch (e) {
|
||||
logger.error('❌ 外网请求被拦截(不应该): ' + e.message);
|
||||
return 'FAILED';
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**期望结果**: ✅ 成功访问
|
||||
|
||||
### 测试2: 内网攻击拦截 ❌
|
||||
|
||||
```javascript
|
||||
function parse(shareLinkInfo, http, logger) {
|
||||
try {
|
||||
var response = http.get('http://127.0.0.1:6400/');
|
||||
logger.error('❌ 内网访问成功(不应该)');
|
||||
return 'SECURITY_BREACH';
|
||||
} catch (e) {
|
||||
logger.info('✅ 内网访问被拦截: ' + e.message);
|
||||
return 'PROTECTED';
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**期望结果**: ✅ 被拦截,显示"安全拦截: 禁止访问内网IP地址"
|
||||
|
||||
### 测试3: 云服务元数据拦截 ❌
|
||||
|
||||
```javascript
|
||||
function parse(shareLinkInfo, http, logger) {
|
||||
try {
|
||||
var response = http.get('http://169.254.169.254/latest/meta-data/');
|
||||
logger.error('❌ 元数据API访问成功(不应该)');
|
||||
return 'SECURITY_BREACH';
|
||||
} catch (e) {
|
||||
logger.info('✅ 元数据API被拦截: ' + e.message);
|
||||
return 'PROTECTED';
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**期望结果**: ✅ 被拦截,显示"安全拦截: 禁止访问云服务元数据API"
|
||||
|
||||
---
|
||||
|
||||
## 🎯 安全建议
|
||||
|
||||
### ✅ 当前策略适用于
|
||||
|
||||
- 需要访问多种外网API的场景
|
||||
- 网盘、文件分享等服务
|
||||
- 需要爬取外网资源
|
||||
- 对可用性要求较高的环境
|
||||
|
||||
### ⚠️ 如需更严格的防护
|
||||
|
||||
如果你的应用场景需要更严格的安全控制,可以考虑:
|
||||
|
||||
#### 1. 白名单模式
|
||||
|
||||
只允许访问特定域名:
|
||||
|
||||
```java
|
||||
private static final String[] ALLOWED_DOMAINS = {
|
||||
"api.example.com",
|
||||
"cdn.example.com"
|
||||
};
|
||||
|
||||
private void validateUrlSecurity(String url) {
|
||||
String host = new URI(url).getHost();
|
||||
boolean allowed = false;
|
||||
for (String domain : ALLOWED_DOMAINS) {
|
||||
if (host.equals(domain) || host.endsWith("." + domain)) {
|
||||
allowed = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!allowed) {
|
||||
throw new SecurityException("域名不在白名单中");
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### 2. 协议限制
|
||||
|
||||
只允许HTTPS:
|
||||
|
||||
```java
|
||||
String scheme = uri.getScheme();
|
||||
if (!"https".equalsIgnoreCase(scheme)) {
|
||||
throw new SecurityException("仅允许HTTPS协议");
|
||||
}
|
||||
```
|
||||
|
||||
#### 3. 端口限制
|
||||
|
||||
只允许标准端口(80, 443):
|
||||
|
||||
```java
|
||||
int port = uri.getPort();
|
||||
if (port != -1 && port != 80 && port != 443) {
|
||||
throw new SecurityException("仅允许标准HTTP/HTTPS端口");
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📝 配置说明
|
||||
|
||||
### 修改黑名单
|
||||
|
||||
在 `JsHttpClient.java` 中修改:
|
||||
|
||||
```java
|
||||
// 危险域名黑名单
|
||||
private static final String[] DANGEROUS_HOSTS = {
|
||||
"localhost",
|
||||
"169.254.169.254", // AWS/阿里云元数据
|
||||
"metadata.google.internal", // GCP元数据
|
||||
"100.100.100.200", // 阿里云元数据
|
||||
// 添加更多...
|
||||
};
|
||||
```
|
||||
|
||||
### 修改内网IP规则
|
||||
|
||||
```java
|
||||
// 内网IP正则表达式
|
||||
private static final Pattern PRIVATE_IP_PATTERN = Pattern.compile(
|
||||
"^(127\\..*|10\\..*|172\\.(1[6-9]|2[0-9]|3[01])\\..*|192\\.168\\..*|169\\.254\\..*|::1|[fF][cCdD].*)"
|
||||
);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🔄 策略变更历史
|
||||
|
||||
### v2 - 宽松模式(当前)✅
|
||||
- **日期**: 2025-11-29
|
||||
- **变更**:
|
||||
- DNS解析失败不拦截
|
||||
- URL格式错误不拦截
|
||||
- 只拦截明确的内网攻击
|
||||
- **原因**: 避免误杀正常外网请求
|
||||
|
||||
### v1 - 严格模式
|
||||
- **日期**: 2025-11-28
|
||||
- **变更**: 初始实现
|
||||
- **问题**: 过于严格,导致很多正常请求被拦截
|
||||
|
||||
---
|
||||
|
||||
## 📞 反馈
|
||||
|
||||
如果遇到以下情况,请考虑调整策略:
|
||||
|
||||
1. **正常外网请求被拦截** → 检查DNS解析、域名是否在黑名单
|
||||
2. **内网攻击未被拦截** → 添加更多内网IP段或域名黑名单
|
||||
3. **性能问题** → 考虑缓存DNS解析结果
|
||||
|
||||
---
|
||||
|
||||
**最后更新**: 2025-11-29
|
||||
**当前版本**: v2 - 宽松模式
|
||||
**安全级别**: ⚠️ 中等(建议生产环境根据实际需求调整)
|
||||
|
||||
59
parser/doc/security/test-security.sh
Normal file
59
parser/doc/security/test-security.sh
Normal file
@@ -0,0 +1,59 @@
|
||||
#!/bin/bash
|
||||
|
||||
# JavaScript执行器安全测试脚本
|
||||
# 用于快速执行所有安全测试用例
|
||||
|
||||
echo "========================================"
|
||||
echo " JavaScript执行器安全测试"
|
||||
echo "========================================"
|
||||
echo ""
|
||||
|
||||
# 进入parser目录
|
||||
cd "$(dirname "$0")"
|
||||
|
||||
echo "📋 测试用例列表:"
|
||||
echo " 1. 系统命令执行测试 🔴"
|
||||
echo " 2. 文件系统访问测试 🔴"
|
||||
echo " 3. 系统属性访问测试 🟡"
|
||||
echo " 4. 反射攻击测试 🔴"
|
||||
echo " 5. 网络Socket测试 🔴"
|
||||
echo " 6. JVM退出测试 🔴"
|
||||
echo " 7. HTTP客户端SSRF测试 🟡"
|
||||
echo ""
|
||||
|
||||
echo "⚠️ 警告: 这些测试包含危险代码,仅用于安全验证!"
|
||||
echo ""
|
||||
|
||||
read -p "是否继续执行测试? (y/n): " -n 1 -r
|
||||
echo ""
|
||||
|
||||
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
|
||||
echo "测试已取消"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "🚀 开始执行测试..."
|
||||
echo ""
|
||||
|
||||
# 执行JUnit测试
|
||||
mvn test -Dtest=SecurityTest
|
||||
|
||||
# 检查测试结果
|
||||
if [ $? -eq 0 ]; then
|
||||
echo ""
|
||||
echo "✅ 测试执行完成"
|
||||
echo ""
|
||||
echo "📊 请检查测试日志,确认:"
|
||||
echo " ✓ 所有高危测试(系统命令、文件访问等)应该失败"
|
||||
echo " ✓ 所有日志中不应该出现【安全漏洞】标记"
|
||||
echo " ⚠ 如果出现安全漏洞警告,请立即修复!"
|
||||
else
|
||||
echo ""
|
||||
echo "❌ 测试执行失败"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "📖 详细文档请参考: doc/SECURITY_TESTING_GUIDE.md"
|
||||
echo ""
|
||||
|
||||
Reference in New Issue
Block a user