Dify远程文件上传SSRF风险检查与加固

本文由AI辅助编写

一次公网安全扫描把问题指向了Dify的远程文件上传接口。当时运行的是1.1.0,无法立即确认漏洞编号和修复版本,于是先撤掉公网NAT映射,避免接口继续暴露,再检查版本、访问日志和出站边界。

后来Dify发布的安全公告明确了这条接口的影响范围:低于1.13.0的版本受影响,1.13.0完成修复。对于仍在运行旧版的部署,升级已经有了清楚的版本边界,关闭公网入口只能作为临时隔离措施。

先确认是不是同一个问题

Dify公开过不止一处SSRF风险,远程文件上传、自定义工具测试和文档解析属于不同入口。只看到“Dify存在SSRF”就套用某个CVE编号,很容易把受影响版本和修复结论写错。

这次需要确认的是/console/api/remote-files/upload。Dify后来发布的GHSA-8235-vv5j-mmvg专门描述了这个接口:未登录的请求可以触发服务端获取远程资源,影响范围是< 1.13.0,修复版本为1.13.0。公告没有为它分配CVE编号,不必强行和其他SSRF记录对应。

官方公告发布前,公开漏洞库中已经出现过指向远程文件上传控制器的CVE-2025-29720,但该记录没有给出可靠的修复版本。判断当前部署是否需要处理时,以Dify维护者后来公布的公告和修复提交为准更稳妥。

先缩小暴露面

发现风险后,先取消了公网NAT映射。这一步不能消除漏洞,但能立即切断原来的公网入口,适合在补丁窗口到来前降低风险。

如果服务不能完全下线,至少应把Dify入口收回到可信网络,或在反向代理、VPN和访问控制层限制来源。不要只隐藏前端页面:风险点在API,请求是否能直接到达后端才是检查重点。

可以先从主机监听端口和容器映射开始检查:

1
2
ss -lntp
docker compose ps

再检查负载均衡、反向代理、防火墙和云安全组,确认没有旁路入口。这里尤其要留意临时测试端口、直接映射到宿主机的容器端口,以及已经不用但没有删除的转发规则。

升级到修复版本

Dify在修复提交中为远程文件上传接口补上了登录校验,安全公告将1.13.0列为修复版本。因此旧部署应升级到1.13.0或更高的受支持版本,而不是继续依赖外围拦截规则。

升级前先记录当前镜像和配置,按实际部署方式备份数据库与持久化目录。完成升级后,核对运行中的容器使用了新镜像,不能只看配置文件里的标签:

1
2
docker compose images
docker compose ps

跨越多个版本时还要阅读中间版本的发布说明和迁移要求。Dify 1.13.0发布说明可以作为这个修复边界的起点,但不替代完整的升级说明。

限制服务端出站访问

身份校验修复了这次公开的未授权入口,出站限制仍然值得保留。Dify本身需要获取远程文件、访问模型服务和调用工具,如果应用容器可以任意访问内网,其他入口出现问题时仍可能把风险带到内部服务。

出站策略至少应覆盖这些边界:

  • 应用只访问业务确实需要的外部地址和端口;
  • 拒绝访问回环、私有、链路本地及其他保留地址;
  • 云环境单独阻断实例元数据服务;
  • 内部模型、数据库和管理接口使用独立网络与最小访问规则;
  • 所有代理和防火墙规则都要处理DNS解析后的目标地址,不能只检查用户提交的字符串。

Dify的Docker部署中包含SSRF代理配置。使用这层代理时仍要检查实际生效的环境变量、容器网络和代理规则,避免应用存在可以绕过代理的直接出站路径。

查找可能的访问痕迹

隔离和升级之外,还需要回看风险窗口内的访问日志。日志位置取决于部署方式,Docker Compose环境可以先从API服务和入口代理中筛选相关路径:

1
2
docker compose logs --since 24h api \
| grep -F '/console/api/remote-files/upload'

不能只把命中记录当作攻击,也不能因为没有命中就断定没有风险。继续结合请求来源、时间、状态码、异常出站连接、代理日志和防火墙日志判断;如果日志保留时间较短,应先保存现有记录,避免容器滚动或升级时覆盖。

修复后的验证放在隔离环境中进行,使用自己控制的外部探针地址观察服务是否发起请求,并确认未登录访问已经被拒绝。不要把真实内网服务、云元数据地址或生产凭据作为测试目标。