[P0/严重] HttpRequestTool 未防御 SSRF,可访问内网与云元数据服务 #10

Open
opened 2026-07-21 21:55:41 +08:00 by thzxx · 0 comments
Owner

问题类型

安全漏洞 / 严重 / 工具系统

文件位置

electron/harness/tools/built-in/http-request.ts

问题描述

HttpRequestTool 接受任意 URL,未做 SSRF 防护。LLM 可调用:

  • http://169.254.169.254/latest/meta-data/ (AWS / GCP / Azure 元数据,可获取云凭证)
  • http://localhost:port/ (访问本机内部服务,如数据库、Redis、管理 API)
  • http://10.0.0.0/8 / http://192.168.0.0/16 (内网扫描)
  • http://[::1]/ (IPv6 回环)

这违反了 OWASP SSRF 防御最佳实践。

影响

  • 云凭证泄露(IAM 临时凭证可被用于接管云账户)
  • 内网服务暴露
  • 横向移动跳板

建议修复

  1. URL 解析与 IP 校验
import { lookup } from 'dns/promises';
import { isIP } from 'net';

async function isPrivateIP(ip: string): Promise<boolean> {
  // 检查 IPv4 私有段 / 回环 / 链路本地 / 元数据
  const privateRanges = [
    /^127\./, /^10\./, /^192\.168\./, /^172\.(1[6-9]|2[0-9]|3[0-1])\./,
    /^169\.254\./, /^0\./, /^224\./, /^240\./,
  ];
  if (privateRanges.some(re => re.test(ip))) return true;
  // IPv6
  if (ip === '::1' || ip.startsWith('fe80::') || ip.startsWith('fc00::')) return true;
  return false;
}

// 解析域名后校验 IP
const ips = await lookup(hostname, { all: true });
for (const { address } of ips) {
  if (await isPrivateIP(address)) {
    throw new Error(`Blocked SSRF: ${hostname} resolves to private IP ${address}`);
  }
}
  1. 禁用 redirect 跟随或重新校验重定向后的 URL
  2. 协议白名单:仅允许 http/https
## 问题类型 安全漏洞 / 严重 / 工具系统 ## 文件位置 `electron/harness/tools/built-in/http-request.ts` ## 问题描述 HttpRequestTool 接受任意 URL,未做 SSRF 防护。LLM 可调用: - `http://169.254.169.254/latest/meta-data/` (AWS / GCP / Azure 元数据,可获取云凭证) - `http://localhost:port/` (访问本机内部服务,如数据库、Redis、管理 API) - `http://10.0.0.0/8` / `http://192.168.0.0/16` (内网扫描) - `http://[::1]/` (IPv6 回环) 这违反了 OWASP SSRF 防御最佳实践。 ## 影响 - 云凭证泄露(IAM 临时凭证可被用于接管云账户) - 内网服务暴露 - 横向移动跳板 ## 建议修复 1. **URL 解析与 IP 校验**: ```ts import { lookup } from 'dns/promises'; import { isIP } from 'net'; async function isPrivateIP(ip: string): Promise<boolean> { // 检查 IPv4 私有段 / 回环 / 链路本地 / 元数据 const privateRanges = [ /^127\./, /^10\./, /^192\.168\./, /^172\.(1[6-9]|2[0-9]|3[0-1])\./, /^169\.254\./, /^0\./, /^224\./, /^240\./, ]; if (privateRanges.some(re => re.test(ip))) return true; // IPv6 if (ip === '::1' || ip.startsWith('fe80::') || ip.startsWith('fc00::')) return true; return false; } // 解析域名后校验 IP const ips = await lookup(hostname, { all: true }); for (const { address } of ips) { if (await isPrivateIP(address)) { throw new Error(`Blocked SSRF: ${hostname} resolves to private IP ${address}`); } } ``` 2. **禁用 redirect 跟随**或重新校验重定向后的 URL 3. **协议白名单**:仅允许 http/https
thzxx added the ???????????? labels 2026-07-21 21:55:41 +08:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: MetonaTeam/metona-ai-desktop#10