You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何防止CDN类代理服务被用于访问受防火墙保护的内部资源?

防止CDN服务被用于SSRF攻击的解决方案

这是一个典型的**服务器端请求伪造(SSRF)**漏洞——攻击者利用你的公开CDN服务作为跳板,绕过防火墙访问内部受保护的8081端口资源。要彻底解决这个问题,你需要从多个维度添加防护措施,具体方案如下:

核心防护措施

1. 严格的URL白名单与内部地址拦截

首先,你需要明确CDN允许访问的外部资源范围,只放行预先批准的域名或IP,同时彻底拦截所有指向内部网络的请求:

  • 检查URL的主机部分,拒绝包含localhost127.0.0.1以及私有IP段(如10.0.0.0/8172.16.0.0/12192.168.0.0/16)的请求。
  • 额外添加白名单校验,只允许访问业务需求内的外部域名,避免无限制的任意请求。

示例Node.js/Express中间件代码:

const { URL } = require('url');
// 定义私有/内部IP范围的正则
const privateIPRanges = [
  /^10\./,
  /^172\.(1[6-9]|2[0-9]|3[0-1])\./,
  /^192\.168\./,
  /^127\./
];

app.use((req, res, next) => {
  const coolUrl = req.get('X-Cool-URL');
  if (!coolUrl) {
    return res.status(400).send('X-Cool-URL header is required');
  }

  try {
    const urlObj = new URL(coolUrl);
    
    // 拦截内部主机/IP
    const isPrivateHost = privateIPRanges.some(range => range.test(urlObj.hostname)) 
                          || urlObj.hostname === 'localhost';
    if (isPrivateHost) {
      return res.status(403).send('Access to internal resources is forbidden');
    }

    // 白名单校验(替换为你允许的域名)
    const allowedDomains = ['your-approved-domain.com', 'trusted-cdn.org'];
    if (!allowedDomains.includes(urlObj.hostname)) {
      return res.status(403).send('Domain not in allowed list');
    }

    next();
  } catch (err) {
    return res.status(400).send('Invalid URL format');
  }
});

2. 解析URL后验证目标IP

攻击者可能通过注册指向内部IP的外部域名来绕过主机名检查,因此需要解析URL的主机名获取实际IP,再验证IP是否属于内部范围:

const dns = require('dns');

// 在上述中间件中添加IP解析验证
dns.resolve(urlObj.hostname, (err, addresses) => {
  if (err) {
    return res.status(400).send('Failed to resolve domain');
  }
  
  const hasPrivateIP = addresses.some(ip => 
    privateIPRanges.some(range => range.test(ip))
  );
  if (hasPrivateIP) {
    return res.status(403).send('Access to internal IP addresses is forbidden');
  }
  
  next();
});

3. 限制请求协议

禁止使用file://ftp://gopher://等非HTTP/HTTPS协议,防止攻击者读取服务器本地文件或访问其他风险服务:

if (!['http:', 'https:'].includes(urlObj.protocol)) {
  return res.status(403).send('Unsupported request protocol');
}

4. 过滤编码后的内部地址

攻击者可能用URL编码、Unicode编码等方式隐藏内部地址(比如%31%32%37%2E%30%2E%30%2E%31对应127.0.0.1),需要先解码再检查:

const decodedUrl = decodeURIComponent(coolUrl);
// 对decodedUrl重复执行主机名和IP校验逻辑

5. 设置请求安全限制

添加超时和资源大小限制,防止攻击者利用你的服务器进行端口扫描或DoS攻击:

request({
  url: urlObj.href,
  timeout: 5000, // 5秒超时
  maxBodyLength: 1024 * 1024, // 限制响应体最大1MB
  followRedirect: false // 可选:禁止自动跳转,避免跳转到内部资源
}, (error, response, body) => {
  if (error) {
    return res.status(500).send('Failed to fetch resource');
  }
  res.send(body);
});

6. 使用隔离代理中转请求

如果你无法直接修改CDN代码,可以在CDN和外部资源之间部署一层专用代理服务。给这层代理配置严格的防火墙规则,只允许访问外部公开网络,彻底阻断对内部IP/端口的请求。这样即使CDN被利用,代理也会拦截非法请求。

内容的提问来源于stack exchange,提问作者Grant Gryczan

火山引擎 最新活动