fix(security): 修复余额脚本功能的RCE和SSRF漏洞

- 将 BALANCE_SCRIPT_ENABLED 默认值改为 false,需显式启用
- 添加 isUrlSafe() SSRF防护,禁止访问:
  - localhost/127.x
  - 私有IP (10.x, 172.16-31.x, 192.168.x)
  - AWS metadata (169.254.x)
  - 非HTTP(S)协议
This commit is contained in:
shaw
2026-01-07 21:55:08 +08:00
parent dbd4fb19cf
commit 8a4dadbbc0
2 changed files with 54 additions and 3 deletions

View File

@@ -2,6 +2,50 @@ const vm = require('vm')
const axios = require('axios') const axios = require('axios')
const { isBalanceScriptEnabled } = require('../utils/featureFlags') const { isBalanceScriptEnabled } = require('../utils/featureFlags')
/**
* SSRF防护检查URL是否访问内网或敏感地址
* @param {string} url - 要检查的URL
* @returns {boolean} - true表示URL安全
*/
function isUrlSafe(url) {
try {
const parsed = new URL(url)
const hostname = parsed.hostname.toLowerCase()
// 禁止的协议
if (!['http:', 'https:'].includes(parsed.protocol)) {
return false
}
// 禁止访问localhost和私有IP
const privatePatterns = [
/^localhost$/i,
/^127\./,
/^10\./,
/^172\.(1[6-9]|2[0-9]|3[0-1])\./,
/^192\.168\./,
/^169\.254\./, // AWS metadata
/^0\./, // 0.0.0.0
/^::1$/,
/^fc00:/i,
/^fe80:/i,
/\.local$/i,
/\.internal$/i,
/\.localhost$/i
]
for (const pattern of privatePatterns) {
if (pattern.test(hostname)) {
return false
}
}
return true
} catch {
return false
}
}
/** /**
* 可配置脚本余额查询执行器 * 可配置脚本余额查询执行器
* - 脚本格式:({ request: {...}, extractor: function(response){...} }) * - 脚本格式:({ request: {...}, extractor: function(response){...} })
@@ -55,6 +99,11 @@ class BalanceScriptService {
throw new Error('脚本 request.url 不能为空') throw new Error('脚本 request.url 不能为空')
} }
// SSRF防护验证URL安全性
if (!isUrlSafe(request.url)) {
throw new Error('脚本 request.url 不安全禁止访问内网地址、localhost或使用非HTTP(S)协议')
}
if (typeof extractor !== 'function') { if (typeof extractor !== 'function') {
throw new Error('脚本 extractor 必须是函数') throw new Error('脚本 extractor 必须是函数')
} }

View File

@@ -20,8 +20,9 @@ const parseBooleanEnv = (value) => {
} }
/** /**
* 是否允许执行余额脚本(安全开关) * 是否允许执行"余额脚本"(安全开关)
* 默认开启,便于保持现有行为;如需用请显式设置 BALANCE_SCRIPT_ENABLED=false环境变量优先 * ⚠️ 安全警告vm模块非安全沙箱默认禁用。如需用请显式设置 BALANCE_SCRIPT_ENABLED=true
* 仅在完全信任管理员且了解RCE风险时才启用此功能
*/ */
const isBalanceScriptEnabled = () => { const isBalanceScriptEnabled = () => {
if ( if (
@@ -36,7 +37,8 @@ const isBalanceScriptEnabled = () => {
config?.features?.balanceScriptEnabled ?? config?.features?.balanceScriptEnabled ??
config?.security?.enableBalanceScript config?.security?.enableBalanceScript
return typeof fromConfig === 'boolean' ? fromConfig : true // 默认禁用,需显式启用
return typeof fromConfig === 'boolean' ? fromConfig : false
} }
module.exports = { module.exports = {