前端进阶之旅前端进阶之旅
基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
AI 篇
小程序题库
  • 每日一题每天一道,攒手感
  • 原理篇React / Vue 源码拆解
  • 知识卡片NEW碎片时间过考点
  • 历年面经按年份追踪真实考点
  • 算法题库在线编码即时判题
  • 专项自测100 题快速查漏
  • 业务场景题真实业务问题与追问
  • 查漏补缺常见问题解析
  • AI 模拟面试NEW模拟真实面试 + 报告
  • 前端基础
    • HTTP从报文一路讲到 HTTPS
    • 浏览器渲染、事件循环、进程
    • 计算机基础Linux、网络、操作系统
  • 进阶专项
    • 设计模式23 种模式怎么用
    • 前端系统进阶学习大型项目工程化
    • 前端综合文章长期沉淀的实践文
  • 工程与工具
    • Node学习指南从环境搭建到服务端
    • NPM工作流script、依赖与发布
    • Docker容器化部署上手
    • Canvas图形与动画实战
  • 路线与导图
    • 思维导图知识点全景图
    • 学习路线按图索骥不跑偏
    • AI 定制路线NEW按你的简历现排
    • AI 知识地图NEW串起全站知识点
  • 动态
    • AI 热点NEWAI 每日动态
    • 公众号动态公众号历史文章
    • 博客动态站长的技术博客
    • 开发者导航常用工具与文档站
AI 助手NEW
旧版
基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
AI 篇
小程序题库
  • 每日一题每天一道,攒手感
  • 原理篇React / Vue 源码拆解
  • 知识卡片NEW碎片时间过考点
  • 历年面经按年份追踪真实考点
  • 算法题库在线编码即时判题
  • 专项自测100 题快速查漏
  • 业务场景题真实业务问题与追问
  • 查漏补缺常见问题解析
  • AI 模拟面试NEW模拟真实面试 + 报告
  • 前端基础
    • HTTP从报文一路讲到 HTTPS
    • 浏览器渲染、事件循环、进程
    • 计算机基础Linux、网络、操作系统
  • 进阶专项
    • 设计模式23 种模式怎么用
    • 前端系统进阶学习大型项目工程化
    • 前端综合文章长期沉淀的实践文
  • 工程与工具
    • Node学习指南从环境搭建到服务端
    • NPM工作流script、依赖与发布
    • Docker容器化部署上手
    • Canvas图形与动画实战
  • 路线与导图
    • 思维导图知识点全景图
    • 学习路线按图索骥不跑偏
    • AI 定制路线NEW按你的简历现排
    • AI 知识地图NEW串起全站知识点
  • 动态
    • AI 热点NEWAI 每日动态
    • 公众号动态公众号历史文章
    • 博客动态站长的技术博客
    • 开发者导航常用工具与文档站
AI 助手NEW
旧版
返回 AI 情报前线
All News · 全部资讯8294
  • AWS 双层方案监控生产环境 Agent 生命周期
  • 选对 Bedrock 上的 OpenAI 模型:超越每百万 token 价格
  • 用 Bedrock AgentCore 构建支持交互组件的 MCP 应用
  • 2026 Agentic AI安全警示:模型越狱与网络突破
  • 万级Agent集群架构实战:10万次编排背后的工程方法论
  • Anthropic内部标准:生产代码的AI辅助应有更高门槛
  • 陶哲轩等数学家联名批评 AI 数学推理的严重错位问题
  • 陶哲轩:AI 数学推理的严重错位
  • Hugging Face安全Txt暗藏AI伦理考题
  • Next.js Copilot安全设计审查清单
  • Agent PR中的内存缓存——代码审查的盲区
  • 一次 stamping:约束AI Agent范围的工程方法
  • AI生成的C++补丁为何在Release版崩溃
  • 本地优先Agent的四个信号决策门
  • AI Agent记忆 vs RAG:核心区别与工程选择
  • AI代码审查的签署人制度SOP
  • 用「每修复成本」替代通过率评估AI Agent
  • Agent「修复成功」但进程从未退出引发的生产事故
  • 面试AI编程能力应先评估「循环预算」
  • 部署 AI 推理网关前,先查队年龄龄而非面板利用率
  • WAF 拦截日志拷进 AI 助手?Cookie 和 token 也一起泄露了
  • 给无人值守 AI Worker 配一张 JSON 检查卡
  • Anthropic 报告:黑客用 Claude 开发导弹与无人机,中国实验室批量挖掘训练数据
  • 律师用ChatGPT生成上诉文书虚构证人证词,被罚5000美元
  • Claude Code Hookbook:20 个开箱即用的 Claude 钩子库
  • OpenAI如何扩展存储架构支撑10亿ChatGPT用户
  • 每天为同一段上下文付三次钱:Agent 记忆缺失的代价
  • OpenAI Agents API公开测试:Codex同款基础设施向开发者开放
  • Vercel开源skills:AI编程智能体技能共享生态
  • OmniRoute:聚合352个AI服务商免费额度的开源网关
  • DeepSeek V4.1 Flash发布:提供商别名路由与890B缓存的代价
  • DeepSeek Flash搅局:MoE架构将百万token成本打至新低
  • AI生成支付代码的五大安全漏洞与防护策略
  • Sakana AI推出Fugu Max/Ultra v2,主打多Agent编排降本
  • Google 发布 ToolGrad:先建 API 链再写 Query,ToolBench 通过率 99.8%
  • OpenAI GPT-Live-1 API支持实时语音交互
  • 美团Agent评测白皮书:评测体系全览
  • Apify MCP服务器让AI实时获取电商数据
  • 语音AI延迟从4.2秒压到780ms:逐字优化实录
  • Datasette紧急安全补丁:AI辅助审计发现多个微妙漏洞
  • DevOps AI Agent 审计追踪:关联每次 kubectl 与 Git 操作
  • AI 写的 PR 测试全绿:你的合并标准是什么
  • 放 AI Agent 进仓库前必须锁死的五项配置
  • LLM API 重试逻辑:官方 SDK 只做了一半
  • 生产环境微调对比:Claude vs GPT vs Llama 实操指南
  • Claude AI用11天完成费马大定理机器证明,代码1300万行
  • 面向 AI Agent 的 24 端点 URL 元数据 API
  • 免费在线工具:LLM 工具 JSONSchema 一键生成
  • LLM 智能体暴露现代软件工程的脆弱性
  • OpenAI Agents API 公测:云端智能体基础设施开放
  • GitHub Copilot支持Jira集成和Project HydraFusion
  • 已加载 51 / 8294
9.0
重磅
AI SCORE
行业动态2026-09-11 23:12

WAF 拦截日志拷进 AI 助手?Cookie 和 token 也一起泄露了

dev.to · AI#WAF#提示词注入#安全运营
Editor brief · 编辑速览

WAF 阻断请求后,安全工程师常把日志粘贴给 AI 模型分析,但日志中残留的 Cookie、Bearer token、session id 会被模型读取——阻断不等于脱敏,信任边界已悄然转移。

文章思维导图
Knowledge map
拖拽缩放
Full translation

完整中文译文

WAF 完成了它的工作。请求从未抵达应用层。于是我把拦截日志复制给了一个编码模型,问了一个合理的问题:这是 SQLi,还是噪声误报?

模型回答了。同时它也收到了 Cookie 请求头、Bearer token,以及挂在查询字符串里的 session id。攻击者从未到达源站,但我还是把 session 甩给了提示词 API 后面的任何东西。眼熟吗?

这是一个实验演练,不是生产事故报告。没有真实租户受影响。但这种失效模式是真实存在的:拦截请求的控制措施不会自动产生一个净化后的产物。如果你粘贴的是产物,你就移动了信任边界。

粘贴才是特权操作

WAF 位于客户端到源站的路径上。你的剪贴板位于工程师到模型的路径上。这不是同一个边界。混淆它们,就是把被拦截的 cookie 变成提示词。

flowchart LR
  Client -->|HTTPS request| WAF
  WAF -->|allow / block| Origin
  WAF -->|block event| LogStore
  LogStore -->|export / copy| Engineer
  Engineer -->|prompt pack| ModelRuntime

大声问出那个丑陋的问题。谁被允许查看 Cookie?WAF 进程,也许还有 SIEM,也许还有已经有生产权限的 on-call 工程师。远程补全 API 不在那个名单上。共享 GPU 盒子也不在那个名单上,即使没有人为此给你开账单。

在这次演练中,我把三个事实视为不可协商的:

拦截日志是恶意输入。它们包含攻击者载荷和浏览器附加的任何东西。

查询字符串是伪装成 URL 参数的请求头。Token 出现在那里是因为 2019 年有人偷懒,客户端从未打过补丁。

"我只粘贴了一行"不是控制措施。一行就足够了。

评审包允许包含什么

我想要模型帮我分类规则触发事件。我不想要它重建一个会话。所以提示词包使用白名单,而不是一段"请小心使用"的空话。

这个 fixture 允许的字段:

ts、method、path(不含查询字符串)、status、rule_id、action、latency_ms、proto

X-Api-Key / X-Auth-Token

查询字符串中的 access_token、id_token、refresh_token、sessionid、sid

原始 URL,仍带有 ?

白名单从未命名的额外 JSON 键

为什么拒绝额外键?因为 WAF 导出器喜欢"有用"的字段。raw_request。header_map。decoded_body。多一个额外键,你的白名单就成了演戏。

Source IP 敏感吗?有时候是。我故意把它放在白名单之外。如果你的 IR runbook 需要它,且模型运行时与 SIEM 处于同一信任区域,你可以加回来。这是一个策略选择。不是默认值。

实验 fixture,固定版本并标注

固定运行时:Python 3.12。本模板未针对真实 WAF 执行。它是提示词包的回归门。如果你把它指向生产日志,你自己负责脱敏策略,不是这篇文章。

正向 fixture——必须失败。结构化事件加上一行原始混合风格。两者都泄露。

# fixtures/positive.log
{"ts":"2026-09-11T02:14:08Z","method":"POST","path":"/login?access_token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJsYWIifQ.labfixturetoken","status":403,"rule_id":"sql-1","action":"block","latency_ms":12,"cookie":"session=abc"}
02:14:08 POST /admin HTTP/1.1 403 Authorization: Bearer lab-token-32chars Cookie: sid=1

负向 fixture——必须通过。同样的攻击类别。包内无凭证。

# fixtures/negative.log
{"ts":"2026-09-11T02:14:08Z","method":"POST","path":"/login","status":403,"rule_id":"sql-1","action":"block","latency_ms":12,"proto":"HTTP/1.1"}

正向文件的预期失败证据:非零退出码,至少一个发现命名为 json_keys_outside_allowlist、path_contains_query、access_token_qs、cookie_header、authorization_header 或 jwt_like。负向文件的预期证据:退出码 0 且输出 ok。

#!/usr/bin/env python3
"""Refuse to pack WAF/block logs that still contain secrets. Lab fixture."""
from __future__ import annotations

import argparse
import json
import re
import sys
from pathlib import Path

DENY_PATTERNS = [
    ("authorization_header", re.compile(r"(?i)authorization\s*[:=]\s*bearer\s+\S+")),
    ("cookie_header", re.compile(r"(?i)\bcookie\s*[:=]\s*\S+")),
    ("set_cookie", re.compile(r"(?i)set-cookie\s*[:=]")),
    ("jwt_like", re.compile(
        r"\beyJ[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}\b"
    )),
    ("access_token_qs", re.compile(
        r"(?i)(access_token|id_token|refresh_token|sessionid|sid)="
    )),
    ("api_key_header", re.compile(r"(?i)(x-api-key|x-auth-token)\s*[:=]\s*\S+")),
]

ALLOW_KEYS = {
    "ts", "method", "path", "status", "rule_id", "action", "latency_ms", "proto",
}

def findings_in_text(blob: str) -> list[tuple[str, str]]:
    hits: list[tuple[str, str]] = []
    for name, cre in DENY_PATTERNS:
        match = cre.search(blob)
        if match:
            hits.append((name, match.group(0)[:80]))
    return hits

def findings_in_line(line: str) -> list[tuple[str, str]]:
    try:
        obj = json.loads(line)
    except json.JSONDecodeError:
        return findings_in_text(line)
    if not isinstance(obj, dict):
        return findings_in_text(line)
    hits: list[tuple[str, str]] = []
    extra = sorted(set(obj) - ALLOW_KEYS)
    if extra:
        hits.append(("json_keys_outside_allowlist", ",".join(extra)))
    packed = " ".join(str(obj.get(k, "")) for k in ALLOW_KEYS if k in obj)
    hits.extend(findings_in_text(packed))
    path = obj.get("path")
    if isinstance(path, str) and "?" in path:
        hits.append(("path_contains_query", path[:80]))
    return hits

def scan(path: Path) -> list[tuple[int, str, str]]:
    out: list[tuple[int, str, str]] = []
    for i, line in enumerate(path.read_text(encoding="utf-8").splitlines(), 1):
        if not line.strip() or line.startswith("#"):
            continue
        for name, snippet in findings_in_line(line):
            out.append((i, name, snippet))
    return out

def main() -> int:
    parser = argparse.ArgumentParser()
    parser.add_argument("--input", type=Path, required=True)
    parser.add_argument("--expect", choices=("pass", "fail"), required=True)
    args = parser.parse_args()
    hits = scan(args.input)
    if hits:
        for line_no, name, snippet in hits:
            print(f"FAIL line={line_no} rule={name} snippet={snippet!r}")
        failed = True
    else:
        print("ok")
        failed = False
    if args.expect == "fail" and not failed:
        print("expected findings, got a clean pack")
        return 2
    if args.expect == "pass" and failed:
        return 1
    return 0

if __name__ == "__main__":
    sys.exit(main())

不要从争论模型供应商开始。先证明这个门是关闭失效的。

把脚本保存为 waf_log_prompt_gate.py,两个 fixture 放在同目录。

先跑负向路径。如果这个失败了,你的白名单写错了,不是模型的问题。

跑正向路径。如果这个通过了,门在撒谎,你还会再粘贴 cookie。

只有到那时才导出一个真实的拦截事件,脱敏到白名单,然后用 --expect pass 重新跑。

保留原始事件在 SIEM。模型永远不需要原始版本。

python3 --version   # expect Python 3.12.x
python3 waf_log_prompt_gate.py --input fixtures/negative.log --expect pass
python3 waf_log_prompt_gate.py --input fixtures/positive.log --expect fail

如果第 3 步打印了 expected findings, got a clean pack,停下来。你没有检测器。你只是 wiki 里的一个注释。

预防、检测、恢复

注意少了什么:"让模型忽略 secrets"。那不是控制措施。模型不会执行你的隐私策略。它们只是补全文本。

自托管推理移动了边界。它没有删除边界。

远程模型 API 是显而易见的泄露点。然后人们切换到桌下的一台机器就放松了。为什么?因为"这是我们的 GPU"感觉像是一个安全属性。它不是。它只是一个位置。

磁盘快照、共享操作员访问、提示词缓存,以及下一个实习生的 tmux session 仍然能看到那个包。如果你用编码助手审查 WAF 事件,在字节离开日志存储之前就做脱敏。运行时应该只收到白名单化的 JSON,不要其他东西。

披露:本文是 MonkeyCode 产品推广的一部分。MonkeyCode 是一个开源 AI 开发平台,提供免费模型访问和免费服务器选项。我在这里关心它的原因只有一个:你可以在自己运营的基础设施上保留对净化后拦截事件的评审。这不允许在提示词中出现原始 Cookie。如果本文中的门失效了,不要发送那个文件,包括发送到你喜欢的那台服务器。

自托管选项是一个部署决策。不变式仍然是:"提示词包中不得包含 session 材料。"

局限性,以及谁应该跳过这个

Regex 不是 HTTP 解析器。编码后的 cookie、分片请求头、分块请求体、gzip 和 protobuf 导出器都会绕过这些模式。多部分上传也会。请求头中的同形异义词也会。如果你的 WAF 把二进制对象写入对象存储,这个脚本救不了你。

白名单也故意丢弃了取证细节。path 加 query 可能是整个事件的全部。如果你在积极进行 IR,且需要在模型评审的同一窗口中获得原始字节,不要用编码模型作为查看器。用 SIEM、用有访问控制的工单、用已经持有生产凭证的人。

如果以下情况,跳过这种方法:

你不拥有日志管道(你将与导出格式无休止地斗争)

你需要在模型评审的同一窗口中进行完整 PCAP 或请求体重建

你的"WAF"是你无法在下载前剥离的 CDN dashboard

你想要一个让泄露变得安全的魔法提示词

这个 fixture 不能证明供应商在你数据上训练过模型。它只能证明你差点把 session 交给了他们。这是不同的主张。把它们分开。

哪一层拥有这个不变量?

我想要导出按钮成为执行点。CI 对提示词包文件的检查是回归测试。模型运行时是最后一道关卡,而最后关卡会失效。

所以这里是我真正想在评审中回答的边界问题:WAF 控制台是否拒绝复制被拒绝的字段,还是我们继续依赖工程师在剪贴板已经丢失之后运行一个 Python 门?

如果你已经在评估自托管编码工作区,把这个门放在提示词包第一次补全之前——包括在免费服务器上。有趣的部分不是产品。而是你拦截的那个 cookie 是否还坐在你即将粘贴的那个 JSON 里。

Original source

本文由 AI 翻译整理自 dev.to · AI,原文版权归原作者所有。

阅读英文原文
上一篇
部署 AI 推理网关前,先查队年龄龄而非面板利用率
下一篇
给无人值守 AI Worker 配一张 JSON 检查卡