Skip to content

AI数据从采集到删除的全生命周期安全

AI 数据安全不是在模型输出后用正则把手机号打星。一次 AI 请求可能复制数据到用户输入、会话历史、RAG Chunk、Embedding、Tool Result、Prompt、第三方 Provider、流式缓冲、Trace、缓存、评估集和人工标注平台。只处理其中一份,其他副本仍可能泄露或继续被检索。

核心目标是:

text
知道数据是什么
→ 为什么需要
→ 谁能访问
→ 能发到哪里
→ 保存了几份
→ 保存多久
→ 怎样撤销和删除
→ 如何证明控制有效

本章讲工程原理和通用控制方向,不替代组织所在司法辖区、行业和合同所要求的法律合规评估。

一、学习目标

学完后,你应该能够:

  • 区分 AI 数据安全、模型行为安全和传统应用安全。
  • 画出数据在 Prompt、RAG、Tool、Provider、日志、缓存和评估集中的副本链。
  • 建立数据分类、字段级策略、处理目的和允许目的地。
  • 区分删除、掩码、泛化、假名化、匿名化、哈希、HMAC 和加密。
  • 解释为什么普通哈希不能可靠保护手机号、身份证等低熵数据。
  • 设计发送外部模型前的字段级最小化和阻断规则。
  • 设计 RAG 的入库分级、ACL、检索过滤、引用和删除传播。
  • 设计 Tool Result 的字段投影、再鉴权、脱敏和限长。
  • 评估第三方 Provider 的留存、训练使用、区域、子处理者和删除能力。
  • 设计租户、ACL、模型、Prompt 和索引版本隔离的缓存 Key。
  • 管理日志、Trace、评估集和人工标注中的敏感副本。
  • 解释删除请求为何需要清单、状态机、对账、备份到期和例外记录。
  • 运行字段策略 Demo 和删除传播 Demo。
  • 根据 requestId 和 dataSubjectId 排查越权、日志污染和删除不完整。

二、AI数据安全与AI安全有什么区别

维度AI数据安全AI行为与系统安全
主要问题数据是否被多收、多发、越权、长期留存模型是否被注入、误导或诱导调用工具
主要对象输入、文档、Prompt、Tool、日志、缓存、评估集指令层级、Tool权限、Agent动作、输出行为
主要控制分类、目的限制、最小化、ACL、加密、删除注入防护、参数校验、幂等、审批、沙箱

两者会交叉。例如 RAG 文档注入属于行为攻击,但如果恶意文档诱导模型泄露其他患者资料,最终又是数据安全事件。真正的边界必须由后端权限和数据控制实现,不能只靠 Prompt。

三、一条数据会被复制到哪里

mermaid
flowchart TD
    A["用户输入或业务记录"] --> B["API网关与业务后端"]
    B --> C["会话与Prompt编排"]
    B --> D["Tool调用"]
    B --> E["RAG检索"]
    E --> F["Chunk、Metadata与向量"]
    C --> G["模型网关"]
    D --> C
    F --> C
    G --> H["本地或第三方Provider"]
    H --> I["模型输出与流式缓冲"]
    I --> J["业务响应和结果缓存"]
    B --> K["日志、Trace和指标"]
    I --> K
    K --> L["评估集、反馈与人工标注"]
    F --> M["快照、备份和灾备副本"]

3.1 为什么数据副本容易被忽略

业务表可能只保存一份患者记录,但 AI 链路为了调试和评估又保存:

  • 完整用户问题。
  • 完整 Prompt。
  • RAG 片段。
  • Tool HTTP 请求和响应。
  • Provider 请求日志。
  • SSE 临时缓冲。
  • 会话记忆。
  • 语义缓存。
  • 线上失败样本。
  • 标注平台导出文件。

删除源记录不代表这些副本自动消失。

3.2 先做数据流清单

每条链路至少登记:

text
数据类别
字段和数据主体标识
业务目的
来源系统
处理服务
传输目的地和区域
存储位置
访问角色
加密方式
保留期限
删除能力
备份恢复方式
责任人

没有清单就无法回答“这条身份证号是否发给了外部模型”“删除请求还剩哪些副本”。

四、分类分级必须落实到系统行为

示例分级,组织应根据法律、行业和业务风险制定自己的标准:

级别示例AI链路默认方向
Public已授权公开FAQ可处理,仍做版权和来源控制
Internal内部接口文档、一般运维手册仅授权用户和企业链路
Sensitive手机号、地址、合同金额、患者标识目的限制、最小化、假名化或脱敏
Restricted密码、API Key、支付凭证、完整病历明细默认阻断外部模型与普通日志
Regulated医疗、金融、未成年人等受监管数据合规评估、区域和审计控制

4.1 字段级目录

text
fieldName: patient_id
classification: Sensitive
purposes: [field_definition, authorized_case_analysis]
externalModelAllowed: false
localModelAllowed: conditional
logAction: HMAC_TOKEN
evaluationAction: SYNTHETIC_REPLACE
retentionDays: 30
owner: medical-data-governance

4.2 分级不是只看字段名

自由文本可能包含手机号、病历和密钥;普通字段组合也可能重新识别个人。例如年龄、科室、稀有病和精确时间组合可能指向唯一患者。需要同时考虑:

  • 显式标识符。
  • 准标识符组合。
  • 自由文本实体识别。
  • 数据规模和可关联性。
  • 处理目的和接收方。

五、目的限制与数据最小化

“有权限访问订单”不等于“可以把订单全部字段发给模型”。权限回答“能否访问”,目的限制回答“当前任务需要哪些字段”。

用户问订单是否发货,完整对象可能有:

json
{
  "orderNo": "SO-1001",
  "status": "SHIPPED",
  "trackingNo": "YT123",
  "phone": "13812345678",
  "address": "北京市朝阳区...",
  "internalCost": "83.60",
  "paymentToken": "pay_secret"
}

模型只需要:

json
{
  "orderNo": "SO-1001",
  "status": "SHIPPED",
  "trackingNo": "YT123"
}
mermaid
flowchart TD
    A["业务对象"] --> B["确认任务Purpose"]
    B --> C["加载字段策略版本"]
    C --> D{"字段是否为完成任务必需"}
    D -- "否" --> E["Drop"]
    D -- "是" --> F{"目的地是否允许该级别"}
    F -- "否" --> G["阻断、改走本地或人工"]
    F -- "是" --> H["保留、掩码、泛化或假名化"]
    H --> I["发送最小上下文"]

最小化应在调用 Provider 之前完成。只在模型输出后脱敏,敏感数据已经离开安全边界并可能进入 Provider 日志。

六、八种处理方式不能混为“脱敏”

方法能否恢复能否稳定关联典型用途
删除任务不需要的字段
掩码原值仍在权威系统,展示不可逆方向部分给用户显示后四位
泛化精度降低,通常不可直接恢复可能精确地址变城市、年龄变区间
摘要只保留任务语义取决于摘要长记录变风险结论
假名化通过受控映射可恢复patientId换随机Token
普通哈希理论不可逆,但可字典枚举高熵内容校验,不适合裸哈希低熵PII
HMAC需密钥计算,防公开字典预计算日志关联Token、去重
加密持有密钥可恢复存储或传输中保护原文

6.1 掩码

text
13812345678 → 138****5678

适合展示,不等于匿名化。用户仍可能被其他字段识别。

6.2 假名化

text
patient_id=P1001 → subject_token=RANDOM-8f31

映射表由独立受控服务保存。拿到映射或其他关联数据仍可还原主体,所以假名化数据仍应按敏感数据保护。

6.3 为什么手机号不能直接SHA-256后公开

手机号、身份证格式空间有限,攻击者可以枚举候选并计算相同哈希进行比对。盐能阻止通用预计算表,但如果盐公开且每条可验证,仍可能被逐条暴力枚举。

需要稳定关联又不暴露原值时,可使用服务端秘密密钥 HMAC:

text
token = HMAC(secretKey, normalizedValue)

密钥必须在 KMS/Secret 中管理、限权和轮换。HMAC 也不是匿名化,拥有密钥或可查询 Token 服务仍能关联。

6.4 加密不等于最小化

数据在传输和存储时加密,进入模型计算前通常要解密。若模型根本不需要字段,正确措施是删除字段,而不是“加密后连同密钥一起发给模型”。

6.5 匿名化要求更高

真正匿名化要求合理方式下无法重新识别数据主体。只删姓名、换 ID 通常只是去标识或假名化。是否达到法律意义的匿名化需要结合攻击模型、外部数据和专业评估,文档不能用“打星号”直接宣称匿名。

七、传输加密、静态加密和信封加密

7.1 传输中

使用 TLS,校验证书和主机名;内部服务同样需要身份认证和网络策略。TLS 只保护链路,不能阻止接收方服务记录明文。

7.2 静态存储

数据库、对象存储、向量库、日志和备份都要考虑加密。磁盘加密防设备或快照直接泄露,但数据库管理员权限、应用查询权限仍要单独控制。

7.3 信封加密方向

mermaid
flowchart TD
    A["KMS中的主密钥KEK"] --> B["生成或解密数据密钥DEK"]
    B --> C["DEK加密业务数据"]
    C --> D["存储密文与被KEK加密的DEK"]
    D --> E["授权服务请求KMS解封DEK"]
    E --> F["内存中短暂解密使用"]

应用不应把主密钥硬编码在配置、镜像、Prompt 或日志。密钥轮换需要版本、重加密策略、回滚和审计。

八、Prompt编排的数据安全

Prompt 可能包含:

  • System/Developer 规则。
  • 用户问题。
  • 会话历史。
  • RAG Chunk。
  • Tool Result。
  • Few-shot 示例。

每一部分都应有来源、分类、租户、保留和最大长度。

8.1 会话历史不是无限信任

历史中可能有已撤销权限的数据、过期 Token 或用户先前粘贴的隐私。每轮组装都应重新按当前身份和保留策略裁剪,不能因为曾经进入会话就永久可见。

8.2 Few-shot不能用真实敏感样本

示例会进入每个请求,真实患者和订单样本会被重复扩散。使用合成、匿名化并经审核的示例。

8.3 Prompt版本也可能敏感

System Prompt 可能包含内部流程、工具名称和风控规则。不要把密钥写入 Prompt;Prompt 存储需访问控制,但系统安全不能依赖“用户永远无法推断 Prompt”。

九、RAG全生命周期数据安全

mermaid
flowchart TD
    A["原始文档"] --> B["授权、分类和恶意内容检查"]
    B --> C["解析、最小化和脱敏"]
    C --> D["稳定docId、chunkId与ACL"]
    D --> E["Embedding并写候选索引"]
    E --> F["权限、删除和召回评估"]
    F --> G["发布Alias"]
    H["用户查询"] --> I["认证上下文生成Filter"]
    I --> J["Filter-aware召回"]
    J --> K["Rerank仍保留ACL"]
    K --> L["Prompt预算与引用"]
    L --> M["输出权限和引用校验"]

9.1 入库前

  • 确认文档处理授权和用途。
  • 分类分级。
  • 检测秘密、患者信息和恶意文档注入。
  • 高敏内容决定阻断、脱敏、本地处理或不入库。
  • 保存来源、owner、版本、tenantId、ACL、有效期。

9.2 Embedding也可能泄露信息吗

向量不是可直接阅读原文,但不能自动视为匿名。攻击者可能进行成员推断、相似性探测或利用关联数据推测内容;向量还关联 Metadata 和原文 ID。向量库、索引快照和 Embedding Cache 仍需权限、加密和删除治理。

9.3 检索时

tenantId、role、department、securityLevel 必须来自服务端认证上下文,在候选召回前或索引遍历中生效。Post-filter 不足以作为安全边界。

9.4 引用

模型只能返回本次已授权候选的 citationId;URL、页码和路径由应用根据真实 Metadata 渲染。不能让模型自由生成内部地址。

十、Tool Result数据安全

Tool 返回完整 Entity:

json
{
  "status": "SHIPPED",
  "phone": "13812345678",
  "address": "...",
  "paymentToken": "...",
  "internalCost": "83.60"
}

后端按场景执行字段投影:

json
{
  "status": "SHIPPED",
  "trackingNo": "YT123"
}

步骤:

text
重新确认资源属于当前用户范围
→ 加载Purpose字段策略
→ Drop非必要字段
→ Mask/HMAC/泛化必要敏感字段
→ 限制条数、时间范围和文本长度
→ 删除内部异常栈与Header
→ 标记内容为不可信数据
→ 发送模型

Tool Result 中的工单备注、网页和数据库自由文本可能包含 Prompt Injection,不能因为来源是内部服务就当成高优先级指令。

十一、第三方Provider评估

调用外部 Provider 前要形成可审计决策,而不是只看“企业版”标签。

11.1 数据处理问题清单

  • 请求和响应是否保存,保存多久?
  • 默认或可选是否用于训练、评估或人工审核?
  • 数据处理区域和备份区域在哪里?
  • 有哪些子处理者?
  • 数据是否跨区域传输?
  • 传输和静态加密如何做?
  • 租户隔离和访问审计怎样实现?
  • 删除、导出和事件通知能力是什么?
  • Abuse Monitoring 是否保留内容?
  • 合同、DPA、SLA 和事件响应责任如何约定?

具体结论必须基于当前合同和 Provider 文档,不能长期假设“API 数据一定不训练”。

11.2 Provider路由需要数据驻留约束

模型路由不仅看能力、延迟和价格,还要看:

text
dataClassification
allowedProviders
allowedRegions
retentionMode
localOnly

高敏请求若没有合规可用模型,应拒绝、脱敏、转本地或人工,不能自动降级到数据边界更弱的 Provider。

11.3 本地模型也不自动安全

本地部署降低数据出组织边界风险,但仍有:

  • 内部越权。
  • 模型服务公网暴露。
  • Prompt 明文日志。
  • GPU 内存残留和临时文件。
  • Tool 过度返回。
  • 运维账号无审计。
  • 备份和评估集扩散。

十二、日志、Trace和指标怎样记录

12.1 推荐默认记录

text
requestId、scene、tenantIdToken
principalIdToken、roles摘要
promptVersion、modelRoute、providerRegion
inputTokenCount、outputTokenCount
retrievedChunkIds、indexVersion
toolCallId、toolName、resultCode
policyVersion、classificationSummary
latency、status、errorType

身份 Token 可使用受控 HMAC,使安全团队能关联同一主体而普通日志读者看不到原值。

12.2 默认不要记录

  • 完整用户输入。
  • 完整 Prompt。
  • RAG 原文。
  • 完整 Tool Result。
  • 模型输出明文。
  • Authorization Header、Cookie、API Key、密码。

12.3 受控调试样本

确需内容排障时:

  1. 明确工单和目的。
  2. 只采样必要请求。
  3. 先自动和人工复核脱敏。
  4. 单独加密存储。
  5. 最小人员访问。
  6. 短保留并自动删除。
  7. 记录访问审计。

指标标签不能放 patientId、手机号、完整 Query 等高基数字段,否则既泄露数据又拖垮指标系统。

十三、缓存为什么是高风险副本

AI 常见缓存:

  • Prompt/响应缓存。
  • Semantic Cache。
  • Embedding Cache。
  • RAG 结果缓存。
  • Tool 结果缓存。
  • Prefix/KV Cache。

13.1 Cache Key不能只有问题文本

至少考虑:

text
tenantIdToken
ACL或dataScopeHash
scene
promptVersion
modelVersion
knowledgeIndexVersion
embeddingRevision
toolDataVersion
locale

否则 A 租户有权限的回答可能返回给 B 租户。

13.2 Value也要最小化

缓存完整 Prompt 或 Tool Entity 会形成长期敏感副本。优先缓存授权后的最小结果或稳定 ID,并设置 TTL、加密、容量和删除索引。

13.3 删除怎样命中缓存

只按 Query Hash 存缓存,很难按 dataSubjectId 或 docId 找出相关条目。可维护反向索引:

text
subjectToken/docId → cacheKeys

或者使用短 TTL 和版本失效降低残留,但短 TTL 不能替代需要明确删除的场景。

十四、评估集和人工标注数据安全

线上失败样本常包含最真实也最敏感的数据。

14.1 入评估集前

  • 确认用途和授权。
  • 识别字段与自由文本实体。
  • 用合成值替换手机号、身份证、订单号和患者标识。
  • 保留任务难度,不保留真实身份。
  • 文档片段按 ACL 和版权保存。
  • 分离原始受控样本与可共享脱敏样本。

14.2 标注平台

  • 标注人按项目和数据级别授权。
  • 禁止本地下载、复制和截图方向的控制,具体结合终端治理。
  • 水印、访问日志和异常下载告警。
  • 标注说明不要暴露额外内部信息。
  • 项目结束后撤权和删除导出。

14.3 LLM-as-Judge

把评估样本发送给另一个模型等于新增 Provider 和数据副本。Judge 也要经过同样的驻留、最小化和合同评估,不能因为它只“打分”就忽略数据安全。

十五、数据保留策略怎样设计

每类存储明确:

text
purpose
classification
retentionPeriod
retentionStart
deletionMethod
legalHoldPolicy
backupExpiry
owner
evidence

不同对象可以不同:

对象保留方向示例
会话原文最短业务必要期,可由用户删除
脱敏运行日志运维和安全审计期
高敏调试样本极短、工单绑定
评估集版本化并定期复核用途
不可变安全审计按法规和组织政策保留,内容最小化
备份按备份周期自然到期并防止恢复后复活

保留时长不能由文档凭空给统一数字,应由业务、法律和风险共同确定。

十六、删除请求为什么是分布式工作流

一个数据主体请求删除时,可能涉及:

text
业务主库
对象存储原文
RAG Chunk与向量
关键词索引
会话与Memory
Tool结果缓存
响应缓存
日志与Trace
评估集与标注导出
Provider留存
备份与灾备
mermaid
flowchart TD
    A["接收删除请求并验证主体"] --> B["生成deletionId与subjectToken"]
    B --> C["查询数据清单和Lineage"]
    C --> D["向各可变存储发送删除任务"]
    D --> E["立即禁止检索和使用"]
    E --> F["各存储返回删除证据"]
    F --> G["Provider删除或按合同确认"]
    G --> H["备份登记到期不再恢复"]
    H --> I["对账所有Required Target"]
    I --> J{"是否全部完成或有合法例外"}
    J -- "否" --> K["重试、告警或人工处理"]
    J -- "是" --> L["关闭请求并保存最小审计证据"]

16.1 先阻止继续使用

物理删除可能需要 Compaction 或备份到期。应先将主体/文档标为 revoked,所有检索、缓存和评估任务立即排除,再异步完成物理清理。

16.2 不可变日志和法定留存

有些安全审计或法律记录不能立即删除。设计时就应避免写入不必要原文,保存 HMAC Token、事件类型和最小证据。删除工作流对例外记录原因、范围、到期和审批,不能虚假声明已经物理擦除。

16.3 备份

离线备份通常不能逐条修改,否则破坏完整性。常见方向是:

  • 在线系统立即删除/撤销。
  • 备份按既定周期到期销毁。
  • 恢复旧备份时重新应用删除清单,防止数据复活。
  • 记录 backupExpiry 和恢复 Runbook。

十七、可运行Demo:Purpose驱动字段策略

下面仅使用 Python 标准库,演示相同业务对象在“外部模型上下文”和“运行日志”两个目的地下使用不同字段策略:

  • 外部模型只保留发货状态所需字段。
  • 手机号只在日志中掩码。
  • patientId 在日志中用 HMAC Token 稳定关联。
  • paymentToken、地址和内部成本始终删除。
  • 未登记字段默认删除。
python
from __future__ import annotations

import hashlib
import hmac
import re
from enum import Enum
from typing import Any


class Action(str, Enum):
    KEEP = "KEEP"
    MASK_PHONE = "MASK_PHONE"
    HMAC_TOKEN = "HMAC_TOKEN"
    DROP = "DROP"


POLICIES: dict[str, dict[str, Action]] = {
    "external_model_shipping_answer": {
        "orderNo": Action.KEEP,
        "status": Action.KEEP,
        "trackingNo": Action.KEEP,
        "phone": Action.DROP,
        "patientId": Action.DROP,
        "address": Action.DROP,
        "internalCost": Action.DROP,
        "paymentToken": Action.DROP,
    },
    "operations_log": {
        "orderNo": Action.HMAC_TOKEN,
        "status": Action.KEEP,
        "trackingNo": Action.DROP,
        "phone": Action.MASK_PHONE,
        "patientId": Action.HMAC_TOKEN,
        "address": Action.DROP,
        "internalCost": Action.DROP,
        "paymentToken": Action.DROP,
    },
}


def mask_phone(value: str) -> str:
    return re.sub(r"^(1[3-9]\d)\d{4}(\d{4})$", r"\1****\2", value)


def stable_hmac_token(value: str, secret: bytes) -> str:
    normalized = value.strip().lower()
    digest = hmac.new(secret, normalized.encode("utf-8"), hashlib.sha256).hexdigest()
    return f"hmac256:{digest}"


def transform(
    record: dict[str, Any], purpose: str, secret: bytes
) -> dict[str, Any]:
    policy = POLICIES.get(purpose)
    if policy is None:
        raise ValueError("未登记Purpose,默认拒绝处理")

    result: dict[str, Any] = {}
    for field, value in record.items():
        action = policy.get(field, Action.DROP)
        if action is Action.KEEP:
            result[field] = value
        elif action is Action.MASK_PHONE:
            result[field] = mask_phone(str(value))
        elif action is Action.HMAC_TOKEN:
            result[field] = stable_hmac_token(str(value), secret)
        elif action is Action.DROP:
            continue
    return result


if __name__ == "__main__":
    secret = b"demo-only-use-kms-in-production"
    order = {
        "orderNo": "SO-1001",
        "status": "SHIPPED",
        "trackingNo": "YT123",
        "phone": "13812345678",
        "patientId": "P-9001",
        "address": "北京市朝阳区某小区",
        "internalCost": "83.60",
        "paymentToken": "pay_secret",
        "unknownDebugField": "must-drop-by-default",
    }

    model_context = transform(order, "external_model_shipping_answer", secret)
    log_context = transform(order, "operations_log", secret)

    assert model_context == {
        "orderNo": "SO-1001",
        "status": "SHIPPED",
        "trackingNo": "YT123",
    }
    assert log_context["phone"] == "138****5678"
    assert log_context["patientId"].startswith("hmac256:")
    assert "paymentToken" not in model_context and "paymentToken" not in log_context
    assert "unknownDebugField" not in model_context and "unknownDebugField" not in log_context

    print("external model:", model_context)
    print("operations log:", log_context)

Demo Secret 仅为教学,生产使用 KMS/Secret,并为 HMAC Key 记录版本。密钥轮换会改变 Token,需要双读迁移或明确旧新关联策略。

十八、可运行Demo:删除传播状态机

下面模拟删除请求必须等待所有 Required Target 确认;备份不能立即逐条擦除时,状态为 EXPIRY_SCHEDULED,并记录到期时间;任何 Target 失败都不能把请求标成完成。

python
from dataclasses import dataclass, field
from enum import Enum


class TargetStatus(str, Enum):
    PENDING = "PENDING"
    DELETED = "DELETED"
    REVOKED = "REVOKED"
    EXPIRY_SCHEDULED = "EXPIRY_SCHEDULED"
    FAILED = "FAILED"


@dataclass
class Target:
    name: str
    status: TargetStatus = TargetStatus.PENDING
    evidence: str | None = None


@dataclass
class DeletionRequest:
    deletion_id: str
    subject_token: str
    targets: dict[str, Target] = field(default_factory=dict)

    def complete(self) -> bool:
        acceptable = {
            TargetStatus.DELETED,
            TargetStatus.REVOKED,
            TargetStatus.EXPIRY_SCHEDULED,
        }
        return bool(self.targets) and all(
            target.status in acceptable and target.evidence
            for target in self.targets.values()
        )


if __name__ == "__main__":
    request = DeletionRequest(
        deletion_id="del-20260716-001",
        subject_token="hmac256:subject-demo",
        targets={
            name: Target(name)
            for name in ["business_db", "rag_index", "cache", "evaluation_set", "backup"]
        },
    )

    request.targets["business_db"] = Target(
        "business_db", TargetStatus.DELETED, "db-audit-101"
    )
    request.targets["rag_index"] = Target(
        "rag_index", TargetStatus.REVOKED, "index-tombstone-202"
    )
    request.targets["cache"] = Target(
        "cache", TargetStatus.DELETED, "cache-purge-303"
    )
    request.targets["evaluation_set"] = Target(
        "evaluation_set", TargetStatus.FAILED, "eval-worker-timeout"
    )
    request.targets["backup"] = Target(
        "backup",
        TargetStatus.EXPIRY_SCHEDULED,
        "expires-2026-08-15-and-reapply-ledger-on-restore",
    )

    assert request.complete() is False
    request.targets["evaluation_set"] = Target(
        "evaluation_set", TargetStatus.DELETED, "eval-delete-404"
    )
    assert request.complete() is True

    print("deletion complete:", request.complete())
    for target in request.targets.values():
        print(target.name, target.status.value, target.evidence)

真实状态需要持久化、版本控制、重试队列、Deadline、法定例外审批和定期对账;不能只存在单进程内存。

十九、商业场景:医疗数据资产AI助手

19.1 场景

用户询问字段定义、采集异常和资产摘要。系统拥有医疗数据标准、接口文档、采集日志和部分患者标识。

19.2 安全链

mermaid
flowchart TD
    A["用户登录"] --> B["服务端获得医院、部门、角色和密级"]
    B --> C["识别field_definition或incident_analysis Purpose"]
    C --> D["RAG按tenant与ACL召回"]
    D --> E["Tool按数据范围查询最小日志字段"]
    E --> F["字段策略Drop患者值、连接密钥和内部地址"]
    F --> G{"分类是否允许目标Provider"}
    G -- "否" --> H["本地模型、进一步脱敏或人工"]
    G -- "是" --> I["发送最小Prompt"]
    I --> J["输出实体检测、引用和权限复核"]
    J --> K["返回字段含义与证据,不返回真实患者样例"]

19.3 字段解释和真实值必须分开

允许回答:

text
patient_id是患者标识字段,用于关联患者业务记录,属于敏感字段。

不应为了“举例”检索和输出真实身份证或患者编号。教学示例使用明确的合成数据。

19.4 采集日志

日志查询工具只返回:

text
assetId、time、reasonCode、evidenceId、retryable

删除连接串、用户名、密码、患者 ID、原始 SQL 和完整异常栈。需要深度排障时由受控运维系统查看,不通过普通聊天 Prompt 扩散。

二十、数据安全事件响应Runbook

20.1 发现模型输出了越权或敏感数据

  1. 立即关闭受影响场景、Provider 路由或切安全降级。
  2. 保存最小取证信息:requestId、时间、版本、主体 Token,避免再次复制明文。
  3. 确认数据来源:用户历史、RAG、Tool、缓存、Few-shot、模型参数或日志回灌。
  4. 检查谁接收了数据:终端用户、Provider、日志、评估流水线、人工标注。
  5. 阻断继续访问,清理缓存和候选索引,修复 ACL/字段策略。
  6. 按组织事件响应和通知流程评估影响范围。
  7. 加入确定性权限测试和脱敏回归样本。

20.2 日志中发现API Key或支付Token

  1. 先吊销并轮换密钥,不能只删日志。
  2. 确认日志索引、归档、备份、转发和告警系统中的副本。
  3. 限制日志访问并清理可变副本。
  4. 检查密钥是否被使用和是否存在异常调用。
  5. 修复源头字段策略、日志拦截和 Secret 扫描。

20.3 删除请求长期卡住

  • 查看 deletionId 的各 Target 状态和最后错误。
  • 检查稳定 subjectToken/docId 是否能定位所有副本。
  • 检查评估集、标注导出和缓存是否缺反向索引。
  • 对不可变日志确认最小化和合法保留例外。
  • 对备份确认到期日期和恢复重放删除清单。
  • 超出删除 SLO 时告警和人工升级,不能自动标完成。

20.4 外部Provider策略发生变化

  1. 暂停受影响分类的数据路由。
  2. 对比留存、训练、区域、子处理者和删除条款。
  3. 更新 Provider Allowlist 和 Policy Version。
  4. 使用安全评估集验证新路由。
  5. 必要时迁移到其他区域、本地模型或人工流程。

20.5 缓存出现跨租户回答

这是严重越权事故:

  • 立即禁用相关缓存。
  • 检查 Key 是否包含 tenant、ACL、Prompt、模型和索引版本。
  • 根据缓存访问日志评估哪些主体收到错误结果。
  • 清空污染缓存并轮换命名空间。
  • 补 A/B 租户相同 Query 的隔离测试。

二十一、常见误区与后果

误区正确理解
输出打星就安全数据可能已进入Provider、日志和缓存
删除姓名就是匿名化准标识符组合仍可重新识别
手机号SHA-256不可破解低熵格式可被枚举,应最小化或受控HMAC
加密后可以随便发送接收方计算时会看到明文,先判断是否需要
向量不是原文所以不敏感向量可被探测且关联Metadata,仍需治理
本地模型天然安全内部越权、日志、备份和服务暴露仍存在
Cache Key用Query即可会跨租户、跨权限和跨版本串数据
评估集只是测试数据常来自真实失败样本,是长期敏感副本
删除主库记录就完成RAG、缓存、Provider、评估集和备份仍存在
不可变日志可以记录完整Prompt应从源头最小化,只保留必要审计证据

二十二、面试标准回答

22.1 AI数据安全怎样做

先建立用户输入、RAG、Tool、Prompt、Provider、日志、缓存和评估集的数据流清单;按字段和自由文本分类分级,基于 Purpose 最小化数据;RAG 在召回前做租户和 ACL,Tool Result 做字段投影和脱敏;Provider 路由考虑留存、训练使用、区域和子处理者;所有副本设置加密、访问审计、保留和删除传播。

22.2 脱敏、假名化、哈希和加密有什么区别

掩码用于展示部分信息;假名化用受控 Token 替换身份,保留可关联性且可能恢复;普通哈希对低熵手机号容易被枚举,稳定关联更适合受控 HMAC;加密持有密钥可以恢复,用于传输和存储保护。它们都不能替代数据最小化,假名化也不自动等于匿名化。

22.3 为什么不能记录完整Prompt

完整 Prompt 聚合用户输入、历史、RAG 片段、Tool Result 和系统规则,日志又会被索引、转发、备份和更多人员访问,形成新的高风险副本。生产默认记录 requestId、版本、Chunk ID、Token、耗时和脱敏/HMAC主体标识;内容调试要工单授权、采样、脱敏、加密和短期自动删除。

22.4 第三方模型数据安全要评估什么

评估请求和响应的留存时间、是否用于训练或人工审核、处理与备份区域、跨境和子处理者、加密与租户隔离、删除导出能力、事件通知和合同责任。路由还要按数据级别配置允许 Provider/区域;高敏数据不能因主模型故障自动降级到未批准 Provider。

22.5 为什么删除请求是分布式工作流

同一数据可能存在业务库、RAG Chunk与向量、关键词索引、会话、缓存、日志、评估集、Provider和备份。删除请求要用稳定主体 Token 枚举 Target,先撤销检索和使用,再异步删除并收集证据;备份按周期到期且恢复时重放删除清单,法定留存记录例外,所有 Required Target 完成后才能关闭。

22.6 AI缓存为什么必须带权限和版本

同一个 Query 在不同租户、dataScope、Prompt、模型和知识库版本下结果不同。Key 只有问题文本会把 A 用户有权数据返回给 B 用户,也会返回过期索引结果。Key 至少包含租户 Token、ACL Hash、场景、Prompt、模型、索引和 Embedding Revision,Value 也只保存最小必要数据。

更多简洁回答见 AI应用工程化面试题,完整原理以本页为准。

二十三、关联知识点

二十四、学习验收清单

  • [ ] 能画出AI数据的全部常见副本和处理者。
  • [ ] 能为字段定义级别、Purpose、目的地和保留策略。
  • [ ] 能区分掩码、泛化、假名化、匿名化、哈希、HMAC和加密。
  • [ ] 能解释为什么低熵PII不能只做普通哈希。
  • [ ] 能实现默认Drop的字段最小化策略。
  • [ ] 能解释RAG向量为什么不能自动视为匿名数据。
  • [ ] 能设计Provider Allowlist、Region和Retention路由。
  • [ ] 能设计日志内容、受控调试和指标标签边界。
  • [ ] 能设计租户与ACL隔离的缓存Key和删除反向索引。
  • [ ] 能治理评估集、标注平台和LLM-as-Judge的数据副本。
  • [ ] 能画出删除请求的Target状态机和备份到期处理。
  • [ ] 能说明法定留存例外为何不能虚假标记为已物理删除。
  • [ ] 能根据requestId和subjectToken完成泄露影响面排查。

达到这些标准后,才算理解 AI 数据安全,而不是只会说“敏感信息要脱敏”。