最稳妥的权限隔离是为开发、测试、生产环境分别创建独立数据库及专属账号,严格限制跨库访问,权限由数据库用户本身强制管控,而非依赖应用层判断或配置约定。
用不同数据库或 schema 隔离开发、测试、生产账号最稳妥
权限隔离的本质是让环境之间无法互相读写,靠应用层“约定”不越界根本不可靠。数据库级隔离是最小侵入、最易审计的方式。
常见错误现象:SELECT * FROM users 在开发环境跑通,上线后意外删了生产数据;运维误把测试账号的 GRANT ALL ON * 复制到生产库。
- 开发环境用独立数据库,比如
myapp_dev;测试用myapp_test;生产用myapp_prod - 每个库配专属账号:开发账号只对
myapp_dev有SELECT, INSERT, UPDATE, DELETE权限,禁止跨库访问 - MySQL 8+ 或 PostgreSQL 可进一步用
CREATE SCHEMA+SET search_path控制可见范围,但不如独立库直观 - 注意连接字符串里不能硬编码库名——用配置项如
DATABASE_NAME注入,避免部署时漏改
避免在代码里写死权限逻辑(比如 if env == 'prod' then deny_delete)
这类判断一旦漏掉、写反或被绕过,就等于没隔离。权限检查必须落在数据库连接建立那一刻,而不是业务逻辑中间。
使用场景:你改了个接口,加了 if os.getenv('ENV') != 'prod': db.delete() —— 这种写法上线后只要环境变量没设对,或者有人本地调试时忘切环境,立刻崩。
- 所有环境共用同一套 SQL 和 ORM 模型,不加条件分支
- 权限由数据库用户本身决定:生产账号连上去就连不到开发表,连到了也查不了字段,根本不需要代码判断
- ORM 如 Django 的
db_router或 SQLAlchemy 的多引擎可以辅助路由,但别用来“模拟”权限,只用来分库
CI/CD 流水线里禁止自动执行 DDL 或 GRANT
流水线默认拥有高权限,如果脚本里写了 GRANT INSERT ON myapp_prod.users TO 'app_user',某次合并就可能把测试账号权限同步到生产。
错误现象:Permission denied: cannot execute GRANT in transaction block(PostgreSQL)或 MySQL 报 Access denied for user 'ci_user'@'%',说明权限模型已混乱。
- 建库、建用户、授予权限的操作全部抽离为手动审批步骤,或由 DBA 专用工具执行
- CI 中只允许运行
SELECT类校验语句,比如SELECT COUNT(*) FROM information_schema.tables WHERE table_schema = 'myapp_test' - 所有 GRANT 语句必须带明确的
ON database.table,禁用ON *.*;生产环境禁止WITH GRANT OPTION
密码和连接信息必须按环境加密分离,且禁止共享账号
一个 app_user 账号横跨三个环境,哪怕密码不同,只要其中任一环境失陷(比如开发机中病毒),攻击者就能暴力猜解其他环境密码。
性能影响:看似多几个账号麻烦,实则避免了每次连接都要动态判断环境再拼接权限,连接池复用率更高。
- 每个环境用独立用户名:如
app_dev、app_test、app_prod - 密码存进密钥管理服务(如 HashiCorp Vault、AWS Secrets Manager),按环境路径隔离,例如
secret/myapp/dev/db - 本地开发用
.env文件,但确保它被.gitignore严格排除;禁止出现DB_USER=app_prod这类明显错误配置
环境越复杂,越要回归本质:数据库账号本身就是权限载体。别指望靠人记规则、靠代码拦、靠流程卡——账号建错、连错库、权限开大,三秒就出事。

















