BodySense 数据库第 19 课:Database Security、Privacy Erasure 与 Data Lifecycle
结合 BodySense 健康数据场景学习最小权限、PII/secret 边界、日志泄露、删除级联、privacy erasure、审计与数据生命周期。
[!info] related notes
- 课程 MOC:BodySense 数据库工程深化课程 MOC
- 前置:第 18 课
- 项目:BodySense 数据库设计
BodySense 数据库第 19 课:Database Security、Privacy Erasure 与 Data Lifecycle
[!abstract] 本课目标 数据库安全不只是 SQL Injection。对健康类系统,必须知道谁能读什么、数据复制到哪里、删除时哪些派生副本还存在。
从零建立概念:Database Security 不只是 SQL Injection
一提数据库安全,最先想到:
SQL Injection
它当然重要,但生产数据库的攻击面还包括:
credential theft
over-privileged account
network exposure
backup leakage
logs containing sensitive values
IDOR / authorization bugs
misconfigured replica
unsafe migration role
insider access
retention / erasure failure
所以这一课从“数据生命周期”看安全。
Authentication 与 Authorization
Authentication
这个 database client 是谁?
例如:
bodysense_api role
migration role
admin role
monitoring role
Authorization
这个 role 能做什么?
例如:
SELECT
INSERT
UPDATE
DELETE
CREATE TABLE
ALTER TABLE
CREATE EXTENSION
read specific schema
不要因为应用能连接,就让它拥有 superuser。
Least Privilege 从零理解
原则:
一个身份只拥有完成职责所需的最小权限。
例如 Runtime API 正常只需要:
read/write application tables
maybe execute selected functions
不代表它需要:
DROP DATABASE
CREATE ROLE
ALTER SYSTEM
CREATE EXTENSION
把 Migration Role 单独拆出来的价值:
API credential leaked
→ attacker blast radius smaller
Network Boundary
数据库端口不应该默认暴露给整个 Internet。
常见:
private network / VPC
firewall/security group
TLS
allowlisted clients
managed DB network policy
Redis/PostgreSQL 都一样:
Authentication 不是网络暴露的替代品。
Parameterized Query 与 SQL Injection
危险:
sql := "SELECT * FROM users WHERE email='" + input + "'"
用户输入可能改变 SQL 结构。
参数化:
SELECT * FROM users
WHERE email = $1
Driver 把 SQL structure 与 data value 分开。
ORM 正常 query API 也通常参数化,但:
Raw SQL
dynamic ORDER BY / column names
string-built clauses
仍要审查。
SQL Injection 防住了,也不代表 Authorization 正确
例如:
SELECT * FROM assessment_reports
WHERE id = $1
SQL 完全参数化。
但如果 API 没检查:
report.user_id == current_user
攻击者知道别人的 report id 仍可能读取。
这是 IDOR/BOLA,属于 authorization boundary。
数据库访问层需要把:
user-scoped query
tenant boundary
resource ownership
设计清楚。
Sensitive Data Classification
先分类才知道怎么保护。
BodySense 可能涉及:
Credentials
password hash
refresh/token secret
DB password
API key
PII
email
name
IP
device/account identifiers
Health / Body Data
body measurements
symptoms
observations
diagnosis/treatment history
uploads
Derived Data
embedding
projection
cache
analytics
search index
“派生”不等于“不敏感”。
如果 embedding / projection 仍能关联某用户健康信息,它仍属于 data lifecycle 的一部分。
At Rest / In Transit
In Transit
Application ↔ PostgreSQL
应考虑 TLS,尤其跨主机/不可信网络。
At Rest
数据库磁盘、snapshot、backup 可能由:
disk encryption
managed service encryption
encrypted backup
保护。
加密解决的是介质/传输风险的一部分,不替代应用 authorization。
Password 为什么存 Hash,不存可逆 Encryption
Password verification 不需要恢复原文。
所以应使用:
slow password hashing KDF
→ bcrypt / Argon2id 等
数据库泄露时提高破解成本。
不要把 password 当普通 secret:
AES encrypt password
→ application has decryption key
→ attacker gets DB + key may recover all plaintext
Logs 是数据复制系统
每次写:
log.Info("query", payload)
其实是在把数据复制到:
log file
collector
APM
cloud logging
retention archive
developer dashboard
因此 SQL logger 可能扩大敏感数据表面积。
BodySense database.go 在 staging/production 将 GORM logger 默认降低到 Warn,注释明确是为了避免把 consultation/body-state payload 通过 SQL interpolation 写进共享环境日志。
Privacy Erasure:删除不是一条 SQL
用户要求删除数据时,第一步是建立 Data Inventory。
PostgreSQL authoritative tables
Redis session/cache
Object Storage uploads
pgvector / RAG derived rows
analytics
search index
backups
logs
third-party processors
如果只:
DELETE FROM users
其他副本仍可能存在。
ON DELETE CASCADE 解决什么
如果 child 的生命周期完全属于 parent:
user
└─ owned child
FK:
ON DELETE CASCADE
可以自动保持 referential cleanup。
但它不是隐私策略本身。
有些数据:
audit
billing
security event
legal retention
可能需要:
anonymize
retain minimal fields
expire later
explicit erasure workflow
不能全部 CASCADE。
Soft Delete 与 Erasure 不是同一个词
Soft Delete:
deleted_at = now
→ application hides row
→ bytes still exist
它适合:
undo
business history
workflow state
但:
如果要求真正删除个人数据,单纯 soft delete 往往不满足 erasure 目标。
必须明确 retention policy。
Backup 中的删除为什么特殊
很多 Backup 是:
immutable / append-retained
不现实每次用户删除都重写所有历史备份。
常见治理思路:
online systems erase promptly
backups access strictly restricted
backup retention expires
restore procedure re-applies erasure ledger before serving production
具体要求取决于法律/组织政策,但工程上必须把 Backup 纳入 data lifecycle。
Audit 与 Privacy 的张力
Audit 希望:
history not silently changed
Privacy 希望:
personal data not retained unnecessarily
设计需要:
记录 action identity / time / object
但避免记录不必要完整敏感 payload
这是 Data Minimization:
不因为“以后可能 debug”就无限复制和永久保留健康数据。
1. Least Privilege
应用数据库账号不应该默认是 superuser。应按需要授权 schema/table/sequence/extension 能力,migration role 与 runtime role 也可以分离。
2. Sensitive Data
分类:
credential secret
PII
health data
audit metadata
derived analytics
cache/search/embedding copies
不同类别有不同日志、保留、删除和访问策略。
3. SQL Log 也会泄露数据
BodySense production 调低 GORM SQL interpolation log level,就是为了避免 consultation/body-state payload 被写进共享日志。
Parameterized query 防 SQL injection,但不会自动防止敏感参数进入应用日志。
4. Privacy Erasure
删除用户不是:
DELETE FROM users WHERE id = ?;
就结束。要追踪:
FK child tables
uploads/object storage
Redis session/cache
pgvector / RAG derived rows
analytics/events
backup retention
audit exceptions
必须区分“立即从在线系统删除”和“历史备份按 retention 最终淘汰”。
5. ON DELETE CASCADE 不是万能隐私策略
CASCADE 很适合强 ownership child,但某些审计/不可变历史可能需要匿名化、软删除、保留法定字段或显式 lifecycle。关系语义必须先定义。
Prediction
[!question]
- 使用 parameterized SQL 后,数据库相关安全问题是否基本解决?
- Runtime 应用账号为什么不一定需要 CREATE EXTENSION / ALTER TABLE 权限?
- 用户表 ON DELETE CASCADE 能否证明 privacy erasure 已完整?
- 备份中的已删除数据该如何理解?
- 为方便 debug,把完整健康 JSONB 打到 SQL log 是否合适?
[!success]- Answer / 解析 1. 远远没有。 仍有权限、数据泄露、IDOR/authorization、日志、备份、连接 secret、生命周期等问题。
2. 这些是 schema/migration 权限,runtime 不需要时应遵循 least privilege,降低凭证泄露后的 blast radius。
3. 不能。 数据可能复制到 Redis、对象存储、向量库、analytics 和备份;还要检查非 FK 关联和外部系统。
4. 通常无法瞬时修改所有 immutable backup;需要明确 retention、访问控制和恢复后重新执行 erasure 的策略。
5. 不合适。 shared logs 会扩大敏感数据表面积;应记录结构化非敏感诊断或显式 redaction。
Lab
为 BodySense 做一张 user-data inventory:每一类用户数据列出 authority、派生副本、delete mechanism、retention、是否进入日志/备份。
L4 Gate
给定“用户请求删除账户”,能画出一条覆盖 PostgreSQL + Redis + uploads + vector/search + backup 的完整删除/保留边界。