Webhook、回调地址和“导入远程资源”功能,往往需要服务端主动访问用户提供的 URL。这个设计本身并不等于漏洞,但如果缺少协议限制、目标校验和网络出口控制,攻击者可能借助应用服务器访问原本不应暴露的内部服务,形成服务端请求伪造(SSRF)风险。这类问题的难点不在于找到一个可以发起 HTTP 请求的参数,而在于判断请求链路是否真的由服务端执行、跳转和 DNS 解析是否可控、最终连接的目标是否经过有效校验,以及修复后是否能够抵抗编码、重定向和解析差异带来的绕过。一、常见业务场景与审计入口在代码审计中,可以优先关注以下功能:Webhook、回调通知、第三方集成配置。头像、文档、图片或远程压缩包导入。在线预览、网页截图、Markdown 远程渲染。通过 URL 检查站点状态、生成分享卡片或抓取网页标题。后台任务、消息队列消费者和定时同步程序中的远程请求。审计时不要只搜索参数名。更可靠的方法是从网络请求的调用点反向追踪数据流,重点搜索 HTTP 客户端、URL 解析器、重定向处理和代理配置。例如 Java 项目中可以关注 RestTemplate、WebClient、HttpURLConnection 和 Apache HttpClient;Python 项目中可以关注 requests、urllib、httpx;Node.js 项目中则需要检查 axios、got、fetch 等调用。二、建立完整的数据流模型一个典型的风险链路可以抽象为:用户输入 URL
-> 参数校验
-> URL 解析
-> DNS 解析
-> 建立 TCP/TLS 连接
-> 处理 HTTP 重定向
-> 读取响应
-> 解析响应内容或返回结果审计报告应分别回答以下问题:URL 是否完全由用户控制,还是只控制主机名、路径或查询参数?应用是否允许 http、https 之外的协议?解析后的主机名是否可能指向回环地址、私有地址、链路本地地址或其他受限网段?DNS 解析发生在校验之前还是之后?连接时是否可能重新解析?是否自动跟随 30x 重定向?重定向后的地址是否重新校验?请求是否经过代理,代理是否会改变目标判断逻辑?响应体是否会被完整读入内存,是否存在资源消耗风险?如果只验证了输入字符串是否以 https:// 开头,通常不足以说明安全。URL 解析存在用户名、端口、编码、IPv6 和大小写等差异,字符串检查很容易与实际连接目标不一致。三、容易被忽略的解析问题第一类问题是用户信息和主机名混淆。例如 URL 中可以同时存在认证信息、主机名、端口和路径。安全判断必须使用标准解析器取得结构化字段,不能通过字符串截取判断目标。第二类问题是 IP 表示形式差异。部分解析库或底层网络栈可能接受十进制、十六进制、短格式或 IPv6 表示。防护逻辑应将主机名解析为所有实际地址,并对每个地址执行统一的网络范围判断。第三类问题是 DNS 重绑定。应用在校验阶段解析到一个允许访问的地址,真正建立连接时却可能得到另一个地址。更稳妥的做法是在受控网络出口上再次限制目标,或者由网络代理负责解析和连接,并禁止应用直接访问任意地址。第四类问题是重定向。即使初始 URL 合规,服务端也可能被引导到不合规的目标。因此建议默认关闭自动重定向;如果业务确实需要,应限制跳转次数,并对每一次跳转后的 URL 重新执行协议、主机和地址校验。四、一个可审计的校验思路下面的示例用于说明校验顺序,实际项目仍应结合语言运行时和网络架构进行测试。示例只允许固定协议,解析主机名后检查所有地址,并限制端口范围和重定向策略。from ipaddress import ip_address, ip_network
from urllib.parse import urlsplit
import socket
BLOCKED = [
ip_network(
推荐意见