内网大模型网关没做好,半夜被通报是常事

内网大模型网关没做好,半夜被通报是常事

前言

去年年底,我接手了一个集团级的私有化大模型项目。
模型跑通了,GPU 资源也调优了。
结果就在上线前夜,安全部门一纸通报,说我们的接口没有审计日志,存在数据泄露风险。
那一刻,我真的想找个地缝钻进去。
在内网环境,尤其是涉密或强合规行业,模型本身只是引擎。
网关才是那个把控生死的“海关”。
很多同行觉得,内网嘛,只要防火墙一关就万事大吉。
大错特错。
内网威胁同样存在,横向移动、权限滥用、数据窃取,哪一样少得了流量监控?
今天我就把这套经过实战检验的“合规网关”设计思路,毫无保留地摊开来讲。
不讲虚的,只讲怎么让安全部门闭嘴,让业务跑得稳。

一、底层原理

1.1 核心机制

在内网隔离环境下,大模型网关的核心使命只有三个词:
准入、审计、隔离

它不能只是个简单的转发代理。
它必须是一个具备“状态感知”的流量过滤器。
我们设计了一套“三层漏斗”架构。
第一层是身份校验,确保调用者是人还是机器。
第二层是内容过滤,防止 Prompt 注入或敏感数据出域。
第三层是审计留痕,所有请求必须落盘,且不可篡改。

为了让大家更直观地理解流量走向,我画了这张拓扑图。

graph TD
    Client["客户端应用"] -->|HTTPS 双向认证 | Gateway["大模型安全网关"]
    subgraph DMZ 区 ["DMZ 隔离区"]
        Gateway
    end
    Gateway -->|鉴权通过后 | Filter["内容安全过滤器"]
    Filter -->|脱敏处理 | ModelProxy["模型路由代理"]
    subgraph 核心模型区 ["核心模型内网区"]
        ModelProxy --> LLM["大模型推理服务"]
    end
    Gateway -->|异步写入 | AuditDB["审计日志数据库"]
    Filter -.->|阻断违规请求 | Alert["安全告警系统"]

这张图的核心逻辑在于“隔离”。
网关部署在 DMZ 区,模型服务在更深层的内网区。
即使网关被攻破,攻击者也无法直接触达模型权重文件。
审计日志是异步写入的,避免影响主链路性能。
这种设计最大的优势是“解耦”。
安全策略变了,不用重启模型服务,改改网关配置就行。

1.2 与同类方案的对比

市面上常见的方案主要有三种。
一种是直接暴露模型 API,完全依赖网络防火墙。
一种是使用开源网关如 Kong,不做深度定制。
最后一种就是我们采用的“自研合规网关”。

方案 审计能力 内容过滤 部署复杂度 合规推荐度
直接暴露 API ❌ 绝对禁止
开源通用网关 需插件开发 ⚠️ 勉强可用
自研合规网关 内置规则引擎 ✅ 强烈推荐

开源网关虽然香,但它的插件生态往往跟不上国内特殊的合规要求。
比如“数据出境评估”或“特定关键词拦截”。
自研虽然前期累点,但后期维护成本低,且完全可控。

二、快速上手

别被“企业级”三个字吓到。
我们先把最核心的“鉴权 + 日志”链路跑通。
这里我用 Java 写了一个最小可运行的网关拦截器示例。
注意,为了符合安全规范,代码里所有的变量名我都汉化了。
复制这段代码,你马上就能看到效果。

// 定义一个网关过滤器,负责拦截所有进入的请求
public class 安全合规网关过滤器 implements 网关过滤器 {

    // 定义一个日志记录器,专门用于记录审计信息
    private static final 日志记录器 审计日志 = 日志记录器.获取日志("com.enterprise.gateway.audit");

    @Override
    public 网关处理结果 过滤(网关上下文 上下文) {
        // 第一步:检查请求头里有没有携带有效的令牌
        String 用户令牌 = 上下文.获取请求头("Authorization");
        
        // 如果令牌为空,直接拒绝访问,不要浪费资源
        if (用户令牌 == null || 用户令牌.isEmpty()) {
            return 网关处理结果.拒绝("未提供访问令牌,请前往认证中心获取");
        }

        // 第二步:校验令牌的有效性,这里模拟调用内部认证服务
        boolean 令牌是否有效 = 认证服务.校验令牌(用户令牌);
        
        if (!令牌是否有效) {
            // 记录一次非法尝试,方便安全团队追踪
            审计日志.记录警告("检测到无效令牌尝试,来源 IP: " + 上下文.获取客户端 IP());
            return 网关处理结果.拒绝("令牌已过期或无效");
        }

        // 第三步:提取用户信息,放入上下文,供后续链路使用
        用户信息 当前用户 = 令牌解析器.解析(用户令牌);
        上下文.设置属性("当前用户", 当前用户);

        // 第四步:记录一次成功的访问审计日志
        // 注意:这里只记录操作行为,严禁记录具体的 Prompt 内容,防止敏感信息落盘
        审计日志.记录信息(String.format("用户 %s 成功访问模型接口,时间: %s", 
            当前用户.用户名, 当前时间.获取当前时间戳()));

        // 放行请求,继续执行后续链路
        return 网关处理结果.放行();
    }
}

这段代码虽然简单,但包含了最核心的“鉴权”和“审计”逻辑。
在实际生产中,我们会把 认证服务 换成 LDAP 或 OAuth2 的对接。
但逻辑骨架是不变的。

三、核心 API / 深水区

3.1 核心方法速查

网关开发中,有几个 API 是必须掌握的。
我把它们整理成了表格,方便大家查阅。

方法名 功能描述 适用场景
获取请求体快照 获取请求的原始内容 用于内容安全过滤
设置响应头 修改返回给客户端的 Header 用于添加安全标识
异步写入审计 将日志非阻塞写入数据库 避免阻塞主线程
限流计数器 统计当前 IP 的请求频率 防止 DDoS 攻击

3.2 生产级配置

光有代码不行,配置才是关键。
在内网环境,SSL 双向认证是标配。
客户端必须持有证书,网关也必须验证客户端证书。
这就好比进公司大门,不仅要刷工牌,还得验指纹。

另外,超时控制必须严格。
大模型推理慢是常态,但网关不能无限等待。
我们建议设置两级超时。
连接超时设为 5 秒,读取超时设为 60 秒。
超过 60 秒还没返回,直接切断连接,返回“服务繁忙”。
这能防止某个慢请求拖垮整个网关线程池。

3.3 高级定制

有些业务场景需要更精细的控制。
比如,财务部门只能问财务报表相关的问题。
这时候就需要引入“意图识别”模块。
在网关层,先跑一个轻量级的分类模型。
如果意图不匹配,直接拦截,不调用大模型。
这不仅能省钱,还能降低合规风险。

四、实战演练

光说不练假把式。
我们来看一个真实的业务场景。
某银行内部想要部署一个“信贷助手”,帮助客户经理查询政策。
这个场景对数据隐私要求极高。

需求分析

  1. 只有信贷部的人能访问。
  2. 禁止查询客户姓名、身份证号等敏感信息。
  3. 所有问答必须留痕,且保留 6 个月。

代码实现

// 这是一个专门针对信贷场景的自定义过滤器
public class 信贷数据合规过滤器 implements 网关过滤器 {

    // 定义一组敏感词正则,用于匹配请求内容
    private static final 正则匹配器 敏感信息正则 = 正则匹配器.编译("(身份证 | 手机号 | 银行卡号)");

    @Override
    public 网关处理结果 过滤(网关上下文 上下文) {
        // 获取当前请求的完整内容
        String 请求内容 = 上下文.获取请求体();

        // 检查请求内容里是否包含敏感信息
        // 比如用户试图让模型分析某个具体的身份证号
        if (敏感信息正则.匹配(请求内容)) {
            // 记录一次违规拦截事件
            审计日志.记录警告("检测到敏感信息尝试,用户: " + 上下文.获取当前用户());
            // 直接阻断请求,并返回友好的提示
            return 网关处理结果.拒绝("出于合规要求,禁止输入个人敏感信息");
        }

        // 检查用户权限,确保只有信贷部员工能过
        String 用户部门 = 上下文.获取属性("部门");
        if (!"信贷管理部".equals(用户部门)) {
            return 网关处理结果.拒绝("您没有权限访问信贷助手");
        }

        // 一切检查通过,放行
        return 网关处理结果.放行();
    }
}

结果分析
经过测试,当测试人员输入包含“身份证号”的句子时。
网关在 50 毫秒内就完成了拦截。
模型服务根本没有收到请求。
审计日志里准确记录了是谁、在什么时间、尝试了什么违规操作。
这套机制上线后,安全部门一次性验收通过。

五、避坑指南与最佳实践

这一部分全是血泪教训,大家拿小本本记好。

💡 技巧一:日志脱敏要彻底
很多团队为了排查问题,喜欢把请求体完整打印出来。
在内网环境,这也是违规的。
如果日志里包含了用户问的“公司薪资结构”,那日志库就成了重灾区。
建议:日志系统必须配置自动脱敏规则,或者在网关层就把敏感字段替换为 ***

⚠️ 警告二:不要信任内网 IP
以前我觉得,只要 IP 是内网的,就默认可信。
后来发现,内网主机一旦被肉鸡化,IP 照样能发起攻击。
建议:必须结合“身份令牌”做二次校验,IP 白名单只能作为第一道防线,不能作为唯一依据。

推荐三:灰度发布策略
新版本的网关规则上线前,千万别全量推。
先切 5% 的流量到新版本。
观察错误率和延迟。
没问题了,再慢慢加到 100%。
大模型网关一旦配置错误,可能导致整个业务停摆。

六、综合实战演示

最后,我提供一套精简、闭环的综合实战代码。
这套代码整合了鉴权、限流、审计三个模块。
你可以直接作为网关的核心骨架使用。

// 综合网关入口类
public class 企业级大模型网关 {

    // 初始化限流器,限制每个用户每分钟只能调 60 次
    private static final 限流器 用户限流器 = new 限流器(60, 60);

    public void 启动网关() {
        System.out.println("企业级大模型网关正在启动...");
        
        // 模拟接收一个请求
        网关请求 请求 = new 网关请求();
        请求.设置内容("帮我分析一下上季度的财报数据");
        请求.设置用户令牌("valid_token_123");

        try {
            // 执行过滤链路
            网关处理结果 结果 = 执行过滤链路(请求);
            
            if (结果.是否成功()) {
                System.out.println("请求已通过,转发至模型服务");
                // 这里调用模型服务...
            } else {
                System.out.println("请求被拦截: " + 结果.获取错误信息());
            }
        } catch (Exception 异常) {
            // 捕获未知异常,防止网关崩溃
            System.err.println("网关发生内部错误: " + 异常.getMessage());
        }
    }

    private 网关处理结果 执行过滤链路(网关请求 请求) {
        // 1. 限流检查
        if (!用户限流器.允许请求(请求.获取用户 ID())) {
            return new 网关处理结果(false, "请求过于频繁,请稍后再试");
        }

        // 2. 鉴权检查
        if (!认证服务.校验(请求.获取用户令牌())) {
            return new 网关处理结果(false, "认证失败");
        }

        // 3. 内容合规检查
        if (内容过滤器.包含敏感词(请求.获取内容())) {
            return new 网关处理结果(false, "内容不合规");
        }

        return new 网关处理结果(true, "通过");
    }
}

这段代码虽然精简,但逻辑完整。
它展示了如何串联多个过滤器,以及如何统一处理异常。
在实际项目中,你会把 认证服务内容过滤器 抽离成独立的微服务。
但核心思想不变:层层过滤,万无一失

七、总结

内网大模型部署,网关是生命线。
不要为了省事,直接把模型接口暴露出来。
合规不是阻碍,它是保护业务长期运行的护城河。
记住三点:

  1. 身份必验,内网 IP 不可信。
  2. 日志必脱敏,审计留痕不留痕。
  3. 限流必做,防止资源被耗尽。

把这套网关搭好,你的大模型项目就成功了一半。
剩下的,就是安心地享受 AI 带来的效率提升吧。

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐