9.2 权限管理:GRANT 与 REVOKE 的最小权限实践


9.2 权限管理:GRANT 与 REVOKE 的最小权限实践

本节摘要:GRANT 授予权限、REVOKE 收回权限,授权粒度从整库到单列层层收紧。生产安全的第一原则是最小权限:报表账号只给 SELECT、应用账号按需给增删改、结构权限只留给 DBA 与迁移流程。权限与账号体系配合视图(第 8 章)能做出干净的读写分离与脱敏出口。

一、实习生为什么不该有 DROP 权限

复盘一个真实节奏的事故:周一入职的实习生拿到了测试库的高权限账号"图方便",周三他把连接配置里的 host 改错一位,连上了生产库,顺手执行了自己练习用的 DROP TABLE——生产表没了。事故链上的每一环单独看都可原谅:图方便、改配置、练手法;串起来就是灾难。防御不能靠"人小心",要靠权限结构让危险动作从一开始就无权发生:

  • 实习生:只读账号,仅 SELECT,仅指定库;
  • 应用服务:一个应用一个账号,只授予它实际用到的权限(通常 SELECT/INSERT/UPDATE/DELETE);
  • 迁移脚本:单独账号,临时授予 DDL,跑完收回;
  • DBA:全权,但走审计与堡垒机。

这条分层就是最小权限原则(principle of least privilege)的落地:每个身份只拿完成本职所需的最小权限集合,权限的默认答案是"不给"。

GRANT 三步走:建账号、授权、验证

-- 第一步:创建账号(MySQL 语法 用户名加主机限定) CREATE USER 'analyst_ro'@'%' IDENTIFIED BY '复杂口令A1'; CREATE USER 'svc_order'@'10.0.%' IDENTIFIED BY '复杂口令B2'; -- analyst_ro 给分析师 只读 -- svc_order 给订单服务 限定内网网段 -- 第二步:按角色授权 GRANT SELECT ON bookstore.* TO 'analyst_ro'@'%'; GRANT SELECT, INSERT, UPDATE, DELETE ON bookstore.orders TO 'svc_order'@'10.0.%'; GRANT SELECT, INSERT ON bookstore.order_items TO 'svc_order'@'10.0.%'; -- 明细表不给 UPDATE DELETE:订单明细不允许事后改删 由应用层保证 -- 第三步:验证(用新账号登录后) SHOW GRANTS FOR 'analyst_ro'@'%';
GRANT USAGE ON *.* TO `analyst_ro`@`%` GRANT SELECT ON `bookstore`.* TO `analyst_ro`@`%` -- USAGE 表示"只有登录资格 无实质权限" 这是每个账号的起点

读这三条 GRANT 时注意粒度的阶梯:bookstore.*整库bookstore.orders单表,还能细到 bookstore.orders(amount, status)单列——脱敏场景里"分析师只能看顾客表的姓名与城市、看不到手机号",列级授权一步到位。权限类型同样分层:SELECT/INSERT/UPDATE/DELETE 是数据权限,CREATE/ALTER/DROP 是结构权限(DDL),ALL 是全开(等于把 root 分了一半出去,慎用)。

REVOKE:止损与回收

权限不是发完就完,两条纪律:人员变动当天回收临时权限到期回收。REVOKE 的语法与 GRANT 镜像:

-- 收回整张表的删除权 REVOKE DELETE ON bookstore.orders FROM 'svc_order'@'10.0.%'; -- 迁移账号用完即收 REVOKE ALL ON bookstore.* FROM 'mig_tmp'@'localhost'; DROP USER 'mig_tmp'@'localhost'; -- 账号也一并销毁 不留僵尸
Query OK, 0 rows affected (0.02 sec) -- 收权即时生效 该账号下次执行 DELETE 即被拒

被收权后账号再执行越权语句,收到的是明确拒绝:

-- 用 analyst_ro 执行写操作的下场 DELETE FROM books WHERE id = 1;
ERROR 1142 (42000): DELETE command denied to user 'analyst_ro'@'...' for table 'books'

权限与视图配合:脱敏出口的完整拼图

第 8 章说过"视图是权限的搭档",现在拼上最后一块。需求:客服组要查订单,但顾客手机号不能暴露。方案:建脱敏视图、只授视图不授基表:

-- 基表里有完整手机号 视图里打码 CREATE VIEW v_orders_for_support AS SELECT o.id, o.status, o.amount, c.name, CONCAT(LEFT(c.phone, 3), '****', RIGHT(c.phone, 4)) AS phone_masked FROM orders o JOIN customers c ON c.id = o.customer_id; GRANT SELECT ON bookstore.v_orders_for_support TO 'support_ro'@'%'; -- 注意 不授 orders 与 customers 的任何权限
Query OK, 0 rows affected (0.03 sec) -- support_ro 查 v_orders_for_support 正常 查 customers 直接被拒 -- 打码发生在视图定义里 客服端无论怎么查都拿不到完整号码

这套"视图收口 + 列级授权 + 账号分层"的组合拳,是小团队不引额外组件就能做到的数据脱敏标准解。权限矩阵的评审要点收拢成四问:谁能写生产?谁能建删结构?谁能看敏感列?离职能当天断吗?四问都有清晰答案,权限体系就及格了。

⚠️ 常见坑:应用拿 root 连库"省得以后再授权"——一次 SQL 注入或配置泄露就直接交出全库;以及共享账号多人混用,出事无法定位到人。账号与身份一一对应是审计的底线,宁可多建十个号,不留一个共享号。

💡 关键直觉:把权限当"默认全拒、按需开洞"的防火墙。每条 GRANT 都是一次开洞,洞的大小(库/表/列)与方向(读/写/结构)都该有对应的业务理由——说不清理由的授权,一律先驳回。

本节要点回顾

  • 最小权限原则:默认不给、按需开洞、够用即止,权限结构是事故链的第一道断路器;
  • 账号分层:只读分析、应用专用、迁移临时、DBA 全权走审计,一人一号不共享;
  • 授权粒度阶梯:整库、单表、单列;数据权限与结构权限分开管理,ALL 慎给;
  • REVOKE 即时生效:人员变动与临时权限到期当天回收,僵尸账号一并 DROP;
  • 视图加列级授权做脱敏:打码写进视图定义,客服端查不到完整敏感列;
  • 权限评审四问:谁能写生产、谁能动结构、谁能看敏感列、离职能否当天断。

作者与出处
原作者: 灏天文库
来源:灏天文库
整理: 灏天文库整理
由灏天文库平台收录,内容或由平台用户上传,仅供学习交流
发布者: 作者: 灏天文库 转发
评论区 (0)
U