当前位置: 代码迷 >> Access >> select into outfile access deny有关问题
  详细解决方案

select into outfile access deny有关问题

热度:2669   发布时间:2013-02-26 00:00:00.0
select into outfile access deny问题
为应用建立了rnd的帐号,专门为他们查询线上数据库用的,当然,只有他们上了生产网络以后才能连上数据库,安全方面我们还是很注意的,呵呵。
授权的语句如下:
grant select on armory.* to rnd;
flush privileges;

select查询数据没有问题,但是有的用户有了更多的需求,他想把数据导出来,简单的处理的话,可以用select into outfile导出来。自己指定字段的分隔,行分隔等等。
但是用户一查询就报:access deny的错误,权限不对。
rnd@localhost : armory 09:26:31> select * into outfile ‘/tmp/1.txt’ from os limit 5;
ERROR 1045 (28000): Access denied for user ‘rnd’@'%’ (using password: NO)
郁闷的是MySQL没有说缺少了那个权限。

在本机测试了一下,
grant all on armory.* to rnd;
flush privileges;
给rnd所有的权限以后,还是报权限错误。这个就奇怪了,所有的权限都给它了,还报错?不可理喻阿。
实在搞不定,最后让用户:
mysql -urnd -p -e ‘select * from os limit 5;’ >1.txt
的变通方法。

一直被这个纠结着,突然后来有一天,查询了一下MySQL的文档,找到是file的权限没有加上去,但是当时MySQL对应的库的所有权限我都加上去了阿。灵光一闪,file是全局的权限,在MySQL中对单个库是没有这个权限概念的,所以就算我把库上的所有权限给了rnd,file的权限其实还是没有附权给它的。不信的话,我们这就试试:
root@localhost : (none) 09:55:14> grant file on armory.* to rnd;
ERROR 1221 (HY000): Incorrect usage of DB GRANT and GLOBAL PRIVILEGES
果然,File权限是GLOBAL权限,不能附权给数据库。
GLOBAL FILE附权以后
root@localhost : mysql 09:58:21> grant file on *.* to rnd;
Query OK, 0 rows affected (0.00 sec)
select查询就可以执行了:
rnd@localhost : armory 10:00:42> select * into outfile ‘/tmp/1.txt’ from os limit 5;
Query OK, 5 rows affected (0.00 sec)

其实MySQL的权限可能比较拗,让我们一下子适应不过来。MySQL的权限可以精细到列,权限判断是根据GLOBAL,DB,TABLE,COLUMN来授权的,可以简单的理解为他们对应到mysql库中的四个表:user,db,tables_priv,columns_priv这几个表。当然,MySQL没有这么简单拉。有兴趣的话可以好好看一下MySQL的reference或者其他介绍。举个例子:
rnd@localhost : armory 10:00:43> show grants for rnd;
+————————————————-+
| Grants for rnd@%                                |
+————————————————-+
| GRANT FILE ON *.* TO ‘rnd’@'%’                  |
| GRANT ALL PRIVILEGES ON `armory`.* TO ‘rnd’@'%’ |
+————————————————-+
2 rows in set (0.00 sec)
grant对同一个用户就分了两行,分别对应着user和db里面的两行:
root@localhost : mysql 10:18:34> select * from mysql.user where user=’rnd’\G
*************************** 1. row ***************************
Host: %
User: rnd
Password:
Select_priv: N
Insert_priv: N
Update_priv: N
Delete_priv: N
Create_priv: N
Drop_priv: N
Reload_priv: N
Shutdown_priv: N
Process_priv: N
File_priv: Y
Grant_priv: N
References_priv: N
Index_priv: N
Alter_priv: N
Show_db_priv: N
Super_priv: N
Create_tmp_table_priv: N
Lock_tables_priv: N
Execute_priv: N
Repl_slave_priv: N
Repl_client_priv: N
Create_view_priv: N
Show_view_priv: N
Create_routine_priv: N
Alter_routine_priv: N
Create_user_priv: N
Event_priv: N
Trigger_priv: N
ssl_type:
ssl_cipher:
x509_issuer:
x509_subject:
max_questions: 0
max_updates: 0
max_connections: 0
max_user_connections: 0
1 row in set (0.00 sec)

root@localhost : mysql 10:18:41> select * from mysql.db where user=’rnd’\G
*************************** 1. row ***************************
Host: %
Db: armory
User: rnd
Select_priv: Y
Insert_priv: Y
Update_priv: Y
Delete_priv: Y
Create_priv: Y
Drop_priv: Y
Grant_priv: N
References_priv: Y
Index_priv: Y
Alter_priv: Y
Create_tmp_table_priv: Y
Lock_tables_priv: Y
Create_view_priv: Y
Show_view_priv: Y
Create_routine_priv: Y
Alter_routine_priv: Y
Execute_priv: Y
Event_priv: Y
Trigger_priv: Y
1 row in set (0.00 sec)
MySQL的权限检查也是通过检查这两个表来进行判断的。

附上tables_priv和columns_priv的两个表的字段,和user和db还是有点不同的,用到了set类型。
root@localhost : mysql 10:18:58> desc tables_priv;
+————-+———————————————————————————————————————————–+——+—–+——————-+—————————–+
| Field       | Type                                                                                                                              | Null | Key | Default           | Extra                       |
+————-+———————————————————————————————————————————–+——+—–+——————-+—————————–+
| Host        | char(60)                                                                                                                          | NO   | PRI |                   |                             |
| Db          | char(64)                                                                                                                          | NO   | PRI |                   |                             |
| User        | char(16)                                                                                                                          | NO   | PRI |                   |                             |
| Table_name  | char(64)                                                                                                                          | NO   | PRI |                   |                             |
| Grantor     | char(77)                                                                                                                          | NO   | MUL |                   |                             |
| Timestamp   | timestamp                                                                                                                         | NO   |     | CURRENT_TIMESTAMP | on update CURRENT_TIMESTAMP |
| Table_priv  | set(‘Select’,'Insert’,'Update’,'Delete’,'Create’,'Drop’,'Grant’,'References’,'Index’,'Alter’,'Create View’,'Show view’,'Trigger’) | NO   |     |                   |                             |
| Column_priv | set(‘Select’,'Insert’,'Update’,'References’)                                                                                      | NO   |     |                   |                             |
+————-+———————————————————————————————————————————–+——+—–+——————-+—————————–+
8 rows in set (0.00 sec)

root@localhost : mysql 10:21:24> desc columns_priv;
+————-+———————————————-+——+—–+——————-+—————————–+
| Field       | Type                                         | Null | Key | Default           | Extra                       |
+————-+———————————————-+——+—–+——————-+—————————–+
| Host        | char(60)                                     | NO   | PRI |                   |                             |
| Db          | char(64)                                     | NO   | PRI |                   |                             |
| User        | char(16)                                     | NO   | PRI |                   |                             |
| Table_name  | char(64)                                     | NO   | PRI |                   |                             |
| Column_name | char(64)                                     | NO   | PRI |                   |                             |
| Timestamp   | timestamp                                    | NO   |     | CURRENT_TIMESTAMP | on update CURRENT_TIMESTAMP |
| Column_priv | set(‘Select’,'Insert’,'Update’,'References’) | NO   |     |                   |                             |
+————-+———————————————-+——+—–+——————-+—————————–+
7 rows in set (0.00 sec)

may your success.


-------------------------------------
我理清是什么问题了。
在red hat系列的linux中selinux对哪些daemon可以进行怎么样的操作是有限制的,mysql的select into outfile的命令是mysql的daemon来负责写文件操作的。写文件之前当然要具有写文件的权限。而selinux对这个权限做了限制。如果selinux是关闭的吧,这个命令执行是没有问题的
mysql> select user from user into outfile '/home/test.txt';
Query OK, 2 rows affected (0.02 sec)
当时selinux开启时
selinux对mysql的守护进程mysqld进行了限制。
mysql> select user from user into outfile '/home/test.txt';
ERROR 1 (HY000): Can't create/write to file '/home/test.txt' (Errcode: 13) 
出现了没有权限写的error。
解决方法,可以关闭selinux。
可以在/etc/selinux中找到config
root用户,
shell>vi /etc/selinux/config

# This file controls the state of SELinux on the system.
# SELINUX= can take one of these three values:
# enforcing - SELinux security policy is enforced.
# permissive - SELinux prints warnings instead of enforcing.
# disabled - SELinux is fully disabled.
SELINUX=enforcing

修改SELINUX=disabled关闭selinux就可以了,这个问题就可以解决了。
不过全部关闭SELINUX有带来一些安全问题。
当然也可以,单独给mysql的守护进程权限,
shell>getsebool -a可以查看当前的对系统一系列守护进程的权限情况。

lpd_disable_trans --> off
mail_read_content --> off
mailman_mail_disable_trans --> off
mdadm_disable_trans --> off
mozilla_read_content --> off
mysqld_disable_trans --> off
nagios_disable_trans --> off
named_disable_trans --> off
named_write_master_zones --> off
nfs_export_all_ro --> on
nfs_export_all_rw --> on
nfsd_disable_trans --> off
nmbd_disable_trans --> off
nrpe_disable_trans --> off

shell>setsebool -P mysqld_disable_trans=1
开启对mysql守护进程的权限,这样
mysql> select user from user into outfile '/home/test.txt';
写入到自定义的目录就没有问题了。
-P表示 是永久性设置,否则重启之后又恢复预设值。
getsebool setsebool命令在root用户下有权限。

除了对selinux的权限,当然首先要保证该目录拥有读写权限。


在ubuntu下 ,可以对AppArmor(/etc/apparmor.d/usr.sbin.mysqld) 修改,类似selinux。
添加/etc/squid/lists/eighties.txt w,类似。

---------------------------------------------


root用户登录下:
grant file on *.* to webgametest@10.3.18.158;

改为生成在tmp文件夹下。



  相关解决方案