给AI应用配安全日志,先定字段再落地采集与验证

AI安全日志配置要解决的是“出了事能查到什么”的问题,而不是简单打开一个日志开关。
对大多数自建AI应用来说,可行的最小方案是:在Nginx层记录请求元数据,在Python应用层记录模型调用和异常事件,统一字段格式后写入文件,再用日志轮转控制磁盘占用。
下面按这个顺序展开。

先定字段,再决定写到哪里

安全日志和普通业务日志的区别在于,它要能回答三个问题:谁在什么时候调用了哪个模型接口、请求内容是否异常、服务端返回了什么。
建议至少包含以下字段:

  • timestamp:ISO 8601 格式时间,方便跨服务对齐
  • request_id:一次请求的唯一标识,用于串联Nginx日志和应用日志
  • client_ip:调用方IP,经过代理时从 X-Forwarded-For 取第一个地址
  • user_id 或 api_key_id:调用者身份,不要记录完整API Key
  • model_name:被调用的模型名称
  • prompt_length 和 completion_length:输入输出长度,用于发现异常大请求
  • status_code:HTTP状态码或业务错误码
  • latency_ms:处理耗时
  • event_type:如 request、auth_fail、rate_limit、model_error

字段确定后,写入位置就清楚了:Nginx能拿到IP、状态码、耗时和请求路径;
Python应用能拿到模型名称、token长度和业务异常。
两边用同一个 request_id 关联,后续排查才不用靠猜。

如果使用云厂商的API网关或模型服务,先确认其是否已提供调用日志和审计日志,能直接开启的优先开启,再补充应用层字段,避免重复建设。

在Nginx层记录请求元数据

假设AI推理服务通过Nginx反向代理暴露,在 http 块中定义日志格式,写入 /etc/nginx/nginx.conf 或站点配置的 server 块之前:

log_format ai_security escape=json
  '{"time":"$time_iso8601",'
  '"request_id":"$request_id",'
  '"client_ip":"$remote_addr",'
  '"method":"$request_method",'
  '"path":"$request_uri",'
  '"status":$status,'
  '"body_bytes":$body_bytes_sent,'
  '"request_time":$request_time,'
  '"upstream_time":"$upstream_response_time",'
  '"user_agent":"$http_user_agent"}';

然后在对应的 server 块中启用:

access_log /var/log/nginx/ai_access.log ai_security;

执行 nginx -t 检查语法,通过后 systemctl reload nginx 重载。
这里要注意:$request_id 是Nginx内置变量,但只有在配置中显式引用时才会生成并透传给后端,建议在 location 中加一行 proxy_set_header X-Request-Id $request_id;,让Python应用能拿到同一个ID。

Nginx日志不记录请求体,这是有意的设计。
请求体可能包含用户隐私或敏感提示词,是否记录、记录多少需要单独评估,不要默认全量落盘。

Python应用层记录模型调用事件

应用层推荐使用标准库 logging 配合JSON格式输出,避免自己拼接字符串。
下面是一个最小示例,写入 /opt/ai-app/app.py 同级目录的 security_logger.py:

import logging
import json
import time

logger = logging.getLogger("ai_security")
logger.setLevel(logging.INFO)
handler = logging.FileHandler("/var/log/ai-app/security.log")
handler.setFormatter(logging.Formatter("%(message)s"))
logger.addHandler(handler)

def log_event(request_id, event_type, **kwargs):
    record = {
        "timestamp": time.strftime("%Y-%m-%dT%H:%M:%S%z"),
        "request_id": request_id,
        "event_type": event_type,
    }
    record.update(kwargs)
    logger.info(json.dumps(record, ensure_ascii=False))

在推理接口中调用:

log_event(
    request_id=request_id,
    event_type="request",
    client_ip=client_ip,
    model_name="qwen-local",
    prompt_length=len(prompt),
    completion_length=len(answer),
    status_code=200,
    latency_ms=int((time.time() - start) * 1000),
)

鉴权失败、触发限流、模型调用超时等分支也应各自调用一次 log_event,把 event_type 设为对应值。不要记录完整的prompt和response原文,除非业务明确要求且已做脱敏;
安全日志的目标是发现异常模式,不是保存聊天记录。

日志目录需要提前创建并设置权限:

sudo mkdir -p /var/log/ai-app
sudo chown www-data:www-data /var/log/ai-app
sudo chmod 750 /var/log/ai-app

运行服务的用户必须对目录有写权限,否则应用启动时不会报错,但日志会静默丢失。
用 ls -ld /var/log/ai-app 确认属主与运行用户一致。

配置日志轮转,避免磁盘被写满

安全日志增长快,必须配置轮转。
在 /etc/logrotate.d/ai-security 中写入:

/var/log/nginx/ai_access.log /var/log/ai-app/security.log {
    daily
    rotate 14
    compress
    delaycompress
    missingok
    notifempty
    create 0640 www-data adm
    sharedscripts
    postrotate
        systemctl reload nginx > /dev/null 2>&1 || true
    endscript
}

执行 logrotate -d /etc/logrotate.d/ai-security 做一次演练,确认没有语法错误和路径不匹配。
轮转生效后,security.log 会被压缩成 security.log.1.gz,检索历史日志时需要解压或用 zgrep。

验证日志链路是否真的通了

配置完成后不要只看文件存在,要实际发一次请求再检查。

  1. 发起测试请求:
curl -s -o /dev/null -w "%{http_code}\n" \
  -H "Content-Type: application/json" \
  -d '{"prompt":"test"}' \
  http://127.0.0.1:8000/v1/chat
  1. 检查Nginx日志中是否出现对应记录:
tail -n 5 /var/log/nginx/ai_access.log

预期能看到包含 request_id、status、request_time 的JSON行。

  1. 检查应用日志:
tail -n 5 /var/log/ai-app/security.log

预期能看到 event_type 为 request 的记录,且 request_id 与Nginx日志中的值一致。

  1. 用同一个 request_id 串联两边:
grep '你的request_id' /var/log/nginx/ai_access.log
grep '你的request_id' /var/log/ai-app/security.log

如果应用日志为空,优先检查运行用户是否有目录写权限、FileHandler 路径是否写错;
如果Nginx日志没有 request_id,检查 proxy_set_header 是否加在了正确的 location 中。

几个容易踩的坑

日志里出现完整API Key:鉴权失败时不要把请求头原样打进去,只记录 api_key_id 或Key的后四位。

只记录成功请求:安全事件往往发生在失败分支,401、429、5xx 必须记录,否则日志对排查没有价值。

时间格式不统一:Nginx用 $time_iso8601,Python用带时区的ISO格式,两边都保留时区信息,否则跨时区部署时对不上。

日志目录权限过宽:安全日志包含IP和调用行为,目录权限建议 750,文件权限 640,不要用 777 图省事。

日志配置完成后,下一步通常是基于这些字段设置异常规则,例如同一IP在短时间内的 auth_fail 次数、单次 prompt_length 超过阈值等。
先把字段和采集链路跑通,后续的检索和告警才有可靠的数据来源。

分享到:
上一篇
AI安全告警配置:从日志采集到告警通知的实操步骤
下一篇
AI安全加固教程:从模型接口到服务器层做一轮可验证的加固
1
系统公告

关于香港云优质服务器IP地址更换的通知

尊敬的客户: 因原IP运营商大幅涨价,为避免成本转嫁至用户,我司决定更换IP服务商。本次更换后,您的续费价格将保持不变,且新IP网络质量与服务标准不受影响。新IP已分配至后台,即刻生效(更换的新IP都是香港原生IPv4)。 涉及 IP 段: 45.192.x.x 旧 IP 停用时间: 2026 年 12 月 1 日
服务中心
客服
在线客服
24小时为您服务
咨询
联系我们
联系我们,为您的业务提供专属服务。
24/7 技术支持
如果您遇到寻求进一步的帮助,请过工单与我们进行联系。
24/7 即时支持
泽御云
售前客服
泽御云
泽御云
售后客服
泽御云
技术支持
评价
您对当前页面的整体感受是否满意?
😞
非常不满意
😕
不满意
😐
一般
🙂
满意
😊
非常满意