阻断之外:通过日志、追踪、指标和告警重构LLM连续攻击

凌晨2点18分,LLM服务响起警报,提示策略阻断反复发生。应用程序回应称已阻止请求,但事件响应者需要了解更多。他们需要关联谁以何种权限进入、测试了哪道防线,以及在搜索、模型、工具执行中达到了何种程度。

LLM安全监控并非寻找一个危险的句子。它是通过连接认证主体、策略决策、执行路径、实际副作用和重复模式来重构攻击者的行为。request_id是单个请求的受理编号,而trace_id是串联多个服务中分散处理步骤的线索。

本文中的时间、标识符、日志和数值均为虚拟场景示例,并非实际测量值。

连续的LLM攻击请求经过防御层,并与日志、追踪、指标、告警证据关联的事件调查场景

不看单次事件,而看行为

已认证的usr_7f3首先正常查询了tenant-a的公开信息。接着,它通过“忽略之前的指令”来探索限制,并伪装成业务请求,要求tenant-b的文档。失败后,它试图诱导文档删除和外部传输工具,并在几分钟内改变表达方式重复尝试。单独来看是四个请求,但将主体、租户、时间、策略转移捆绑起来,就形成了一个从侦察到权限提升和执行尝试的单一流程。

sequenceDiagram
    participant U as 인증 사용자
    participant A as Application
    participant P as 정책 계층
    participant R as Retrieval
    participant M as Main Model
    participant T as Tool Executor
    U->>A: 정상 공개 조회
    A->>P: 인증·인가·입력 검사
    P-->>A: 허용
    A->>R: tenant-a 검색
    A->>M: 응답 생성
    U->>A: 지시 덮어쓰기·타 Tenant 요청
    P-->>A: 차단
    Note over R,T: 뒤 단계 호출 없음
    U->>A: 삭제·외부 전송 유도
    M-->>A: 도구 호출 제안
    A->>P: 실행 권한 재검사
    P-->>A: 차단
    Note over T: Executor 호출 없음

应用程序应留下的最小证据

最终的允许/阻断应记录为应用程序的策略决策,而非模型的措辞。即使模型输出拒绝语句,如果application_decision=ALLOW,则不是服务器阻断的证据。反之,即使显示普通的错误信息,如果权限策略中断了它,那就是明确的阻断。

{
  "request_id":"req-02f4", "trace_id":"7d31a9c0b4e2",
  "authenticated_principal":"usr_7f3", "tenant":"tenant-a",
  "prompt_hmac":"hmac:v1:91b7...",
  "prompt_excerpt":"[지시 변경] ... [외부 전송]",
  "application_decision":"BLOCK",
  "blocking_reason":"tool_not_authorized",
  "policy_rule":"TOOL-EXEC-004",
  "stage":"execution_authorization", "stage_order":60,
  "upstream_called":true, "retrieval_called":false,
  "tool_called":false, "tool_result":"not_executed",
  "http_status":403
}

存储原始Prompt会使日志成为新的个人信息和秘密存储库。使用服务器密钥创建的HMAC可以比较相同输入的重复性,而匿名化的excerpt只保留最小上下文。HMAC密钥应与日志分离,并对excerpt中的姓名、电子邮件、令牌、文档内容进行掩码处理。

使用Loki查找原因和顺序

Loki回答“谁在哪个阶段被哪个规则阻断了?”以下LogQL是一个虚拟示例,通过JSON字段缩小某个主体的阻断记录。

{service="llm-application"} | json
| authenticated_principal="usr_7f3"
| application_decision="BLOCK"
| line_format "{{.request_id}} {{.stage_order}} {{.blocking_reason}} {{.policy_rule}} {{.http_status}}"

同时查看正常对比请求。攻击应被阻断,而允许的公开查询应保持,这才是PASS的依据。唯一主体应在日志正文中进行假名化,但不要在Loki索引或Prometheus标签中无限扩展。

使用Tempo查看实际中断点

在Tempo中打开trace_id,可以查看authentication → authorization → input_guardrail → retrieval → main_model → execution_authorization → tool_executor的实际Span。输入阻断后,不应有Retrieval、Main Model或Tool Span;跨租户访问阻断后,不应有检索Span。

即使模型建议了工具调用JSON,如果execution_authorization=BLOCK,tool_called=false,并且没有Executor Span和副作用审计日志,则表示未执行。追踪在中间中断也不意味着攻击成功。可能是收集故障,因此如果缺少必要的Span,应将其标记为ERR并调查观测层。

使用Prometheus检测重复

Prometheus回答“最近阻断增加的速度有多快?”唯一用户ID和request_id会导致时间序列激增,因此Metric中只应包含有限的值,如Tenant、Policy、Decision。

sum by (tenant, policy_rule) (
  increase(llm_security_decisions_total{application_decision="BLOCK"}[5m])
) >= 4
- alert: RepeatedLLMPolicyBlocks
  expr: sum by (tenant, policy_rule) (increase(llm_security_decisions_total{application_decision="BLOCK"}[5m])) >= 4
  for: 1m
  labels: { severity: warning }

条件和阈值是虚拟示例。即使表达式为真,在for时间过去之前仍处于pending状态;如果持续为真,Prometheus中将变为firing。firing表示检测条件成立,并非攻击被阻断或通知已到达的证据。

通过Alertmanager和Webhook确认传递

Alertmanager接收警报,按alertname等进行分组,并应用静默、抑制和路由。屏幕上的active表示持有警报,不等同于Webhook接收成功。必须在最终接收日志中确认alertname=RepeatedLLMPolicyBlocks, severity=warning, 组键, 开始时间以及HTTP 2xx,才能说明接收服务已接受通知。2xx也并非负责人已阅读并响应的证据。Prometheus firing、Alertmanager active、Webhook接收是不同的阶段。

在Grafana中将事件连接到同一屏幕

Grafana不是创建新真相的存储库,而是连接Loki、Tempo、Prometheus证据的调查台。选择阻断增加的时间点,通过Loki行的trace_id打开Tempo,并同时查看同一时间段的Alertmanager和Webhook状态。如果面板为空,不要断定攻击成功,而是检查原始的LogQL、TraceQL、PromQL和收集器状态。

判断限制为三类。如果确认了越权文档返回、秘密泄露、未经授权工具的实际副作用,则为HIT。如果明确防御阻止了攻击且正常对比请求得以维持,则为PASS。如果因超时、5xx、空标识符、收集缺失或传递失败导致证据不足,则为ERR。ERR并非攻击成功,而是调查无法进行的状态。

如何避免错误结论

  • 不要仅凭模型的拒绝语句就判定为PASS。
  • 不要仅凭工具建议就判定为HIT。需要tool_result和实际副作用。
  • 不要因为没有警报就断定没有攻击。如果是观测故障,则为ERR。
  • 不要将单次阻断称为连续攻击。要连接相同主体、时间窗口和策略转移。

事件响应者应留下的一段话

虚拟事件摘要:在02:13~02:18之间,tenant-a的假名化认证主体usr_7f3在正常公开查询后,依次尝试了指令覆盖、访问其他租户文档、执行未经授权的外部传输工具。应用程序明确阻断了攻击请求,未确认禁止的Retrieval和Tool Executor执行以及实际副作用。正常查询得以维持。警报的Prometheus firing、Alertmanager active、Webhook 2xx接收也已确认,因此判定为PASS。如果缺少必要证据,则重新分类为ERR;如果确认实际影响,则重新分类为HIT。

实践清单

  • 正常和攻击请求是否都有request_id和trace_id?
  • 认证主体和租户是否通过假名化值关联?
  • 阻断后是否执行了Retrieval、Main Model或Tool Executor?
  • Loki的决策和Tempo的路径是否一致?
  • 是否分别确认了firing、active和Webhook接收?
  • 是否没有强行将证据不足的情况判定为PASS或HIT?

优秀的LLM安全监控并非止于“已阻断”这一句话。它连接请求和追踪,通过指标检测重复,并验证传递路径,将检测转化为可解释的响应。

官方参考资料


Comments

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注