Heather Adkins 是 Google 安全工程副总裁——她管着全球 Google 安全工程团队。她给 PII 处理只立了 4 条铁律,朴素到看一眼就过。但你让 AI 替你写处理用户数据的代码时,每一条都是 vibe-coder 翻车现场

如果你在澳洲做 SaaS,先看 PII vs SPII vs 澳洲 Privacy Act —— 美国课程讲 PII / SPII,澳洲法律对照物是 Privacy Act 1988,数据归类不完全一样


4 条铁律一句话总览

#铁律防什么
1静态加密(at rest)数据库 / 硬盘被偷或泄漏时,攻击者拿到的只是密文
2传输加密(in transit,TLS / SSL)中间人嗅探时,看到的也只是密文
3最小访问权限极敏感数据应该几乎没人有权限 —— 包括你的同事、包括你的 AI
4审计访问记录 + 定期 review谁、什么时候、为什么访问了这条数据,有 log,且有人看 log

下面挨条讲。


1. 静态加密 — 数据在硬盘上时也要是密文

加密 不只是”传输时”的事。数据库文件、磁盘备份、S3 对象、本地缓存——只要数据停在某个地方,它就是 at rest。Heather 的要求:只要能加密就加密

防什么

场景没加密 = 出事
服务器硬盘被偷(机房入侵、二手转售前没擦)攻击者直接挂载读取
数据库 dump 泄漏到 GitHub / 公开 S3全表明文裸奔
备份没加密放在 NAS / 网盘网盘账号被破 = 全数据流出

AI 容易写错的地方

# ❌ AI 给你写: 密码明文存数据库
db.users.insert({"email": email, "password": password})
 
# ✅ 正确做法: 单向哈希 + [[salting|salt]]
import bcrypt
hashed = bcrypt.hashpw(password.encode(), bcrypt.gensalt())
db.users.insert({"email": email, "password": hashed})
# ❌ AI 给你写: 把用户身份证号原样存进数据库
db.users.update(user_id, {"id_number": "12345678901"})
 
# ✅ 正确做法: 应用层加密后再存
from cryptography.fernet import Fernet
f = Fernet(KEY_FROM_KMS)  # 密钥从 [[cryptographic-key|KMS]] 拿,别硬编码
encrypted = f.encrypt("12345678901".encode())
db.users.update(user_id, {"id_number": encrypted})

实操速查

平台静态加密怎么开
AWS RDS / S3默认建议勾选”Encryption at rest”(用 AWS KMS 管 key)
Supabase / Vercel Postgres默认开启,自动管
自建 PostgreSQL on VPS启用 pgcrypto 扩展 + 表层 / 列层加密
密码字段永远 bcrypt / argon2,不要自己写哈希

⚠️ 加密 ≠ 哈希。密码用[hash-function|哈希],其他敏感数据用[symmetric-encryption|对称加密]


2. 传输加密 — 数据在网上跑时也要是密文

任何数据离开你的服务器在网上跑的瞬间,中间会经过 N 个路由 / 网关 / ISP 节点——每一跳都可能被 嗅探。Heather 的要求:用 TLS / SSL 加密(实操中 SSL 已经废了,现代叫 TLS,但人们还混着说)。

防什么

场景没加密 = 出事
用户在咖啡店 Wi-Fi 登录你网站同 Wi-Fi 的人抓包能看到明文密码
前端调你的 API 用 http://任何 中间人能改请求和返回
内部服务之间用 plaintext gRPC公司网络被渗透后,横向流量裸奔

AI 容易写错的地方

// ❌ AI 给你写: 用 http:// 调 API
fetch('http://api.example.com/users')
 
// ✅ 正确: 强制 https://
fetch('https://api.example.com/users')
# ❌ AI 给你写: 关掉证书验证 (因为它自己 demo 时报错就这样改)
requests.get('https://api.example.com', verify=False)
 
# ✅ 正确: 不要关 verify, 看到这个立即改回 True
requests.get('https://api.example.com', verify=True)
# ❌ AI 给你的 nginx 配置: 只监听 80, 没跳转 443
server { listen 80; ... }
 
# ✅ 正确: 80 自动 301 跳 443
server {
    listen 80;
    return 301 https://$host$request_uri;
}
server {
    listen 443 ssl;
    # 加 HSTS 防降级攻击
    add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
    ...
}

实操速查

工具怎么用
网站证书Let’s Encrypt + certbot 免费自动续期
数据库连接Postgres / MySQL 都支持 SSL connection,生产必开
API 客户端永远不关 verify=True
浏览器侧HSTS header 让浏览器记住”只用 HTTPS”,防降级

⚠️ HTTPS 加密的是 body,不加密 header。攻击者还是知道你访问了哪个 IP / 哪个 端口——只是不知道内容。详见 IP 4 层和数据包


3. 最小访问权限 — 极敏感数据,几乎没人应该有权限

Heather 原话:“It should be almost no one if it’s very sensitive.”

这条比前两条更难——前两条是技术问题,这条是组织 + 设计问题。AI 替你写代码时,默认会给最大权限(因为这样不会报错),你必须主动收紧。

防什么

场景没控权 = 出事
应用用 root db user 连数据库应用被攻破 = 整库都丢
全员能查用户表一个员工电脑中毒 = 全用户数据泄漏
AI assistant 给的 service key 写在前端公开仓库 = 任何人读你数据库

AI 容易写错的地方

# ❌ AI 给你写: 应用直接用 postgres 超级用户连接
DATABASE_URL = "postgresql://postgres:password@host/db"
 
# ✅ 正确: 给应用单独一个用户,只赋予需要的权限
# 在数据库里:
# CREATE USER app_user WITH PASSWORD '...';
# GRANT SELECT, INSERT, UPDATE ON users TO app_user;
# (不给 DELETE, 不给 DROP, 不给其他表)
DATABASE_URL = "postgresql://app_user:password@host/db"
-- ❌ AI 给你建表: 没启 [[sql-filtering|RLS]]
CREATE TABLE users (id uuid, email text, ssn text);
 
-- ✅ 正确: 启 RLS + 写明确策略
CREATE TABLE users (id uuid, email text, ssn text);
ALTER TABLE users ENABLE ROW LEVEL SECURITY;
CREATE POLICY "users read own row" ON users FOR SELECT USING (auth.uid() = id);
-- 即便 anon key 泄漏, 也只能读到自己那一行
# ❌ AI 给你写 IAM 策略: 全权限 (因为图省事)
Effect: Allow
Action: "*"
Resource: "*"
 
# ✅ 正确: 只赋需要的
Effect: Allow
Action: ["s3:GetObject", "s3:PutObject"]
Resource: "arn:aws:s3:::mybucket/uploads/*"

实操速查

最小权限怎么做
数据库应用单独 user + 列级 / 行级 权限
Supabase / FirebaseRLS 必开
云 IAM永远从”拒绝一切”开始加权限
Linux 文件chmod 600 给 SSH key、配置文件
API key不同环境(dev/prod) 不同 key,前端绝不放 service key

⚠️ AI 默认给最大权限——它没有”安全审计员”上下文,你必须主动 review。看到 AI 写 chmod 777 / * 权限 / 全表无 RLS,立即让它收紧到最小够用集


4. 审计访问记录 — 有 log,而且有人看 log

Heather 原话:“There should be a record of that access, who accessed it, and a justification as to why. And you should have a program to look at the audit records.”

注意关键词:“a program to look at”——光记 log 没用,要有人 / 系统定期 review

防什么

场景没审计 = 出事
离职员工 4 个月后拖库没人发现,数据已经在暗网卖
应用账号被盗,攻击者每天慢慢拖数据没异常检测,半年才发现
出事后客户问”我的数据被谁访问过”答不上来 = 失去信任 + 法律暴露

AI 容易写错的地方

# ❌ AI 给你写: SELECT 时不打 log
user = db.users.find_one({"email": email})
 
# ✅ 正确: 敏感数据访问要打审计 log
import logging
audit_logger = logging.getLogger("audit")
user = db.users.find_one({"email": email})
audit_logger.info({
    "event": "pii_access",
    "table": "users",
    "actor": current_user_id,
    "target": user["id"],
    "reason": request.headers.get("X-Access-Reason"),  # 强制要求传原因
    "timestamp": datetime.utcnow().isoformat()
})
-- ❌ Supabase / Postgres 默认: 没开 audit log
-- 不知道谁查了什么
 
-- ✅ 启 pgaudit 扩展
CREATE EXTENSION pgaudit;
ALTER SYSTEM SET pgaudit.log = 'read, write';
-- 之后所有读 / 写都进 audit log

实操速查

审计怎么做
应用层所有敏感数据访问打 audit log,单独一条日志流,不和业务 log 混
数据库Postgres: pgaudit 扩展;MySQL: General Query Log;Supabase: audit 表
云平台AWS CloudTrail / GCP Audit Logs(默认开,要去看)
工具栈SIEM 把多源 log 聚合,异常告警

最关键的一步是定期 review——可以是每周看一次 dashboard,也可以是异常告警自动触发(同一账号 10 分钟内查 1000 行 = 报警)。记 log 但没人看 = 等于没记


5. 出事时的态度 — Heather 没说但最重要的一条

Heather 视频末尾:“Remember that’s someone’s personal information and your response wants to be grounded in that reality.”

PII 泄漏不是一条 bug,是 N 个真实的人——每一行数据后面是一个用户。处理事故的方式如果只看”技术影响 / 法律风险”,会失去客户的信任

实操:

  1. 快速通知——按 隐私保护 法规要求时间内通知用户(澳洲 Privacy Act 是知情后 72 小时内)
  2. 诚实说明——别用”可能受影响”这种含糊话术,说清楚是什么数据、什么范围
  3. 给补救动作——重置密码、免费监控信用、必要时赔偿
  4. 公开 post-mortem——技术圈会因为你诚实而尊重你;含糊推诿会被骂上 Hacker News

4 条铁律的概念地图

每条铁律对应到站内已有的 concept:


AI 给你写 PII 处理代码,3 步审完

读到任何 AI 写的处理用户敏感数据的代码,默念:

  1. 数据存的时候是密文吗? —— password 字段是 bcrypt 后的、id_number 是加密的、备份是 encrypted?
  2. 数据传的时候是密文吗? —— 用了 https://?数据库 connection 启了 SSL?
  3. 访问被记录了吗? —— SELECT 敏感表打 audit log 了吗?有人会看吗?

3 步过完,你看 AI 写的”用户数据相关代码”就不再凭直觉。


相关阅读

  • PII vs SPII vs 澳洲 Privacy Act —— 在澳洲做 SaaS 法律上对照的是 Privacy Act,数据归类比美国课程更广
  • 云共担责任 —— 这 4 条铁律全都落在”你那一半”(in the cloud),云厂商不会替你做
  • SQL 4 个 slot —— 第 3 条最小权限的落地工具:RLS + 数据库账号最小权限
  • 代理 —— 第 2 条传输加密的延伸:VPN / 反向代理在传输层做了什么

Heather 说话的方式像她在 Google 内部跟工程师对话:朴素、可执行、可考核。 4 条铁律没有一条是新发明——但每一条都有 90% 的 vibe-coder 写代码时不做