核心问题

系统是否真的需要这些数据?

隐私不是“不要泄露数据”这么简单。

更根本的问题是:

不该收集的数据,最好一开始就不要进入系统。

数据一旦被收集,就会产生责任:

  • 谁能看?
  • 存多久?
  • 怎么删除?
  • 是否会被导出?
  • 是否会出现在日志里?
  • 是否会进入分析系统?
  • 是否会被第三方处理?
  • 泄露时影响多大?

所以隐私工程的第一原则是数据最小化:

只收集完成明确目的所必需的数据。

数据不是免费资产

很多团队会把数据当成资产:

先收着,以后可能有用。

这句话非常危险。

因为每一份数据也是负债:

  • 存储成本
  • 合规成本
  • 安全成本
  • 访问控制成本
  • 删除成本
  • 泄露风险
  • 用户信任成本

尤其是个人数据。

如果你收集了用户生日、身份证、位置、学习记录、支付记录、聊天内容,就必须承担保护这些数据的责任。

核心句:

不必要的数据不是资产,是风险。

PII:个人可识别信息

PII 是 Personally Identifiable Information,个人可识别信息。

常见 PII:

  • 姓名
  • 邮箱
  • 手机号
  • 身份证号
  • 地址
  • IP 地址
  • 支付信息
  • 精确位置
  • 头像
  • 设备标识

还有一些数据单独看不一定能识别个人,但组合起来可以:

城市 + 公司 + 职位 + 学习记录

所以判断 PII 不要只看单个字段,而要问:

这些数据组合后能不能指向一个具体的人?

收集前先问目的

每新增一个字段,先问:

  1. 我们为什么需要它?
  2. 它服务哪个用户功能或法律义务?
  3. 没有它能不能完成核心流程?
  4. 是否可以用更粗粒度的数据代替?
  5. 是否可以只临时使用,不持久化?
  6. 谁会访问它?
  7. 多久后应该删除?

例如课程平台想收集生日。

可能理由:

为了个性化推荐。

继续追问:

  • 推荐真的需要完整生日吗?
  • 年龄段是否足够?
  • 是否可以由用户自愿填写?
  • 是否可以不存原始生日,只存 age bracket?

更小的数据通常更安全:

birthDate -> ageRange
preciseLocation -> countryOrRegion
fullName -> displayName
rawEventPayload -> selectedFields

日志里的隐私

日志是隐私泄露高发区。

坏日志:

logger.info("payment_request", {
  email,
  phone,
  cardNumber,
  billingAddress,
  rawRequestBody,
})

问题是日志经常被更多系统读取:

  • 日志平台
  • 监控系统
  • 第三方 observability 服务
  • 开发人员
  • 客服工具
  • 离线分析

一旦 PII 进了日志,删除和控制会变得非常难。

更好:

logger.info("payment_request_created", {
  accountId,
  paymentId,
  amount,
  currency,
  requestId,
})

必要时脱敏:

logger.info("login_attempt", {
  emailHash,
  phoneLast4,
  requestId,
  result,
})

原则:

日志应该记录排查所需证据,不记录不必要的私人信息。

数据保留策略

隐私不只是收集,也包括保留。

一个系统应该回答:

数据什么时候应该被删除?

例如:

数据保留策略
登录 session过期后删除
验证码几分钟后删除
原始 webhook payload保留有限天数
审计日志按合规要求保留
支付记录按财务和法律要求保留
临时导出文件几小时或几天后删除

没有保留策略的数据,会自然变成永久数据。

核心句:

如果没有删除时间,数据会默认永生。

删除权和可删除性

很多系统说支持删除用户,但实际做不到。

因为用户数据散落在:

  • 主数据库
  • 日志
  • 搜索索引
  • 缓存
  • 分析仓库
  • 邮件系统
  • 第三方服务
  • 备份

所以设计数据时,要考虑:

如果用户要求删除,我们能删除到什么程度?

删除通常分几类:

1. 软删除

deletedAt: Date

适合业务需要保留历史关系的对象。

2. 匿名化

保留行为统计,但移除可识别身份。

accountId -> anonymousUserId
email -> null
name -> "Deleted User"

3. 硬删除

彻底删除数据。

适合临时数据、验证码、草稿、非合规必需数据。

4. 法律保留

有些数据因为财务、税务、风控、审计要求不能立即删除。

这时要清楚告知范围,并限制访问。

访问审计

敏感数据不仅要保护写入,也要保护读取。

例如后台查看用户个人信息,应留下审计:

type DataAccessAudit = {
  actorId: string
  dataSubjectId: string
  dataType: "profile" | "payment" | "learning_history"
  purpose: string
  occurredAt: Date
  requestId: string
}

尤其是:

  • 查看支付信息
  • 导出用户列表
  • 查看学习记录
  • 查看私密内容
  • 客服查询用户账号

原则:

敏感数据的读取也应该被看见。

数据脱敏和分级

不是所有数据风险一样。

可以把数据分级:

Public: 公开课程标题、公开讲师简介
Internal: 账号 ID、课程进度统计
Sensitive: 邮箱、手机号、学习记录、支付记录
Highly Sensitive: 身份证、精确地址、支付卡信息

不同级别对应不同处理:

  • 是否可进日志
  • 是否可导出
  • 是否需要脱敏
  • 是否需要审批
  • 是否需要加密
  • 是否需要访问审计

例如客服后台可以默认显示:

le***@example.com
phone: ***1234

只有在明确业务需要时,才允许查看完整值,并留下审计。

第三方共享

一旦数据发给第三方,你就失去一部分控制。

例如:

  • 支付平台
  • 邮件服务
  • 短信服务
  • 分析工具
  • 客服系统
  • 错误监控
  • AI 服务

发送前要问:

  1. 第三方是否真的需要这个字段?
  2. 是否可以发内部 ID 而不是 PII?
  3. 是否可以脱敏或哈希?
  4. 第三方保留多久?
  5. 用户删除时,第三方如何删除?
  6. 是否会跨境传输?
  7. 是否进入第三方训练或分析?

原则:

数据离开系统边界前,要重新证明必要性。

隐私默认值

好的系统默认保护用户。

例如:

  • 默认不公开个人资料
  • 默认不展示学习记录
  • 默认不订阅营销邮件
  • 默认不允许被搜索
  • 默认不共享给第三方
  • 默认不把敏感字段写入日志

不要把隐私保护变成用户必须自己找到的开关。

核心句:

隐私应该是默认值,不是高级设置。

隐私检查清单

新增一个字段或数据流时问:

  1. 这个数据是否必要?
  2. 它服务哪个明确目的?
  3. 是否可以用更少、更粗、更短期的数据替代?
  4. 是否是 PII 或敏感数据?
  5. 谁可以读?谁可以写?
  6. 是否会进入日志、缓存、分析、搜索或第三方?
  7. 保留多久?
  8. 如何删除或匿名化?
  9. 是否需要脱敏、加密或访问审计?
  10. 用户是否合理预期我们会这样使用它?

小结

  1. 隐私的第一原则是数据最小化。
  2. 不必要的数据不是资产,是风险。
  3. PII 要看组合识别能力,不只看单个字段。
  4. 日志是隐私泄露高发区。
  5. 没有删除时间的数据会默认永生。
  6. 敏感数据的读取也应该被审计。
  7. 数据离开系统边界前,要重新证明必要性。
  8. 隐私应该是默认值,不是高级设置。