mirror of
https://github.com/labring/FastGPT.git
synced 2026-04-26 02:07:28 +08:00
6ea65f644b
* perf: mcp json schema type * fix: workflow form value reset * fix: ts * fix: test
5.9 KiB
5.9 KiB
SSRF 漏洞修复设计文档
漏洞概述
漏洞编号: GHSA-6g6x-8hq5-9cw4 漏洞类型: Server-Side Request Forgery (SSRF) - CWE-918 严重程度: High 影响版本: <= 4.8.22
漏洞详情
1. 主要问题
FastGPT 的 HTTP Tool 连接器在处理用户控制的 URL 时缺乏 SSRF 保护:
受影响文件:
packages/service/core/app/http.ts(lines 127-166) -runHTTPTool()函数projects/app/src/pages/api/core/app/httpTools/runTool.ts- API 端点
问题代码:
export const runHTTPTool = async ({ baseUrl, toolPath, method, ... }) => {
const { data } = await axios({
method: method.toUpperCase(),
baseURL: baseUrl.startsWith('http') ? baseUrl : `https://${baseUrl}`,
url: toolPath,
// 没有任何 IP 验证!
});
};
2. 次要问题
isInternalAddress() 函数默认被禁用:
文件: packages/service/common/system/utils.ts (line 142)
if (process.env.CHECK_INTERNAL_IP !== 'true') {
return false; // 默认允许内部地址!
}
这意味着 http468 工作流节点和 readFiles 也缺乏 SSRF 保护,除非显式设置 CHECK_INTERNAL_IP=true。
攻击场景
认证用户可以使用 HTTP Tool 进行以下攻击:
-
AWS 凭证窃取:
baseUrl: http://169.254.169.254toolPath: /latest/meta-data/iam/security-credentials/
-
Kubernetes 密钥泄露:
baseUrl: http://kubernetes.default.svctoolPath: /api/v1/namespaces/default/secrets/
-
内部网络扫描和服务利用
修复方案
方案 1: 在 runHTTPTool 中添加 SSRF 保护(推荐)
修改文件: packages/service/core/app/http.ts
在 runHTTPTool 函数中,在发起请求前添加 URL 验证:
export const runHTTPTool = async ({
baseUrl,
toolPath,
method = 'POST',
params,
headerSecret,
customHeaders,
staticParams,
staticHeaders,
staticBody
}: RunHTTPToolParams): Promise<RunHTTPToolResult> => {
try {
// 构建完整 URL
const fullBaseUrl = baseUrl.startsWith('http://') || baseUrl.startsWith('https://')
? baseUrl
: `https://${baseUrl}`;
// SSRF 保护:验证 URL 是否指向内部地址
const fullUrl = new URL(toolPath, fullBaseUrl).toString();
if (await isInternalAddress(fullUrl)) {
return { errorMsg: 'Access to internal addresses is not allowed' };
}
const { headers, body, queryParams } = buildHttpRequest({
method,
params,
headerSecret,
customHeaders,
staticParams,
staticHeaders,
staticBody
});
const { data } = await axios({
method: method.toUpperCase(),
baseURL: fullBaseUrl,
url: toolPath,
headers,
data: body,
params: queryParams,
timeout: 300000
});
return { data };
} catch (error: any) {
return { errorMsg: getErrText(error) };
}
};
方案 2: 修改 CHECK_INTERNAL_IP 默认值
修改文件: packages/service/common/system/utils.ts
将默认行为从"允许"改为"拒绝":
// 3. 如果未启用内部 IP 检查,则默认拒绝(安全优先)
if (process.env.CHECK_INTERNAL_IP === 'false') {
return false; // 显式禁用检查时才允许
}
// 默认启用内部 IP 检查
注意: 这个改动可能影响向后兼容性,需要在文档中说明。
方案 3: 添加 DNS Rebinding 保护(可选增强)
在 isInternalAddress 函数中,可以添加 DNS rebinding 保护:
- 解析域名获取 IP
- 验证 IP 是否为内部地址
- 在实际请求时,固定使用已验证的 IP(而不是重新解析)
这需要修改 axios 请求的方式,使用已解析的 IP 而不是域名。
实施步骤
第一阶段:核心修复(必须)
- ✅ 在
runHTTPTool中添加isInternalAddress验证 - ✅ 修改
CHECK_INTERNAL_IP默认行为为启用 - ✅ 添加单元测试验证修复
第二阶段:文档更新(必须)
- 更新部署文档,说明
CHECK_INTERNAL_IP环境变量的变化 - 添加安全最佳实践文档
- 更新 CHANGELOG
第三阶段:增强保护(可选)
- 实现 DNS rebinding 保护
- 添加请求日志和监控
- 实现 URL 白名单机制
测试计划
单元测试
创建测试文件: test/cases/service/core/app/http.test.ts
测试用例:
- ✅ 测试拒绝 AWS 元数据端点 (169.254.169.254)
- ✅ 测试拒绝 Kubernetes 服务 (kubernetes.default.svc)
- ✅ 测试拒绝私有 IP 范围 (10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16)
- ✅ 测试拒绝 localhost 和 127.0.0.1
- ✅ 测试允许合法的外部 URL
- ✅ 测试 DNS rebinding 场景(域名解析到内部 IP)
集成测试
- 测试 HTTP Tool 在工作流中的行为
- 测试 API 端点
/api/core/app/httpTools/runTool - 验证错误消息的正确性
向后兼容性
破坏性变更
-
CHECK_INTERNAL_IP 默认值变更:
- 旧行为: 默认允许内部地址访问
- 新行为: 默认拒绝内部地址访问
-
影响范围:
- 依赖访问内部服务的工作流将失败
- 需要显式设置
CHECK_INTERNAL_IP=false来恢复旧行为(不推荐)
迁移指南
对于需要访问内部服务的合法用例:
- 推荐方案: 使用代理服务或 API 网关
- 临时方案: 设置
CHECK_INTERNAL_IP=false(不安全,仅用于开发环境)
安全建议
- 生产环境: 始终保持
CHECK_INTERNAL_IP=true(默认) - 网络隔离: 在网络层面限制 FastGPT 服务器的出站访问
- 监控: 记录所有 HTTP Tool 请求,监控异常模式
- 最小权限: 限制 FastGPT 服务账号的权限
参考资料
- CWE-918: Server-Side Request Forgery (SSRF)
- OWASP SSRF Prevention Cheat Sheet
- GitHub Security Advisory: GHSA-6g6x-8hq5-9cw4