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 / Firebase | RLS 必开 |
| 云 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 个真实的人——每一行数据后面是一个用户。处理事故的方式如果只看”技术影响 / 法律风险”,会失去客户的信任。
实操:
- 快速通知——按 隐私保护 法规要求时间内通知用户(澳洲 Privacy Act 是知情后 72 小时内)
- 诚实说明——别用”可能受影响”这种含糊话术,说清楚是什么数据、什么范围
- 给补救动作——重置密码、免费监控信用、必要时赔偿
- 公开 post-mortem——技术圈会因为你诚实而尊重你;含糊推诿会被骂上 Hacker News
4 条铁律的概念地图
每条铁律对应到站内已有的 concept:
| 铁律 | 核心 concept | 协议 / 工具 concept |
|---|---|---|
| 1. 静态加密 | data-at-rest · encryption | symmetric-encryption · asymmetric-encryption · hash-function · cryptographic-key · salting |
| 2. 传输加密 | data-in-transit · encryption | https · ssh · sftp |
| 3. 最小访问权限 | principle-of-least-privilege · access-controls | linux-permissions · authentication · authorization · mfa |
| 4. 审计访问记录 | security-audit · log | siem · splunk-enterprise · network-log-analysis |
AI 给你写 PII 处理代码,3 步审完
读到任何 AI 写的处理用户敏感数据的代码,默念:
- 数据存的时候是密文吗? ——
password字段是 bcrypt 后的、id_number是加密的、备份是 encrypted? - 数据传的时候是密文吗? —— 用了
https://?数据库 connection 启了 SSL? - 访问被记录了吗? —— 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 写代码时不做。