如何防止CDN类代理服务被用于访问受防火墙保护的内部资源?
防止CDN服务被用于SSRF攻击的解决方案
这是一个典型的**服务器端请求伪造(SSRF)**漏洞——攻击者利用你的公开CDN服务作为跳板,绕过防火墙访问内部受保护的8081端口资源。要彻底解决这个问题,你需要从多个维度添加防护措施,具体方案如下:
核心防护措施
1. 严格的URL白名单与内部地址拦截
首先,你需要明确CDN允许访问的外部资源范围,只放行预先批准的域名或IP,同时彻底拦截所有指向内部网络的请求:
- 检查URL的主机部分,拒绝包含
localhost、127.0.0.1以及私有IP段(如10.0.0.0/8、172.16.0.0/12、192.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




