拾光札记

数据库最小权限实践

以 MySQL 为例,讲清楚为什么别用 root 跑业务、怎么按库按表授权、只给必要权限、限定访问来源,配真实 SQL。

「最小权限」是安全里最朴素也最有用的一条原则:每个账号只给它完成本职工作所需的最小权限,多一点都不给。数据库尤其要讲究这个——一旦某个业务账号被人拿到,它能干的事越少,损失就越小。

这篇以 MySQL / MariaDB 为例,讲清楚怎么落地。命令换成 PostgreSQL 思路一样,只是语法不同。

一、为什么不能用 root 跑业务

很多人图省事,网站直接用 root 连数据库。这非常危险:

  • root 能删库、改任何表、创建新用户、读所有数据。
  • 一旦你的网站有 SQL 注入之类的漏洞,攻击者借着这个 root 连接,就能对整个数据库为所欲为——包括 DROP DATABASE(删库跑路真不是段子)。
  • 反过来,如果业务账号只有某个库的读写权限,就算被利用,攻击者也碰不到其它库、删不了库、建不了新账号。

结论:业务程序永远用专用的、权限受限的账号连数据库,root 只留给管理员手动运维。

二、给每个应用建独立账号

假设你有一个博客应用,用一个叫 blog 的数据库。给它建一个专属账号:

-- 只允许从本机连接(@'localhost'),密码用强密码
CREATE USER 'blog_app'@'localhost' IDENTIFIED BY '换成一个足够强的密码';

这里的 @'localhost' 很关键,下面第四节会细说。

三、只授予必要的权限

一个典型的网站业务,通常只需要对自己那个库做增删改查,用不着建表删表、更用不着碰别的库。所以只给这几样:

-- 只对 blog 这个库的所有表,授予查询/插入/更新/删除四种权限
GRANT SELECT, INSERT, UPDATE, DELETE ON blog.* TO 'blog_app'@'localhost';

-- 让权限生效
FLUSH PRIVILEGES;

对比一下,下面这些是绝大多数业务账号都不该有的危险权限:

权限能干什么为什么别给业务账号
ALL PRIVILEGES所有权限等于半个 root,范围太大
DROP删表 / 删库被注入后可直接删库
GRANT OPTION给别人授权能自己给自己提权
CREATE USER建新账号攻击者可留后门账号
FILE读写服务器文件可能被用来读系统文件

如果某个后台管理功能确实需要建表(比如安装程序),可以临时授予、用完立刻收回,别长期挂着。

权限还能精确到表和列

如果想更细,权限可以只给某几张表,甚至某几列:

-- 只给 blog 库里 posts 表的查询和更新权限
GRANT SELECT, UPDATE ON blog.posts TO 'some_user'@'localhost';

-- 只允许更新 posts 表的 title 和 content 两列
GRANT UPDATE (title, content) ON blog.posts TO 'some_user'@'localhost';

一个常见场景:给「只读报表 / 数据分析」的账号,就只给 SELECT,它连改数据的能力都没有,最安全。

CREATE USER 'report_readonly'@'192.168.1.50' IDENTIFIED BY '强密码';
GRANT SELECT ON blog.* TO 'report_readonly'@'192.168.1.50';
FLUSH PRIVILEGES;

四、限定访问来源(谁能连)

MySQL 账号的完整身份是 '用户名'@'来源',那个 @ 后面决定了这个账号只能从哪里连进来。用好它,等于给账号加了一道网络锁:

  • 'blog_app'@'localhost' —— 只能从数据库本机连。网站和数据库在同一台服务器时,用这个最安全。
  • 'blog_app'@'192.168.1.50' —— 只能从这个内网 IP 连。网站和数据库分开部署时用。
  • 'blog_app'@'%' —— 任何 IP 都能连,尽量别用。这等于把数据库门开向全世界。

千万别为了图方便用 @'%' 再把 3306 端口对公网开放,这是数据库被拖库的头号原因。数据库端口应该只在本机或内网可达,配合 服务器安全加固清单 里的防火墙一起做。

五、检查与回收权限

查看某个账号现在有哪些权限:

SHOW GRANTS FOR 'blog_app'@'localhost';

发现权限给多了,收回来:

-- 收回 blog 库上的 DELETE 权限
REVOKE DELETE ON blog.* FROM 'blog_app'@'localhost';
FLUSH PRIVILEGES;

删掉不再使用的账号(离职的人、废弃的应用,及时清掉):

DROP USER 'old_user'@'localhost';

六、几条配套习惯

  • 强密码 + 不复用:每个数据库账号用独立的强密码,别和别处共用。
  • 密码别写进代码仓库:放到环境变量或配置文件里,并确保配置文件不被提交到 Git。
  • 定期审计账号:隔段时间用 SELECT user, host FROM mysql.user; 看看有哪些账号,清掉不认识的、不用的。
  • 关掉匿名账号和测试库:新装的 MySQL 建议跑一遍 mysql_secure_installation,它会帮你删匿名用户、删 test 库、禁止 root 远程登录。

一页速查清单

  • 业务程序绝不用 root 连库
  • 每个应用一个独立账号
  • 只授予实际需要的权限(多数只要 SELECT/INSERT/UPDATE/DELETE)
  • 只读场景就只给 SELECT
  • 不给 DROP / GRANT OPTION / CREATE USER / FILE 等高危权限
  • 用 @'localhost' 或指定 IP 限定来源,别用 @'%'
  • 数据库端口不对公网开放
  • 定期 SHOW GRANTS 审计、清理废弃账号
  • 跑 mysql_secure_installation 做基础收敛

相关文章

本页目录