分类: Mysql/postgreSQL
2008-05-11 17:44:54
附加的功能包括有匿名的用户并对于MySQL特定的功能例如LOAD DATA INFILE进行授权及管理操作的能力。
MySQL权限系统保证所有的用户只执行允许做的事情。当你连接MySQL服务器时,你的身份由你从那儿连接的主机和你指定的用户名来决定。连接后发出请求后,系统根据你的身份和你想做什么来授予权限。
MySQL在认定身份中考虑你的主机名和用户名字,是因为几乎没有原因假定一个给定的用户在因特网上属于同一个人。例如,从office.com连接的用户joe不一定和从elsewhere.com连接的joe是同一个人。MySQL通过允许你区分在不同的主机上碰巧有同样名字的用户来处理它:你可以对joe从office.com进行的连接授与一个权限集,而为joe从elsewhere.com的连接授予一个不同的权限集。
MySQL存取控制包含2个阶段:
如果连接时你的权限被更改了(通过你和其它人),这些更改不一定立即对你发出的下一个语句生效。详情参见5.7.7节,“权限更改何时生效”。
服务器在mysql数据库的 授权表中保存权限信息(即在mysql数据库中)。当MySQL服务器启动时将这些表的内容读入内存,在5.7.7节,“权限更改何时生效”的环境下重新读取它们。访问控制决策取决于内存中的 授权表的份数。
一般情况,你通过GRANT和REVOKE语句间接来操作 授权表的内容,设置账户并控制个人的权限。参见13.5.1.3节,“GRANT和REVOKE语法”。下面讨论了 授权表的结构以及服务器与客户端交互操作时如何使用其内容。
服务器在存取控制的两个阶段使用mysql数据库中的user、db和host表,这些授权表中的列如下:
表名 |
user |
db |
host |
列范围 |
Host |
Host |
Host |
|
User |
Db |
Db |
|
Password |
User |
|
权限列 |
Select_priv |
Select_priv |
Select_priv |
|
Insert_priv |
Insert_priv |
Insert_priv |
|
Update_priv |
Update_priv |
Update_priv |
|
Delete_priv |
Delete_priv |
Delete_priv |
|
Index_priv |
Index_priv |
Index_priv |
|
Alter_priv |
Alter_priv |
Alter_priv |
|
Create_priv |
Create_priv |
Create_priv |
|
Drop_priv |
Drop_priv |
Drop_priv |
|
Grant_priv |
Grant_priv |
Grant_priv |
|
Create_view_priv |
Create_view_priv |
Create_view_priv |
|
Show_view_priv |
Show_view_priv |
Show_view_priv |
|
Create_routine_priv |
Create_routine_priv |
|
|
Alter_routine_priv |
Alter_routine_priv |
|
|
References_priv |
References_priv |
References_priv |
|
Reload_priv |
|
|
|
Shutdown_priv |
|
|
|
Process_priv |
|
|
|
File_priv |
|
|
|
Show_db_priv |
|
|
|
Super_priv |
|
|
|
Create_tmp_table_priv |
Create_tmp_table_priv |
Create_tmp_table_priv |
|
Lock_tables_priv |
Lock_tables_priv |
Lock_tables_priv |
|
Execute_priv |
|
|
|
Repl_slave_priv |
|
|
|
Repl_client_priv |
|
|
安全列 |
ssl_type |
|
|
|
ssl_cipher |
|
|
|
x509_issuer |
|
|
|
x509_subject |
|
|
资源控制列 |
max_questions |
|
|
|
max_updates |
|
|
|
max_connections |
|
|
|
max_user_connections |
|
|
对存取控制的第二阶段(请求证实),服务器执行请求验证以确保每个客户端有充分的权限满足各需求。除了user、db和host授权表,如果请求涉及表,服务器可以另外参考tables_priv和columns_priv表。tables_priv和columns_priv表可以对表和列提供更精确的权限控制。这些表的列如下:
表名 |
tables_priv |
columns_priv |
范围列 |
Host |
Host |
|
Db |
Db |
|
User |
User |
|
Table_name |
Table_name |
|
|
Column_name |
权限列 |
Table_priv |
Column_priv |
|
Column_priv |
|
其它列 |
Timestamp |
Timestamp |
|
Grantor |
|
Timestamp和Grantor列当前还未使用,这儿不再进一步讨论。
为了对涉及保存程序的请求进行验证,服务器将查阅procs_priv表。该表具有以下列:
表名 |
procs_priv |
范围列 |
Host |
|
Db |
|
User |
|
Routine_name |
|
Routine_type |
权限列 |
Proc_priv |
其它列 |
Timestamp |
|
Grantor |
Routine_type列为ENUM列,值为'FUNCTION'或'PROCEDURE',表示行所指的程序类型。该列允许为同名函数和程序单独授权。
Timestamp和Grantor列当前还未使用,这儿不再进一步讨论。
每个授权表包含范围列和权限列:
l 范围列决定表中每个条目(行)的范围,即,行适用的上下文。例如, 一个user表行的Host和User值为'thomas.loc.gov'和'bob',将被用于证实来自主机thomas.loc.gov的bob对服务器的连接。同样,一个db表行的Host、User和Db列的值是'thomas.loc.gov'、'bob'和'reports'将用在bob从主机thomas.loc.gov联接访问reports数据库的时候。tables_priv和columns_priv表包含范围列,指出每个行适用的表或表/列的组合。procs_priv范围列指出每个行适用的保存程序。
对于检查存取的用途,比较Host值是忽略大小写的。User、Password、Db和Table_name值是区分大小写的。Column_name值在MySQL3.22.12或以后版本是忽略大小写的。
l 权限列指出由一个表行授予的权限,即,可实施什么操作。服务器组合各种的授权表的信息形成一个用户权限的完整描述。为此使用的规则在5.7.6节,“访问控制, 阶段2:请求核实”描述。
范围列包含字符串,如下所述;每个列的默认值是空字符串:
列名 |
类型 |
Host |
CHAR(60) |
User |
CHAR(16) |
Password |
CHAR(16) |
Db |
CHAR(64) |
Table_name |
CHAR(64) |
Column_name |
CHAR(64) |
Routine_name |
CHAR(64) |
为了访问检查目的,Host值的比较对大小写不敏感。User、Password、Db和Table_name值对大小写敏感。Column_name值对大小写不敏感。
在user、db和host表中,所有权限列于单独的列内,被声明为ENUM('N','Y') DEFAULT 'N'。换句话说,每一个权限都可以被禁用和启用,并且 默认是禁用。
在tables_priv、columns_priv和procs_priv表中,权限列被声明为SET列。这些列的值可以包含该表控制的权限的组合:
表名 |
列名 |
可能的设置元素 |
tables_priv |
Table_priv |
'Select', 'Insert', 'Update', 'Delete', 'Create', 'Drop', 'Grant', 'References', 'Index', 'Alter' |
tables_priv |
Column_priv |
'Select', 'Insert', 'Update', 'References' |
columns_priv |
Column_priv |
'Select', 'Insert', 'Update', 'References' |
procs_priv |
Proc_priv |
'Execute', 'Alter Routine', 'Grant' |
简单地说,服务器使用这样的授权表:
· user表范围列决定是否允许或拒绝到来的连接。对于允许的连接,user表授予的权限指出用户的全局(超级用户)权限。这些权限适用于服务器上的all数据库。
· db表范围列决定用户能从哪个主机存取哪个数据库。权限列决定允许哪个操作。授予的数据库级别的权限适用于数据库和它的表。
· 当你想要一个给定的db表行应用于若干主机时,db和host表一起使用。例如,如果你想要一个用户能在你的网络从若干主机使用一个数据库,在用户的db表行的Host值设为空值,然后将那些主机的每一个移入host表。这个机制详细描述在5.7.6节,“访问控制, 阶段2:请求核实”。
注释:host表不受GRANT和REVOKE语句的影响。大多数MySQL安装根本不需要使用该表。
· tables_priv和columns_priv表类似于db表,但是更精致:它们在表和列级应用而非在数据库级。授予表级别的权限适用于表和所有它的列。授予列级别的权限只适用于专用列。
· procs_priv表适用于保存的程序。授予程序级别的权限只适用于单个程序。
管理权限(例如RELOAD或SHUTDOWN等等)仅在user表中被指定。这是因为管理性操作是服务器本身的操作并且不是特定数据库,因此没有理由在其他授权表中列出这样的权限。事实上,只需要查询user表来决定你是否执行一个管理操作。
FILE权限也仅在user表中指定。它不是管理性权限,但你在服务器主机上读或写文件的能力与你正在存取的数据库无关。
当mysqld服务器启动时,将授权表的内容读入到内存中。你可以通过FLUSH PRIVILEGES语句或执行mysqladmin flush-privileges或mysqladmin reload命令让它重新读取表。对授权表的更改生效在5.7.7节,“权限更改何时生效”描述。
当你修改授权表的内容时,确保你按你想要的方式更改权限设置是一个好主意。要检查给定账户的权限,使用SHOW GRANTS语句。例如,要检查Host和User值分别为pc84.example.com和bob的账户所授予的权限,应通过语句:
mysql> SHOW GRANTS FOR 'bob'@'pc84.example.com';
一个有用的诊断工具是mysqlaccess脚本,由Carlier Yves 提供给MySQL分发。使用--help选项调用mysqlaccess查明它怎样工作。注意:mysqlaccess仅用user、db和host表检查存取。它不检查tables_priv、columns_priv或procs_priv表中指定的表、列和程序级权限。
对于诊断权限相关的问题的其它帮助,参见5.7.8节,“拒绝访问错误的原因”。对于安全问题常规建议,参见5.6节,“一般安全问题”。
账户权限信息被存储在mysql数据库的user、db、host、tables_priv、columns_priv和procs_priv表中。在MySQL启动时并在5.7.7节,“权限更改何时生效”所说的情况时,服务器将这些数据库表内容读入内存。
GRANT和REVOKE语句所用的涉及权限的名称显示在下表,还有在授权表中每个权限的表列名称和每个权限有关的上下文。关于每个权限的含义相关的详细信息参见13.5.1.3节,“GRANT和REVOKE语法”。
权限 |
列 |
上下文 |
CREATE |
Create_priv |
数据库、表或索引 |
DROP |
Drop_priv |
数据库或表 |
GRANT OPTION |
Grant_priv |
数据库、表或保存的程序 |
REFERENCES |
References_priv |
数据库或表 |
ALTER |
Alter_priv |
表 |
DELETE |
Delete_priv |
表 |
INDEX |
Index_priv |
表 |
INSERT |
Insert_priv |
表 |
SELECT |
Select_priv |
表 |
UPDATE |
Update_priv |
表 |
CREATE VIEW |
Create_view_priv |
视图 |
SHOW VIEW |
Show_view_priv |
视图 |
ALTER ROUTINE |
Alter_routine_priv |
保存的程序 |
CREATE ROUTINE |
Create_routine_priv |
保存的程序 |
EXECUTE |
Execute_priv |
保存的程序 |
FILE |
File_priv |
服务器主机上的文件访问 |
CREATE TEMPORARY TABLES |
Create_tmp_table_priv |
服务器管理 |
LOCK TABLES |
Lock_tables_priv |
服务器管理 |
CREATE USER |
Create_user_priv |
服务器管理 |
PROCESS |
Process_priv |
服务器管理 |
RELOAD |
Reload_priv |
服务器管理 |
REPLICATION CLIENT |
Repl_client_priv |
服务器管理 |
REPLICATION SLAVE |
Repl_slave_priv |
服务器管理 |
SHOW DATABASES |
Show_db_priv |
服务器管理 |
SHUTDOWN |
Shutdown_priv |
服务器管理 |
SUPER |
Super_priv |
服务器管理 |
当从早期的没有CREATE VIEW、SHOW VIEW、CREATE ROUTINE、ALTER ROUTINE和EXECUTE权限的版本的MySQL中升级时,要想使用这些权限,你必须使用MySQL分发提供的mysql_fix_privilege_tables脚本升级 授权表。参见2.10.2节,“升级授权表”。
如果启用了二进制记录,要想创建或修改保存的程序,你还需要SUPER权限,详细描述见20.4节,“存储子程序和触发程序的二进制日志功能”。
通过CREATE和DROP权限,你可以创建新数据库和表,或删除(移掉)已有数据库和表。如果你将mysql数据库中的DROP权限授予某用户,用户可以删掉MySQL访问权限保存的数据库。
SELECT、INSERT、UPDATE和DELETE权限允许你在一个数据库现有的表上实施操作。
SELECT语句只有在他们真正从一个表中检索行时才需要SELECT权限。一些SELECT语句不访问表,甚至没有任何到服务器上的数据库里的存取任何东西的许可。例如,你可使用mysql客户端作为一个简单的计算器来评估未引用表的表达式:
mysql> SELECT 1+1;
mysql> SELECT PI()*2;
INDEX权限允许你创建或删除索引。INDEX适用已有表。如果你具有某个表的CREATE权限,你可以在CREATE TABLE语句中包括索引定义。
通过ALTER权限,你可以使用ALTER TABLE来更改表的结构和重新命名表。
需要CREATE ROUTINE权限来创建保存的程序(函数和程序),ALTER ROUTINE权限来更改和删除保存的程序,EXECUTE来执行保存的程序。
GRANT权限允许你把你自己拥有的那些权限授给其他的用户。可以用于数据库、表和保存的程序。
FILE权限给予你用LOAD DATA INFILE和SELECT ... INTO OUTFILE语句读和写服务器上的文件,任何被授予FILE权限的用户都能读或写MySQL服务器能读或写的任何文件。(说明用户可以读任何数据库目录下的文件,因为服务器可以访问这些文件)。 FILE权限允许用户在MySQL服务器具有写权限的目录下创建新文件。不能覆盖已有文件。
其余的权限用于管理性操作,它使用mysqladmin程序或SQL语句实施。下表显示每个管理性权限允许你执行的mysqladmin命令:
权限 |
权限拥有者允许执行的命令 |
RELOAD |
flush-hosts, flush-logs, flush-privileges, flush-status, flush-tables, flush-threads, refresh, reload |
SHUTDOWN |
shutdown |
PROCESS |
processlist |
SUPER |
kill |
reload命令告诉服务器将授权表重新读入内存。flush-privileges是reload的同义词,refresh命令清空所有表并打开并关闭记录文件,其它flush-xxx命令执行类似refresh的功能,但是范围更有限,并且在某些情况下可能更好用。例如,如果你只是想清空记录文件,flush-logs比refresh是更好的选择。
shutdown命令关掉服务器。只能从mysqladmin发出命令。没有相应的SQL语句。
processlist命令显示在服务器内执行的线程的信息(即其它账户相关的客户端执行的语句)。kill命令杀死服务器线程。你总是能显示或杀死你自己的线程,但是你需要PROCESS权限来显示或杀死其他用户和SUPER权限启动的线程。参见13.5.5.3节,“KILL语法”。
拥有LOCK TABLES权限便可以直接使用LOCK TABLES语句来锁定你拥有SELECT权限的表。包括使用写锁定,可以防止他人读锁定的表。
拥有REPLICATION CLIENT权限便可以使用SHOW MASTER STATUS和SHOW SLAVE STATUS。
REPLICATION SLAVE权限应授予从服务器所使用的将当前服务器连接为主服务器的账户。没有这个权限,从服务器不能发出对主服务器上的数据库所发出的更新请求。
拥有SHOW DATABASES权限便允许账户使用SHOW DATABASE语句来查看数据库名。没有该权限的账户只能看到他们具有部分权限的数据库, 如果数据库用--skip-show-database选项启动,则根本不能使用这些语句。请注意全局权限指数据库的权限。
总的说来,只授予权限给需要他们的那些用户是好主意,但是你应该在授予FILE和管理权限时试验特定的警告:
有一些事情你不能用MySQL权限系统做到:
当你想要访问MySQL服务器时,MySQL客户端程序一般要求你指定参数:
· MySQL服务器运行的主机名
· 姓名
· 密码
例如,可以从命令行按照下述提示启动MySQL客户端(用shell>表示):
shell> MySQL -h host_name -u user_name -pyour_pass
-h, -u和-p选项还可以采用形式--host=host_name、--user=user_name和--password=your_pass。请注意在-p或--password=和后面的密码之间没有空格。
如果你使用-p或--password选项但没有指定密码值,客户端程序提示你输入密码。当你输入密码时并不显示密码。这比在在命令行输入密码要安全得多。系统上的任何用户可以通过命令ps auxww在命令行中指定密码。参见5.8.6节,“使你的密码安全”。
如果没有指定连接参数,MySQL客户端程序使用默认值:
· 如果没有-p,则不提供密码。
这样, 对Unix用户joe,下列命令是等价的:
shell> MySQL -h localhost -u joe
shell> MySQL -h localhost
shell> MySQL -u joe
shell> MySQL
其它MySQL客户端程序类似。
当进行连接时,你可以指定要使用的不同的默认值,这样不必每次在你调用客户端程序是在命令行上输入它们。这可以有很多方法做到:
· [client]
· host=host_name
· user=user_name
· password=your_pass
在4.3.2节,“使用选项文件”中详细讨论了选项文件。
当你试图连接MySQL服务器时,服务器基于你的身份以及你是否能通过供应正确的密码验证身份来接受或拒绝连接。如果不是,服务器完全拒绝你的访问,否则,服务器接受连接,然后进入阶段2并且等待请求。
你的身份基于2个信息:
身份检查使用3个user表(Host, User和Password)范围列执行。服务器只有在user表记录的Host和User列匹配客户端主机名和用户名并且提供了正确的密码时才接受连接。
在user表Host值的指定方法:
· 对于指定为IP号的Host值,你可以指定一个网络掩码,说明使用多少位地址位来评比网络号。例如:
· mysql> GRANT ALL PRIVILEGES ON db.*
· -> -> TO david@'192.58.197.0/255.255.255.0';
允许david从任何客户端用IP号client_ip来连接,下面的条件为真:
client_ip & netmask = host_ip
That is, for the GRANT statement just shown:
client_ip & 255.255.255.0 = 192.58.197.0
满足该条件并可以连接MySQL服务器的IP号的范围为192.58.197.0到192.58.197.255。
· 注释:网络掩码只用来告诉服务器使用8、16、24或32位地址,例如:
· 192.0.0.0/255.0.0.0(192 A类网络的任何地址)
· 192.168.0.0/255.255.0.0(192.168 A类网络的任何地址)
· 192.168.1.0/255.255.255.0(192.168.1 C类网络的任何地址)
· 192.168.1.1(只有该IP)
下面的网络掩码(28 位)无效:
192.168.0.1/255.255.255.240
· db表记录中的空Host值表示它的权限应结合匹配客户端名的host表中的行使用。通过AND(相与)而不是或(联合)操作将权限组合到一起。你可以从5.7.6节,“访问控制, 阶段2:请求核实”找到关于host表的详细信息。
其它grant表的空Host值与'%'相同。
既然你能在Host字段使用IP通配符值(例如,'144.155.166.%'匹配在一个子网上的每台主机),有可能某人可能企图探究这种能力,通过命名一台主机为144.155.166.somewhere.com。为了阻止这样的企图,MySQL不允许匹配以数字和一个点起始的主机名,这样,如果你用一个命名为类似1.2.foo.com的主机,它的名字决不会匹配授权表中的Host列。只有一个IP数字能匹配IP通配符值。
通配符字符在User列中不允许,但是你能指定空的值,它匹配任何名字。如果user表匹配的连接有一个空用户名,用户被认为是匿名用户(没有名字的用户),而非客户端实际指定的名字。这意味着一个空的用户名被用于在连接期间的进一步的访问检查(即,在阶段2期间)。
Password列可以是空的。这不是通配符,也不意味着匹配任何密码,它意味着用户必须不指定一个密码进行连接。
user表中的非空Password值代表加密的密码。MySQL不以任何人可以看的明文文本格式存储密码,相反,正在试图联接的用户提供的密码被加密(使用PASSWORD( )函数),在连接过程中使用加密的密码检查密码是否正确。(加密后的密码未通过连接即可实现)。从MySQL角度,加密的密码是实际密码,因此你不应让其它人访问它!特别是,绝对不要让非管理用户读mysql数据库中的表!
MySQL 5.1使用强鉴定方法(最先在MySQL 4.1中适用)在前面的版本中在连接进程中的密码保护较好。即使TCP/IP包被截取或mysql数据库 被捕获也很安全。5.7.9节,“MySQL 4.1中的密码哈希处理”中详细讨论了密码加密。
下面的例子显示出各种user表中Host和User值的组合如何应用于到来的连接:
Host值 |
User值 |
被条目匹配的连接 |
'thomas.loc.gov' |
'fred' |
fred, 从thomas.loc.gov 连接 |
'thomas.loc.gov' |
'' |
任何用户, 从thomas.loc.gov连接 |
'%' |
'fred' |
fred, 从任何主机连接 |
'%' |
'' |
任何用户, 从任何主机连接 |
'%.loc.gov' |
'fred' |
fred, 从在loc.gov域的任何主机连接 |
'x.y.%' |
'fred' |
fred, 从x.y.net、x.y.com,x.y.edu等联接。(这或许无用) |
'144.155.166.177' |
'fred' |
fred, 从有144.155.166.177 IP地址的主机连接 |
'144.155.166.%' |
'fred' |
fred, 从144.155.166 C类子网的任何主机连接 |
到来的连接中的客户端名和用户名可能与user表中的多行匹配。例如,由fred从thomas.loc.gov的连接匹配多个条目如上所述。
如果有多个匹配,服务器必须选择使用哪个条目。按照下述方法解决问题:
l 服务器在启动时读入user表后进行排序。
l 然后当用户试图连接时,以排序的顺序浏览条目
l 服务器使用与客户端和用户名匹配的第一行。
user表排序工作如下,假定user表看起来像这样:
+-----------+----------+-
| Host | User | …
+-----------+----------+-
| % | root | …
| % | jeffrey | …
| localhost | root | …
| localhost | | …
+-----------+----------+-
当服务器读取表时,它首先以最具体的Host值排序。主机名和IP号是最具体的。'%'意味着“任何主机”并且是最不特定的。有相同Host值的条目首先以最具体的User值排序(空User值意味着“任何用户”并且是最不特定的)。最终排序的user表看起来像这样:
+-----------+----------+-
| Host | User | …
+-----------+----------+-
| localhost | root | … ...
| localhost | | … ...
| % | jeffrey | … ...
| % | root | … ...
+-----------+----------+-
当客户端试图连接时,服务器浏览排序的条目并使用找到的第一匹配。对于由jeffrey从localhost的连接,表内有两个条目匹配:Host和User值为'localhost'和''的条目,和值为'%'和'jeffrey'的条目。'localhost'条目首先匹配,服务器可以使用。
还有一个例子。假定user表看起来像这样:
+----------------+----------+-
| Host | User | …
+----------------+----------+-
| % | jeffrey | …
| thomas.loc.gov | | …
+----------------+----------+-
排序后的表看起来像这样:
+----------------+----------+-
| Host | User | …
+----------------+----------+-
| thomas.loc.gov | | …
| % | jeffrey | …
+----------------+----------+-
由jeffrey从thomas.loc.gov的连接与第一行匹配,而由jeffrey从whitehouse.gov的连接被第二个匹配。
普遍的误解是认为,对给定的用户名,当服务器试图对连接寻找匹配时,明确命名那个用户的所有条目将首先被使用。这明显不符合事实。先前的例子说明了这点,在那里由jeffrey从thomas.loc.gov的连接没被包含'jeffrey'作为User列值的行匹配,但是由没有用户名的题目匹配!结果是,jeffrey被鉴定为匿名用户,即使他连接时指定了用户名。
如果你能够连接服务器,但你的权限不是你期望的,你可能被鉴定为其它账户。要想找出服务器用来鉴定你的账户,使用CURRENT_USER()函数。它返回user_name@host_name格式的值,说明User和Host 值匹配user表记录。假定jeffrey连接并发出下面的查询:
mysql> SELECT CURRENT_USER();
+----------------+
| CURRENT_USER() |
+----------------+
| @localhost |
+----------------+
这儿显示的结果说明user表行有空的User列值。换句话说,服务器将jeffrey视为匿名用户。
诊断鉴定问题的另一个方法是打印出user表并且手动排序它看看第一个匹配在哪儿进行。又见12.9.3节,“信息函数”。