乔丹尼斯 發表於 2025-11-25 14:15:00

MySQL权限管理的坑你踩了没有?

<p>假设有这么一个需求,开发人员要求你创建一个账号test,要求这个账号有创建表,查询,更新,删除表的权限, 如下例子所示</p>
<pre><code class="language-SQL">mysql&gt; select version();
+-----------+
| version() |
+-----------+
| 8.4.5   |
+-----------+
1 row in set (0.00 sec)

mysql&gt; create database if not exists kerry   
    -&gt; default character set utf8mb4
    -&gt; default collate utf8mb4_general_ci;
query ok, 1 row affected (0.02 sec)


mysql&gt; create user `test`@`%` identified by'Test@#$123456';
Query OK, 0 rows affected (0.02 sec)

mysql&gt;

mysql&gt; grant create, drop ,select,update on kerry.* to test@'%';
Query OK, 0 rows affected (0.00 sec)

mysql&gt; flush privileges;
Query OK, 0 rows affected (0.01 sec)

mysql&gt;
</code></pre>
<p>然后我们以test用户登录数据库, 此时你执行下面SQL,你会发现,你不光有drop掉表的权限,甚至连数据库kerry都可以drop掉.如下所示</p>
<pre><code class="language-SQL">mysql&gt; select current_user();
+----------------+
| current_user() |
+----------------+
| test@%         |
+----------------+
1 row in set (0.00 sec)
mysql&gt; use kerry;
Database changed

mysql&gt; create table t1(id int, name varchar(12));
Query OK, 0 rows affected (0.02 sec)

mysql&gt; drop table t1;
Query OK, 0 rows affected (0.01 sec)

mysql&gt; drop database kerry;
Query OK, 0 rows affected (0.01 sec)

mysql&gt;
</code></pre>
<p>然后你会发现,test用户不光有drop掉数据库kerry的权限,而且有创建数据库kerry的权限(<strong>仅仅是创建/删除kerry这个数据库.没有创建/删除其它数据库的权限</strong>),如下所示:</p>
<pre><code class="language-SQL">mysql&gt; select current_user();
+----------------+
| current_user() |
+----------------+
| test@%         |
+----------------+
1 row in set (0.00 sec)

mysql&gt; create database if not exists kerry
    -&gt; default character set utf8mb4
    -&gt; default collate utf8mb4_general_ci;
query ok, 1 row affected (0.01 sec)

mysql&gt; drop database kerry;
query ok, 0 rows affected (0.00 sec)

mysql&gt; create database kkk;
error 1044 (42000): access denied for user 'test'@'%' to database 'kkk'

mysql&gt; drop database k2;
ERROR 1044 (42000): Access denied for user 'test'@'%' to database 'k2'
mysql&gt;
</code></pre>
<p>其实具体原因是你没有留意MySQL官方文档关于CREATE/DROP权限的详细说明,你以为的CREATE权限是创建表的权限,DROP权限是DROP表的权限.其实不然, 如下截图所示,CREATE权限包含创建数据库、表或索引的权限,而DROP权限包DROP数据库、表或视图的权限. 至于为什么MySQL没有细化这些权限.我们也不清楚.但是从上面实验来看, 我都倾向于这个是一个逻辑上的"Bug".</p>
<p><img src="https://img2024.cnblogs.com/blog/73542/202511/73542-20251125141447989-1321837869.png" alt="" loading="lazy"></p>
<p>那么如果这样授权,会有什么问题呢?**如果账号授予了DROP权限,那么这就是一个安全权限的"漏洞", SQL注入式攻击都可以利用这个"漏洞"直接将数据库给删除了. **</p>
<h1 id="解决方案">解决方案</h1>
<p>MySQL中没有单独的CREATE TABLE, DROP TABLE的权限,我们只能另避蹊径,先收回账号test的DROP权限,然后创建一个角色drop_tab,这个角色授予数据库kerry中具体每一个表的DROP权限,最后授予用户这个角色. 如下所示:</p>
<pre><code class="language-SQL">mysql&gt; select current_user();
+----------------+
| current_user() |
+----------------+
| root@localhost |
+----------------+
1 row in set (0.01 sec)

mysql&gt; show grants for test@'%';
+---------------------------------------------------------------+
| Grants for test@%                                             |
+---------------------------------------------------------------+
| GRANT USAGE ON *.* TO `test`@`%`                              |
| GRANT SELECT, UPDATE, CREATE, DROP ON `kerry`.* TO `test`@`%` |
+---------------------------------------------------------------+
2 rows in set (0.00 sec)

mysql&gt; revoke drop on`kerry`.* from `test`@`%`;
Query OK, 0 rows affected (0.06 sec)

mysql&gt; flush privileges;
Query OK, 0 rows affected (0.01 sec)

mysql&gt; create role drop_tab;
Query OK, 0 rows affected (0.01 sec)
ysql&gt; select
    -&gt;       table_name
    -&gt;      ,table_type
    -&gt;      ,concat('grant drop on ', table_schema, '.', table_name , ' to drop_tab;') as grant_cmd
    -&gt;from information_schema.tables
    -&gt;where table_schema='kerry';
+------------+------------+-------------------------------------+
| TABLE_NAME | TABLE_TYPE | grant_cmd                           |
+------------+------------+-------------------------------------+
| t1         | BASE TABLE | grant drop on kerry.t1 to drop_tab; |
| t2         | BASE TABLE | grant drop on kerry.t2 to drop_tab; |
+------------+------------+-------------------------------------+
2 rows in set (0.00 sec)

mysql&gt; grant drop on kerry.t1 to drop_tab;
Query OK, 0 rows affected (0.00 sec)

mysql&gt; grant drop on kerry.t2 to drop_tab;
Query OK, 0 rows affected (0.00 sec)

mysql&gt; grant drop_tab to test@'%';
Query OK, 0 rows affected (0.01 sec)

mysql&gt; SET DEFAULT ROLE 'drop_tab' TO 'test'@'%';
Query OK, 0 rows affected (0.01 sec)

mysql&gt; flush privileges;
Query OK, 0 rows affected (0.01 sec)

mysql&gt;
</code></pre>
<p>此时,账号test就没有删除数据库kerry的权限了. 当然,你的先退出然后登录(如果之前test账号没有退出一直连接数据库的话)</p>
<pre><code class="language-SQL">mysql&gt; select current_role();
+----------------+
| current_role() |
+----------------+
| `drop_tab`@`%` |
+----------------+
1 row in set (0.00 sec)

mysql&gt; select current_user();
+----------------+
| current_user() |
+----------------+
| test@%         |
+----------------+
1 row in set (0.00 sec)

mysql&gt; drop table t1;
Query OK, 0 rows affected (0.01 sec)

mysql&gt; drop database kerry;
ERROR 1044 (42000): Access denied for user 'test'@'%' to database 'kerry'
mysql&gt;
</code></pre>
<p><img src="https://img2024.cnblogs.com/blog/73542/202511/73542-20251125141447981-642360023.png" alt="" loading="lazy"></p>
<h1 id="总结">总结</h1>
<p>关于数据库的权限,我们还是要细心与谨慎. 数据库授权,一般要秉着权限越小越好的原则,避免权限过大带来不必要的麻烦. 另外,就是MySQL这种权限设计,        其实是设计上的一大缺陷.很容易让人踩一个大坑.</p>


</div>
<div id="MySignature" role="contentinfo">
    <div id="KerryCodeSignature">
<div>
<img src="https://images.cnblogs.com/cnblogs_com/kerrycode/1913302/o_240731062102_kerrycode.png" height="120" width="500">
</div>
<div>
<b>扫描上面二维码关注我</b>
</div>
<div>如果你真心觉得文章写得不错,而且对你有所帮助,那就不妨帮忙“推荐"一下,您的“推荐”和”打赏“将是我最大的写作动力!</div>
<div>本文版权归作者所有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接.</div>
</div><br><br>
来源:https://www.cnblogs.com/kerrycode/p/19268303
頁: [1]
查看完整版本: MySQL权限管理的坑你踩了没有?