|
MySQL有一个先进但非标准的安全/权限系统。本文描述它的工作原理。
) m' ]# a0 U. C6 o/ Y% J! d% I6 `( @) L+ E+ _
权限系统做什么
0 }9 Y6 Y7 K( e% ^% bMySQL权限系统的主要功能是证实连接到一台给定主机的一个用户,
1 [* `/ b% w% C8 R# v% y# l. X/ G7 g并且赋予该用户在一个数据库上select、 insert、update和delete的
0 k7 I$ O. V) J( b* f权限。
* V$ V! @/ R* [9 V: k: Y# O/ D2 y; q) @( b
附加的功能包括有一个匿名的用户和对于MySQL特定的功能例如
0 u o" G/ D0 a7 B3 BLOAD DATA INFILE进行授权及管理操作的能力。 . Q* M) q. v* s9 [
7 E; v3 D9 p. {4 G
MySQL 用户名和口令 * d7 u" }* J' j8 `7 d
由MySQL使用用户名和口令的方法与Unix或Windows使用的方式有很 " T9 L) m5 A3 q2 z, n0 r
多不同之处:
8 E+ `# ?- [6 M
& q; I8 u$ x! S6 Y" Z8 OMySQL使用于认证目的的用户名,与Unix用户名(登录名字)或 ; C3 y, k7 u" f# T/ A
Windows用户名无关。缺省地,大多数MySQL客户尝试使用当前Unix用户 9 G4 a; |4 N/ v# x% M2 ~
名作为MySQL用户名登录,但是这仅仅为了方便。客户程序允许用-u或- , V% W4 o( ?/ a$ c& X. s
-user选项指定一个不同的名字,这意味着无论如何你不能使得一个数据 $ H2 g( H0 }4 j
库更安全,除非所有的MySQL用户名都有口令。任何人可以试图用任何名 . `' b0 B+ _( J7 a. L
字连接服务器,而且如果他们指定了没有口令的任何名字,他们将成功。
4 V6 F6 p3 Z& n. h( Y$ ^/ I% PMySQL用户名最长可以是16各字符;典型地,Unix用户名限制为8个字符。
x# V! a3 N' Q: |$ A( t8 [9 {; VMySQL口令与Unix口令没关系。在你使用登录到一台Unix机器口令和你使 & a! H- i N$ K
用在那台机器上存取一个数据库的口令之间没有必要有关联。
6 C: ?2 m4 |/ E( P4 v, W f- {MySQL加密口令使用了一个Unix登录期间所用的不同算法。 , L" _- H) ]( N
0 z. ` f; |) J4 p- J8 N: m与MySQL服务器连接 1 ^" W! R1 D% k' [' G
当你想要存取一个MySQL服务器时,MySQL客户程序一般要求你指定 4 ~" M1 c. H$ m5 O$ B8 o& i, d
连接参数:你想要联接的主机、你的用户名和你的口令。例如,mysql
: W* k: k5 f) ~# ^0 ]& m; R6 I9 C客户可以象这样启动(可选的参数被包括在“[”和“]”之间):
4 D2 H3 _7 |( x( @" H- @
6 O' Y6 o, S" h5 Nshell> mysql [-h host_name][-u user_name][-pyour_pass ] + i) l' m6 o' }0 Y' \
-h, -u和-p选项的另一种形式是--host=host_name、--user= 7 Z+ ]4 P( q0 O7 ~
user_name和--password=your_pass。注意在-p或--password=与跟随它
/ z* V% E1 N) ~- T2 F" X$ p后面的口令之间没有空格。 9 t$ R, R" O! o8 }: `; A: P
) y5 H* I/ |* h" n! b
注意:在命令行上指定一个口令是不安全的!随后在你系统上的任 2 l. g; K1 j) e5 S' I9 x
何用户可以通过打类似这样的命令发现你的口令:ps auxww。
( m* f% v" _) D6 D2 S* |, k0 L: r0 c; J3 x" A
对于命令行没有的联接参数,mysql使用缺省值: # o) S- H5 t! x9 i
: a" `4 F+ | `缺省主机名是localhost。 ' F6 t E. M' u0 M
缺省用户名是你的Unix登录名。
. }, u% |! C& B- p) F如果没有-p,则没有提供口令。
1 i) Q: n- D! w5 Q8 ], D& x这样, 对一个Unix用户joe,下列命令是等价的: 1 f9 R( ~) v( Y' V% ?: L6 w: U8 u
1 |( i+ `+ \$ o. M+ u9 a
shell>mysql -h localhost -u joe 1 Q% O" w/ q1 f3 o# t9 ~5 w
shell>mysql -h localhost " y3 {' T: B7 c' e2 w: R( O
shell>mysql -u joe 4 S, D8 U* s) [! c2 T2 n- d% B W0 \6 y+ n
shell>mysql
/ D* R8 c1 u' p6 a5 x+ V: i: O+ n6 y
其它MySQL客户程序有同样表现。
: T0 N- D% C: d, O5 C& y- S
" Q' n7 o! z, t; |+ l' k! C( `在Unix系统上,当你进行一个连接时,你可以指定要使用的不同的缺 6 N* W# I- p/ B2 `
省值,这样你不必每次在你调用一个客户程序是在命令行上输入他们。这 , I- c" n5 Z7 x2 \' B; E
可以有很多方法做到: % k$ S9 u, }6 d2 V) w3 d$ m- U
& M1 l4 g( N% w V你能在你的主目录下“.my.cnf”的配置文件的[client]小节里指定 0 s& C, ]0 F; q; o+ Q% p
连接参数。文件的相关小节看上去可能像这样: ' `1 ?( L# l" o! j
[client] * ~ |! D) u3 X V( p$ } q, f# s
host=host_name
4 W+ P$ k$ _- Zuser=user_name 0 r3 I9 S( p3 P' r- {
password=your_pass & I4 ~- N3 J2 }3 J y5 A7 C
( @1 F9 J6 u6 }1 _5 Y$ R) V8 k' N你可以用环境变量指定连接参数。主机可用MYSQL_HOST指定,MySQL
3 Y, _$ ^# V: K用户名字可用USER指定(仅对 Windows),口令可用MYSQL_PWD指定(但是
4 i+ C% ?' |4 @9 D这不安全) 。
! n* I8 h/ t" X1 ^- e# A0 `如果连接参数以多种方法被指定,在命令行上被指定的值优先于在配
- x' W R- X. b9 X置文件和环境变量中指定的值,而在配置文件指定的值优先于在环境变量 1 l& W6 a; L0 Y$ F7 `
指定的值。 # T6 P$ P8 A& L7 a( O
2 k5 L; ~) D. `' B* e! B7 D6 N使你的口令安全 ) q- {( b. n1 C: O! i/ T8 d6 k- j
以一种暴露的可被其他用户发现的方式指定你的口令是不妥当的。 b5 s2 J8 {# C4 E/ i& z
当你运行客户程序时,你可以使用下列方法指定你的口令,还有每个方法 + p; x( J) {$ w1 q7 n: s1 y
的风险评估:
6 K+ F j, ^& b9 Q3 k6 n9 z% E- {- ]8 N; Y; L# Y2 E
使用一个在命令行上-pyour_pass或--password=your_pass的选项。
' |9 N8 `) k3 P# A! r/ x& r2 R6 C% d5 W这很方便但是不安全,因为你的口令对系统状态程序(例如ps)变得可见,
9 F# Q7 U8 n. V1 I' Z5 j它可以被其他的用户调用来显示命令行。(一般MySQL客户在他们的初始化
2 w6 t# \! P( w' ^9 s顺序期间用零覆盖命令行参数,但是仍然有一个短暂间隔时间内参数值可 9 t1 E: f+ G* R1 |3 c
见的。)
/ K3 ^: o% C |; j5 g1 O使用一个-p或--password选项(没有指定your_pass值)。在这种情况
3 k. V9 G( b \) u5 i) I8 s8 K下,客户程序请求来自终端的口令:
" v* @5 u% Q- y1 t/ e
, } [% n2 |2 V; Lshell>mysql - u user_name - p
: n6 S4 j9 o/ G/ \/ {/ n" mEnter password: ******** : B1 ~: y8 z( C# D0 Y: N
* H6 d9 \2 g4 w
客户回应“*”字符到作为输入你的口令的终端使得旁观者不能看见
$ I# P0 W, f( z* h它。因为它对其他用户不可见,与在命令行上指定它相比,这样进入你 1 ]; [% k& U+ ^/ m0 N! j9 z% g
的口令更安全。然而,这个输入一个口令的方法仅仅为你交互式运行程
' B, f0 o8 E, u0 S% ]9 ~0 `序是合适的。如果你想要从非交互式运行的一个脚本调用一个客户,就
1 n- t7 c) ~$ F# E3 r没有从终端输入入口令的机会。 1 i0 k& U2 P) L7 [1 Z- h! A1 V
6 z5 o8 J! e w a( ^# W# B在一个配置文件中存储你的口令。例如,你可你的主目录的 & [; k7 c5 y; D* l" b
“.my.cnf”文件中的[client]节列出你的口令: / w9 m& q* X& Z6 ~" o
[client] 2 p' f3 h2 Y9 l2 ^$ j7 C1 @
password=your_pass ' n& t+ w; u) W8 |* U! E" |
N- k6 b8 b$ F- }4 ^* j2 d( E% h h( k如果你在“.my.cnf”里面存储口令,文件应该不是组或世界可读或 7 [, b/ T$ T4 B. u7 o6 V6 S' H4 P
可写的。保证文件的存取模式是400或600。见4.15.4 选项文件。
& R. A2 y- w! ~) X, P7 o: Z6 k/ S" ^, o) c) Y z
你可在MYSQL_PWD环境变量中存储口令,但是这个方法必须想到是极
7 i0 l" U; O5 N9 ?3 G5 q: [6 m不安全的且应该不使用。ps的某些版本包括显示运行进程的环境的选项; 0 L6 P6 Q- `, e2 X
如果你设定MYSQL_PWD,你的口令将对所有人是显而易见的,甚至在没有
' w8 @% C% q! B: h" ?5 r+ e, F k这样一个版本的ps系统上,假设没有其他方法观察到进程环境是不明智 ' W7 U5 s$ ~" g$ W) B9 _0 }4 m
的。 # L0 I, D" g5 f, P
总之,最安全的方法是让客户程序提示口令或在一个适当保护的“
* D+ p2 R+ e- t: w+ ?6 [.my.cnf”文件中指定口令。
; J6 C6 z( |0 p5 c4 o% @, n. V, l& F' _
' n6 \! S1 V s; I2 GMySQL提供的权限
) q) ~( ]9 Z( A9 g1 Q' Z" l1 n, x4 j% w权限信息用user、db、host、tables_priv和columns_priv表被存储 6 h( m3 D' l5 @1 b; I/ `7 R8 i
在mysql数据库中(即在名为mysql的数据库中)。在MySQL启动时和在权限
, l% r/ i, O: z修改何时生效所说的情况时,服务器读入这些数据库表内容。
( @/ i D! m8 D2 N. o% Z8 K
9 ]3 y2 r6 r Y. e+ S& _+ B. X由MySQL提供的权限名称显示在下表,还有在授权表中每个权限的表 7 b0 Z: Z" [4 S, ^
列名称和每个权限有关的上下文:
( \& w0 Q5 k- P0 z+ x权限 列 上下文 select Select_priv 表 insert Insert_priv 表 update Update_priv 表 delete Delete_priv 表 index Index_priv 表 alter Alter_priv 表 create Create_priv 数据库、表或索引 drop Drop_priv 数据库或表 grant Grant_priv 数据库或表 references References_priv 数据库或表 reload Reload_priv 服务器管理 shutdown Shutdown_priv 服务器管理 process Process_priv 服务器管理 file File_priv 在服务器上的文件存取
: I( @- t# g0 b/ \& y9 I zselect、insert、update和delete权限允许你在一个数据库现有的
0 t7 ]* ]% g% P表上实施操作。 ) f* B5 w0 B& Z$ w7 g+ a: J3 t
' L7 e$ c [ q$ c, e1 w
SELECT语句只有在他们真正从一个表中检索行是才需要select权限,
( n- e0 ]8 l4 p3 X9 z0 S) [你可以执行某个SELECT语句,甚至没有任何到服务器上的数据库里的存
4 E. N9 A# C4 X取任何东西的许可。例如,你可使用mysql客户作为一个简单的计算器: 1 Y- y( Q: @- m# m5 E
$ v& L, e& o- s. a4 J3 _9 m
mysql> SELECT 1+1; 0 o& p1 {+ e: g4 I
mysql> SELECT PI()*2;
4 p( ]+ Z5 [( P( ^8 }
: T6 `+ i- [0 j1 v& kindex权限允许你创建或抛弃(删除)索引。
2 b8 E& G3 q9 u8 t5 t! d" z7 e6 b, M$ `
5 `1 w! w7 [9 Dalter权限允许你使用ALTER TABLE。 9 c: x4 M) S1 |5 j; N
3 w x6 f! q6 h; i- J
create和drop权限允许你创建新的数据库和表,或抛弃(删除)现存的 ( J' `2 p B0 w+ S, m
数据库和表。 7 j* q2 ?* r' J, s1 [ o* H
5 D5 W. |1 q6 N5 o3 O1 h) r" }3 d7 }
注意:如果你将mysql数据库的drop权限授予一个用户,该用户能抛弃 ( }/ X' f7 v" u T& x }$ o' n9 D) P
存储了MySQL存取权限的数据库! , T/ [9 ^2 {: h
1 i' p' g( r# v& G( M7 W7 q7 h. rgrant权限允许你把你自己拥有的那些权限授给其他的用户。
% R7 o! E5 A& H
' N6 q. r3 O) _- b# cfile权限给予你用LOAD DATA INFILE和SELECT ... INTO OUTFILE语句
6 L8 m5 e/ o) S6 V读和写服务器上的文件,任何被授予这个权限的用户都能读或写MySQL服务
! }9 l8 A7 d. M; d b3 W) L器能读或写的任何文件。 3 |) t4 ?; r9 s0 R9 _4 r
+ ?" Y; S' c9 }" L( X其余的权限用于管理性操作,它使用mysqladmin程序实施。下表显示 # }4 A/ ~3 o: k2 u
mysqladmin支配每个管理性权限允许你执行的命令:
, m3 C# q# ~7 J7 p. H优惠 权限拥有者允许执行的命令 reload reload, refresh, flush-privileges, flush-hosts, flush-logs, flush-tables shutdown shutdown precess processlist, kill
. h6 Q3 U6 Q9 l6 Qreload命令告诉服务器再读入授权表,refresh命令清洗所有表并打开 W7 t9 c- d. p" ?% b0 u
和关闭记录文件,flush-privileges是reload的一个同义词,其它flush-*
/ }# L) W8 m0 I" {命令执行类似refresh的功能,但是范围更有限,并且在某些情况下可能更 * {6 _3 }# m$ E
好用。例如,如果你只是想清洗记录文件,flush-logs比refresh是更好的 ' v6 @+ i( j. x2 d$ q
选择。
: L+ o7 g/ n; H, w0 D8 I
$ `6 i# b! V- Z# U1 [; S' ^' Sshutdown命令关掉服务器。 4 H7 F9 Q% F- k
' V+ H3 j9 X0 k: z7 T( V
processlist命令显示在服务器内执行的线程的信息。kill命令杀死服 + n3 V: j3 U1 }; E
务器线程。你总是能显示或杀死你自己的线程,但是你需要process权限来
: C/ p) Z- ~5 G! m% h显示或杀死其他用户启动的线程。
! F4 O. ^- S: f" O2 Y3 ]2 Z5 L2 S$ g. q: m
总的说来,只授予权限给需要他们的那些用户是一个好主意,但是你
% z4 B" O" j; b3 A% p应该在授予某个权限时试验特定的警告: ! U" b" w/ n# F" f! K$ `7 ?' A
8 ?: N% q3 U4 r5 y: H5 M$ A) v; h2 a2 G7 jgrant权限允许用户放弃他们的权限给其他用户。2个有不同的权限并 2 l2 t0 u% e& f* Y# R
有grant权限的用户可以合并权限。 / r$ N. t5 n7 r2 S1 Q
alter权限可以用于通过重新命名表来推翻权限系统。
+ {, {( K$ Z, ?6 ofile权限可以被滥用在服务器上读取任何世界可读(world-readable,
% D6 s/ H; b2 C n即任何人可读)的文件到一张数据库表,然后其内容能用SELECT被存取。
* j, A6 L) f6 E; M, O& v6 K# G: Qshutdown权限通过终止服务器可以被滥用完全拒绝为其他用户服务。
) K/ u) E" O% N* Iprecess权限能被用来察看当前执行的查询的普通文本,包括设定或改
3 Y) S! g2 m4 A: _3 y0 |* k9 n变口令查询。
) \& u: l4 `, r: ~6 C- m在mysql数据库上的权限能被用来改变口令和其他存取权限信息。(口 8 |0 D. [9 x9 K3 ]& d5 R/ I8 s
令被加密存储,所以一个恶意的用户不能简单地读取他们。然而,有足够 4 S6 u- h7 A6 }6 q8 V) c
的权限,同一个用户能用不同的一个代替一个口令。) 2 j3 g; `4 G, z& n9 L
有一些事情你不能用MySQL权限系统做到:
/ H* `* t$ V6 x- l
3 C! S6 v+ K5 w+ G: O- a& A9 u# [ M你不能明显地指定一个给定用户应该被拒绝存取。即,你不能明显地匹
1 ]4 R* q# n4 B+ P+ A配一个用户并且然后拒绝连接。 1 [2 k+ o0 D9 b, M2 `) B: _
你不能指定一个用户有权创建立或抛弃一个数据库中的表,也不能创建 % h! g2 ]. k* I. J, K3 l
或抛弃数据库本身。 8 B% z2 C8 `$ O- @, m; t6 Q/ v
权限系统工作原理
6 `, M! f5 J* x1 T5 a7 ?MySQL权限系统保证所有的用户可以严格地做他们假定被允许做的事情。
5 W& f: z; n. l# |9 U+ ]" w5 k当你连接一个MySQL服务器时, 你的身份由你从那连接的主机和你指定的用 0 p' V$ {/ C3 p+ j6 `4 e/ R
户名来决定,系统根据你的身份和你想做什么来授予权限。
. ]; U6 Y/ ]) K
J3 ~- l. T: k* O! r( H+ J) GMySQL在认定身份中考虑你的主机名和用户名字,是因为有很小的原因假
8 e& k/ C8 ?* {定一个给定的用户在因特网上属于同一个人。例如,用户从whitehouse.gov 0 _* J' d/ ]/ r0 V( n
连接的bill不必和从mosoft.com连接bill是同一个人。 MySQL通过允许你区 ) V% X! [ X8 N: J
分在不同的主机上碰巧有同样名字用户来处理它:你可以对从whitehouse.gov
: j, [% e6 ]6 {0 B2 @连接授与bill一个权限集,而为从microsoft.com的连接授予一个不同的权限 8 }( O u4 c$ i _4 P
集。
% h3 ?2 b# ~8 N6 x* Y* H
- `3 e7 ]9 q. m m p! ?) }- CMySQL存取控制包含2个阶段:
2 a& w* I& A5 L, Q/ G! t) Z2 g+ z7 D1 t! r( h) ?
阶段1:服务器检查你是否允许连接。
) @& \* W$ D' R" s8 `) n$ Z1 ~阶段2:假定你能连接,服务器检查你发出的每个请求。看你是否有足够
W* C1 O2 F& [1 n. |- R的权限实施它。例如,如果你从数据库中一个表精选(select)行或从数据库抛
* U3 b J r5 \弃一个表,服务器确定你对表有select权限或对数据库有drop权限。
" P6 O6 t& J2 G" F3 C服务器在存取控制的两个阶段使用在mysql的数据库中的user、db和host
# q/ w; p) M. G( S( F3 |/ M表,在这些授权表中字段如下:
4 l. u: [: Z& H0 @7 @表名称 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 Reload_priv Shutdown_priv Process_priv File_priv : J; a/ l6 P0 M: |2 W
对存取控制的第二阶段(请求证实),如果请求涉及表,服务器可以另外 $ @4 J6 L0 s& q6 l
参考tables_priv和columns_priv表。这些表的
) F# s, B# h$ B字段如下: : H9 Z1 [. j/ j; ^
表名称 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
- S p2 }9 U+ c' s对存取控制的第二阶段(请求证实),如果请求涉及表,服务器可以另外
' M9 J) v( c) ?# N# \( G O参考tables_priv和columns_priv表。这些表的字段如下: 2 `" c4 o- `4 v5 T! l1 L' J: h$ C
字段名 类型 Host CHAR(60) User CHAR(16) Password CHAR(16) Db CHAR(64) (tables_priv和columns_priv表为CHAR(60)) $ F- J' ~/ J( L0 u$ e
在user、db和host表中,
7 b( I* Q3 f0 S' n' S- j所有权限字段被声明为ENUM('N','Y')--每一个都可有值
2 N5 m) c- N2 E& `7 A/ ~7 @'N'或'Y',并且缺省值是'N'.
" y9 A) P' O. E' s# j在tables_priv和columns_priv表中,权
) ~0 ~# ^$ M! ~' `4 T限字段被声明为SET字段: ) ~8 H/ I. ^- V4 F
表名 字段名 可能的集合成员 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'
3 V1 M* U/ o- c' z$ K! {每个授权表包含范围字段和权限字段。 1 @9 ^3 A( [% s: d
1 B7 P" z& e% G范围字段决定表中每个条目的范围,即,条目适用的上下文。例如, . x2 \) D# a6 i; B+ P" B2 I
一个user表条目的Host和User值为'thomas.loc.gov'和'bob'将被用于 / U( H2 }! V2 F6 ~
证实来自主机thomas.loc.gov的bob对服务器的连接。同样,一个db表条 " A4 w9 g- f' J
目的Host、User和Db字段的值是'thomas.loc.gov'、'bob'和'reports'
: R' D: k% }( Y将用在bob从主机联接thomas.loc.gov存取reports数据库的时候。
5 Q$ x. h7 R+ p5 V C7 _/ atables_priv和columns_priv表包含范围字段,指出每个条目适用的表或 5 _- f8 s& K# _ }" h- L& h
表/列的组合。 8 ^9 r' E( @) Y! i0 l
& S+ j( p3 J) l
对于检查存取的用途,比较Host值是忽略大小写的。User、Password、
2 A) w X8 w3 E0 K3 P2 y/ F' i, aDb和Table_name值是区分大小写的。Column_name值在MySQL3.22.12或以
$ ^, S& W5 `, n7 n3 i. X$ Q后版本是忽略大小写的。
/ O2 |" {5 j8 R' M! W% x
# u( q, H; C# J# Z; L: `% \2 M; v权限字段指出由一个表条目授予的权限,即,可实施什么操作。服务
6 Z2 P8 q8 K8 |; ~器组合各种的授权表的信息形成一个用户权限的完整描述。为此使用的规 6 Y9 k7 e) \% J% x+ F0 S
则在6.8 存取控制, 阶段2:请求证实描述。
, L- ^* f. {# Y( d2 _7 R, _6 A- p) T7 ~* v; y' z& U. b+ L* P
范围字段是字符串,如下所述;每个字段的缺省值是空字符串:
1 ~2 |7 \/ o: H3 `8 V$ @字段名 类型 Host CHAR(60) User CHAR(16) Password CHAR(16) Db CHAR(64) (tables_priv和columns_priv表为CHAR(60)) ' r1 p7 O' a7 O5 O% K X& d, @: T
在user、db和host表中,所有权限字段被声明为ENUM('N','Y')--每一
7 R4 `4 C- x0 e6 ?5 B2 b: e个都可有值'N'或'Y',并且缺省值是'N'.
' ?1 m% z" e& ?! [+ @' R! ~( b
在tables_priv和columns_priv表中,权限字段被声明为SET字段:
! K0 ~5 `4 i$ D6 f表名 字段名 可能的集合成员 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' 0 ?0 o5 f1 _9 E+ e$ B* A
简单地说,服务器使用这样的授权表: ) f% e L; ?, E8 |1 ~6 _, b9 Q3 H
$ T F' J* w; z
user表范围字段决定是否允许或拒绝到来的连接。对于允许的连接, 9 a. c! R8 ~' L
权限字段指出用户的全局(超级用户)权限。
% _0 @1 o) B% Cdb和host表一起使用:
1 W/ q' ]5 e, |# Ndb表范围字段决定用户能从哪个主机存取哪个数据库。权限字段决定 , L& X5 R9 m: C
允许哪个操作。 8 E& S$ F$ c4 S3 x
当你想要一个给定的db条目应用于若干主机时,host表作为db表的扩 * v' W: f- U* E) b6 i, k
展被使用。例如,如果你想要一个用户能在你的网络从若干主机使用一个
4 N r# V( @" u Z8 A E4 m% G数据库,在用户的db表的Host条目设为空值,然后将那些主机的每一个移 - X* N; K) G1 n, H5 _( o c
入host表。这个机制详细描述在6.8 存取控制, 阶段2:请求证实。
t5 g5 u* c: stables_priv和columns_priv表类似于db表,但是更精致:他们在表
# |5 o' x& @+ q( |和列级应用而非在数据库级。
- K, a- k, u8 U% s7 n- u7 b) f6 O注意管理权限(reload, shutdown, 等等)仅在user表中被指定。这是
% S7 `8 b F4 {# O" t, @5 `因为管理性操作是服务器本身的操作并且不是特定数据库,因此没有理由 0 g% z) P) v; a N3 I2 D9 y
在其他授权表中列出这样的权限。事实上,只需要请教user表来决定你是
6 P1 S. k! X6 L$ Q6 U! S! H否执行一个管理操作。
2 k( N% ~: S# T3 I8 G8 R% I7 G$ I) L! g( y, D# Z; { u+ B0 `# x
file权限也仅在user表中指定。它不是管理性权限,但你读或谢在服 ! k' f. ]8 Y# l" q4 V+ b
务器主机上的文件的的能力独立于你正在存取的数据库。 % C% Y# c: J# @# V8 e R8 R
' B+ N& e" W, _5 e: `/ f
当mysqld服务器启动时,读取一次授权表内容。
1 {( R1 b, j# c. U4 Q5 ^* s% i2 n$ m% I# _: W# M3 r. e
当你修改授权表的内容时,确保你按你想要的方式更改权限设置是一 0 _: G6 D6 L ?+ j" m1 r! s0 X- |
个好主意。
. x d- [% P0 s* x) b# F4 g/ `3 j
: F7 M7 l; \5 p一个有用的诊断工具是mysqlaccess脚本,由Carlier Yves 提供给
" U) C! U+ ]' D0 I [; K. m0 t7 mMySQL分发。使用--help选项调用mysqlaccess查明它怎样工作。注意:
+ m, a7 a( D- H4 b4 g& N& Omysqlaccess仅用user、db和host表仅检查存取。它不检查表或列级权限。
0 N4 ?7 k8 Q$ p4 s, t/ m1 l5 t5 H' j5 p) G& T& p' [5 G
存取控制, 阶段1:连接证实 ; O' I; S6 T) N2 I% M( U% J
当你试图联接一个MySQL服务器时,服务器基于你的身份和你是否能 - ?( n+ |( g/ a2 t
通过供应正确的口令验证身份来接受或拒绝连接。如果不是,服务器完全
) {! k/ m+ G6 ], |4 ~/ t0 b具结你的存取,否则,服务器接受连接,然后进入阶段2并且等待请求。 7 S" ]2 r' p! _9 C" m/ ?0 E' x
, M. v& }5 U) w
你的身份基于2个信息: , x% a ?) P( E
0 E/ j( O8 u. L4 {你从那个主机连接
' |/ [$ l2 o5 z; \$ B你的MySQL用户名
" U7 L& ~- g! j" E" J2 ?身份检查使用3个user表(Host, User和Password)范围字段执行。服
% [1 w+ o8 M! Q务器只有在一个user表条目匹配你的主机名和用户名并且你提供了正确的 ( O( _/ ?, D' W4 v( v: @
口令时才接受连接。 8 A: | o9 {. R
" c+ x1 D0 O6 Z
在user表范围字段可以如下被指定: % m9 o9 z9 x \* |+ S* T
& M, ~8 g% r2 {: u' n9 A一个Host值可以是主机名或一个IP数字,或'localhost'指出本地主机。
6 T0 V$ ]5 C- Y o# j/ H+ p你可以在Host字段里使用通配符字符“%”和“_”。 * @/ w' C1 t" F# f+ G6 z
一个Host值'%'匹配任何主机名,一个空白Host值等价于'%'。注意这些
4 A* `& Y9 \9 P7 ^3 m+ Z- m. Z) k值匹配能创建一个连接到你的服务器的任何主机! 3 j9 h1 f# h7 E l
通配符字符在User字段中不允许,但是你能指定空白的值,它匹配任何 % n* W4 B/ Y i3 w4 i Q3 D/ k
名字。如果user表匹配到来的连接的条目有一个空白的用户名,用户被认为
9 F1 @) u6 Z- R, b) D是匿名用户(没有名字的用户),而非客户实际指定的名字。这意味着一个空
9 M% m3 v& ~ |# R$ J+ o3 v白的用户名被用于在连接期间的进一步的存取检查(即,在阶段2期间)。 ; {2 i3 t# W1 U) P
Password字段可以是空白的。这不意味着匹配任何口令,它意味着用户 2 l+ R9 s& v' R) n9 @( V. I; Z2 N
必须不指定一个口令进行连接。
. W1 B- j% L3 Y- E# G% W$ d非空白Password值代表加密的口令。 MySQL不以任何人可以看的纯文本 * ]6 t% `6 k$ E& I) d( n
格式存储口令,相反,正在试图联接的一个用户提供的口令被加密(使用
% n- `7 t& ]& g \! EPASSWORD()函数),并且与存储了user表中的已经加密的版本比较。如果他
' l! ]6 b, | _4 t' c l1 F) x们匹配,口令是正确的。 Z+ J4 i8 Z, h. b l8 |5 l" C5 t8 I
, V( f; w6 Y. T) L8 x$ h9 X( v下面的例子显示出各种user表中Host和User条目的值的组合如何应用于到来
- H! T3 u. j0 r+ m5 |6 E: i的连接: 1 t; J2 i k5 V8 @5 [, W
0 A7 W) v6 V( U( j: [
Host 值 User 值 被条目匹配的连接 ( Y; \) _ C1 _9 }
'thomas.loc.gov' 'fred' fred, 从thomas.loc.gov 连接
3 ]5 H3 V$ O$ t* M5 Q'thomas.loc.gov' '' 任何用户, 从thomas.loc.gov连接
) C1 u' L7 @1 J) C: w; W'%' 'fred' fred, 从任何主机连接
* Q$ I4 c2 T7 O'%' '' 任何用户, 从任何主机连接
9 ?- u7 S) I! q: O+ w'%.loc.gov' 'fred' fred, 从在loc.gov域的任何主机连接 . L: }/ `2 o- v
'x.y.%' 'fred' fred, 从x.y.net、x.y.com,x.y.edu等联接。(这或许
5 X' M: N. r+ Z+ D8 T无用)
' l" D5 W9 `) y9 d3 N* Y% N8 p) U'144.155.166.177' 'fred' fred, 从有144.155.166.177 IP 地址的主 6 [' U2 u' q+ T2 ?- g0 q$ a' G
机连接 , L+ W' e2 B* C
'144.155.166.%' 'fred' fred, 从144.155.166 C类子网的任何主机连
: Y/ i) @# S1 c" G2 Q接
& \8 n5 Q# n5 c
1 g" ~2 v. b# W! ^3 b9 t Q3 g M既然你能在Host字段使用IP通配符值(例如,'144.155.166.%'匹配在一个子 $ F4 n* {: ^; d, c) I
网上的每台主机),有可能某人可能企图探究这种能力,通过命名一台主机
. g1 i) i0 v- `# u" b- j为144.155.166.somewhere.com。为了阻止这样的企图,MySQL不允许匹配以
0 \5 R1 C2 q2 S" a数字和一个点起始的主机名,这样,如果你用一个命名为类似1.2.foo.com的 % H' {5 ^' H' _1 v k
主机,它的名字决不会匹配授权表中Host列。只有一个IP数字能匹配IP通配
, H* q0 i* c# z$ U' o! f8 U1 _符值。 4 u, T6 {$ K$ F' S: A( F
& o5 R6 ^# T I6 o; }; d一个到来的连接可以被在user表中的超过一个条目匹配。例如,一个由 ; S7 a6 f+ C, e$ {! Z0 \ a
fred从thomas.loc.gov的连接匹配多个条目如上所述。如果超过一个匹配, : k; v+ N9 W" E+ }( P
服务器怎么选择使用哪个条目呢?服务器在启动时读入user表后通过排序来 " }; i" `' y1 a$ R! S
解决这个问题,然后当一个用户试图连接时,以排序的顺序浏览条目,第一
L: D# k% ]2 @1 W' D |个匹配的条目被使用。 0 i$ A8 | A7 [2 p, `
( m# K+ e; W) o% b; ]user表排序工作如下,假定user表看起来像这样:
% J' W' k% | s. }9 d+ P2 W8 s5 Q4 F8 d6 V% {
, ^" {7 T8 o' M# a# K. B
+-----------+----------+- 3 a- d9 S+ K" A- k
│ Host │ User │ ...
4 y, P- v9 [& L ~; f4 w b+-----------+----------+-
0 y5 m4 @3 `; W│ % │ root │ ...
6 P' _6 m& r: ?5 B6 e0 R│ % │ jeffrey │ ... . `3 Z: w6 o" i6 R( H
│ localhost │ root │ ... ' n. x7 _3 W/ C ?( B; O# i
│ localhost │ │ ... 5 u) u1 A0 }( E; c
+-----------+----------+-
" c' A( |6 [$ ]7 s9 g" r2 G0 y4 K$ H, Z4 m
当服务器在表中读取时,它以最特定的Host值为先的次序排列('%'在 : z* f5 j' M% d5 E0 X8 U
Host列里意味着“任何主机”并且是最不特定的)。有相同Host值的条目以
% r# }( \$ O! w; P8 c最特定的User值为先的次序排列(一个空白User值意味着“任何用户”并且 $ C9 \ i6 b W
是最不特定的)。最终排序的user表看起来像这样:
& K( ]0 z& i6 Y" h4 V+ I `( d4 n- I# x
+ t9 C+ A5 i' P% A( O
+-----------+----------+-
8 b+ e: a" x/ P) F. U. T│ Host │ User │ ... # X. T5 K" a( j, n. m+ M! k
+-----------+----------+-
. c$ E# R$ J* a7 `. L│ localhost │ root │ ... & ?( }) O) V+ a7 n: Z+ g ~
│ localhost │ │ ...
' v6 }/ I, Q0 _; Z│ % │ jeffrey │ ... , l4 N" I! ~. P- t7 m5 c) g
│ % │ root │ ...
5 u* L0 t; U8 T* a5 I+-----------+----------+- : Q! H B. {3 o0 {: l9 v3 P- R
1 A' E0 w& _# L2 j6 [$ Y% P
当一个连接被尝试时,服务器浏览排序的条目并使用找到的第一个匹
. y0 a3 [7 w8 D/ |& _配。对于由jeffrey从localhost的一个连接,在Host列的'localhost'条目
f, D! t4 P0 a5 p$ d3 t首先匹配。那些有空白用户名的条目匹配连接的主机名和用户名。('%'/ + [, M0 \9 {! `0 W/ J
'jeffrey'条目也将匹配,但是它不是在表中的第一匹配。) 2 |& V! q# r; S& H9 g+ J9 X
, \2 [& Z4 U4 X0 O" v( ]1 H这是另外一个例子。假定user桌子看起来像这样:
* H) }: e/ ]& o+ m/ i
& T- G' V* N" A! I( S7 ?
% S7 W5 @7 u$ q+ F k' ~+----------------+----------+-
{' \& n1 q# A7 Z: O0 n- |│ Host │ User │ ... # |# R( S" B5 A! p; h) f
+----------------+----------+-
* d, R* M6 d+ u- _$ R0 ]│ % │ jeffrey │ ... ! s! U0 K0 I7 K7 `5 L# X Q* @
│ thomas.loc.gov │ │ ...
4 ^4 H: J% S; V5 i% Z+----------------+----------+-
# \% M" t+ Y4 Y N r6 r
! c* l! c$ |: F9 i& d- M; q/ k( |排序后的表看起来像这样: % s& m) g9 o! m0 G& {
$ D# u3 C7 \1 _
. P# n K6 o% E" H+----------------+----------+- / r9 ?$ R2 |9 Q1 w' y
│ Host │ User │ ...
0 d9 G! d" k4 c2 j2 w+----------------+----------+- ' U* X/ |' @1 W( @% \% o* |; O* v
│ thomas.loc.gov │ │ ... ) K. S7 l* J; U
│ % │ jeffrey │ ...
; L, } x' k5 u$ a- d! l* Y+----------------+----------+- / e7 q0 e2 s7 w4 i' H$ Y1 C
; M4 \4 v6 ~4 W, \" X1 b+ [( I
一个由jeffrey从thomas.loc.gov的连接被第一个条目匹配,而一个由
" a7 D$ P- Y/ [jeffrey从whitehouse.gov的连接被第二个匹配。
0 t6 V3 F0 h6 e+ ?7 n, M2 O2 I5 R3 f7 r( W: {3 R; }" K9 G
普遍的误解是认为,对一个给定的用户名,当服务器试图对连接寻找
( N C1 F; x% [匹配时,明确命名那个用户的所有条目将首先被使用。这明显不是事实。
6 ], _* q' M: U# ^先前的例子说明了这点,在那里一个由jeffrey从thomas.loc.gov的连接没 ' _2 h) x& I% ~1 w; ]2 A
被包含'jeffrey'作为User字段值的条目匹配,但是由没有用户名的题目匹 - X9 s, n& P0 ]
配!
_3 o" _9 s) H" c, i
2 G7 f7 C/ Y: t* I: n9 h% q如果你有服务器连接的问题,打印出user表并且手工排序它看看第一个 ; q n0 y5 ]9 K- E+ T; f
匹配在哪儿进行。
( G% _! ]7 [: g- e. r/ q P- B$ t! H/ T+ n
存取控制,阶段2:请求证实
( N! Z* {9 Q* ` D$ j+ x# J8 h- K8 E一旦你建立了一个连接,服务器进入阶段2。对在此连接上进来的每个 , Y# F, e( ^. A& c x& t S6 r G4 {! Z
请求,服务器检查你是否有足够的权限来执行它,它基于你希望执行的操作 5 i2 E: z. J* c+ Z
类型。这正是在授权表中的权限字段发挥作用的地方。这些权限可以来子
9 e% _& Q+ y0 Z6 V# y7 W- B$ V6 {0 Guser、db、host、tables_priv或columns_priv表的任何一个。授权表用 * { f2 P* Y' v5 l+ }
GRANT和REVOKE命令操作。见7.26 GRANT和REVOKE 句法。(你可以发觉参
7 Z6 q1 Y1 G- D* {& z考6.6 权限系统怎样工作很有帮助,它列出了在每个权限表中呈现的字段。)
5 R3 {9 B& X' Z$ E, q: u4 W4 N2 t" f: Q& A& E! j
user表在一个全局基础上授予赋予你的权限,该权限不管当前的数据库 - @' e# n5 a( G2 S6 ~1 _& a
是什么均适用。例如,如果user表授予你delete权限, 你可以删除在服务器
2 j o3 Z3 R- ]% d' \7 U/ B& Z H主机上从任何数据库删除行!换句话说,user表权限是超级用户权限。只把
# U- O6 N+ ?+ ^; l4 cuser表的权限授予超级用户如服务器或数据库主管是明智的。对其他用户, " p- m. a$ R! b5 Z
你应该把在user表中的权限设成'N'并且仅在一个特定数据库的基础上授权, - G% \0 \- S0 s; d
使用db和host表。 # O% h0 J0 Q, U; E# ]2 U1 |0 J
! H( u3 t% O: z
db和host表授予数据库特定的权限。在范围字段的值可以如下被指定:
9 [& a- i; a3 z9 s H+ C
: v5 G( p8 @1 g" n# X K8 ?( g通配符字符“%”和“_”可被用于两个表的Host和Db字段。 8 z, U: T: T% {) I* ]
在db表的'%'Host值意味着“任何主机”,在db表中一个空白Host值意味 , e3 r: ]: {2 D( K
着“对进一步的信息咨询host表”。
8 E, b5 u# a! x3 o' z在host表的一个'%'或空白Host值意味着“任何主机”。 9 T# W4 O8 W- D/ O4 }9 y
在两个表中的一个'%'或空白Db值意味着“任何数据库”。 ( y; j9 F) o: l! L4 h: L
在两个表中的一个空白User值匹配匿名用户。
* \7 M1 Q/ q6 O! H# ^" z# o( Cdb和host表在服务器启动时被读取和排序(同时它读user表)。db表在Host
; S5 _' y% R$ L/ y9 ]、Db和User范围字段上排序,并且host表在Host和Db范围字段上排序。对于
* o, d- s) m( [$ z% G) W' tuser表,排序首先放置最特定的值然后最后最不特定的值,并且当服务器寻找 $ n. ^# |2 l; l' k
匹配入条目时,它使用它找到的第一个匹配。 ; b& E! S4 E7 E# {
0 n3 t! p' l. Rtables_priv和columns_priv表授予表和列特定的权限。在范围字段的值可
: ^2 S' `; ]) T以如下被指定:
! Q% x. } f! F2 l/ C0 I- s I, s a0 f5 O% s" y9 ^
通配符“%”和“_”可用在使用在两个表的Host字段。
+ W( O0 |& ^2 `在两个表中的一个'%'或空白Host意味着“任何主机”。 2 |5 d( i x/ l( g$ s
在两个表中的Db、Table_name和Column_name字段不能包含通配符或空白。
+ O u5 _; j; K' x0 ?2 H* `tables_priv和columns_priv表在Host、Db和User字段上被排序。这类似于
9 I9 A' O) b. T9 Mdb表的排序,尽管因为只有Host字段可以包含通配符,但排序更简单。
3 p% n7 N& L% d3 ^% L" a& A! K/ H8 X/ T1 U0 Y B% |; ^, Y2 U
请求证实进程在下面描述。(如果你熟悉存取检查的源代码,你会注意到这 4 h; x" A, k4 `! ?
里的描述与在代码使用的算法略有不同。描述等价于代码实际做的东西;它只是 1 M3 s" r* j( k- s# P8 o
不同于使解释更简单。)
1 M+ Q" R3 ?. {3 F
4 p6 ?, z* d! e! a+ O/ m, O对管理请求(shutdown、reload等等),服务器仅检查user表条目,因为那是 ( O/ H/ D+ {7 r: c3 R
唯一指定管理权限的表。如果条目许可请求的操作,存取被授权了,否则拒绝。 3 H x2 A, y1 [3 n; H1 I
例如,如果你想要执行mysqladmin shutdown,但是你的user表条目没有为你授 , k! X7 P0 d) P, i
予shutdown权限,存取甚至不用检查db或host表就被拒绝。(因为他们不包含
# X; i0 w2 V$ o3 T5 v9 _. V, NShutdown_priv行列,没有这样做的必要。) 3 Z: a, W( k2 l1 o2 \' l3 g
9 E$ P/ H( M9 T( X' N3 O+ `对数据库有关的请求(insert、update等等),服务器首先通过查找user表 9 t- E8 J# U1 [$ l( I& X8 o
条目来检查用户的全局(超级用户)权限。如果条目允许请求的操作,存取被授
! V" }1 _9 S( d+ [& F& R权。如果在user表中全局权限不够,服务器通过检查db和host表确定特定的用
6 D$ g# K, {) B7 C/ `$ E4 ?) g1 S户数据库权限: # \2 v7 ^ j6 i/ f' ]1 a' G8 f; M
1 R1 t" x; F$ D: J( \服务器在db表的Host、Db和User字段上查找一个匹配。 Host和User对应连
9 K8 H/ I# i7 u$ B( [4 m- R接用户的主机名和MySQL用户名。Db字段对应用户想要存取的数据库。如果没有
2 V2 C& y$ ~. k' \* `. [/ s% n% ~Host和User的条目,存取被拒绝。 9 g0 B% v3 v6 Y0 K, O
如果db表中的条目有一个匹配而且它的Host字段不是空白的,该条目定义用 9 {7 T' c n; K) U" P
户的数据库特定的权限。 " V* _, g! p6 f8 l
如果匹配的db表的条目的Host字段是空白的,它表示host表列举主机应该被 ; K- X j8 C& }
允许存取数据库的主机。在这种情况下,在host表中作进一步查找以发现Host和
( @2 a0 u a0 l: yDb字段上的匹配。如果没有host表条目匹配,存取被拒绝。如果有匹配,用户数
7 c$ i; N2 _ W% `% ~1 y据库特定的权限以在db和host表的条目的权限,即在两个条目都是'Y'的权限的交
, X+ N# o+ B) Q# Z" p0 l+ @集(而不是并集!)计算。(这样你可以授予在db表条目中的一般权限,然后用host
0 D8 L1 @' r) i. ?表条目按一个主机一个主机为基础地有选择地限制它们。)
7 K9 M9 L* X9 k1 Y% U在确定了由db和host表条目授予的数据库特定的权限后,服务器把他们加到 ( i4 |9 e4 m: H- ]& k1 O
由user表授予的全局权限中。如果结果允许请求的操作,存取被授权。否则,服
* d! l: l6 T. V; b4 V* D务器检查在tables_priv和columns_priv表中的用户的表和列权限并把它们加到
. T7 _' Q0 ~. v8 r/ W+ E' `! v用户权限中。基于此结果允许或拒绝存取。 5 F% @/ t' m2 ?. G2 l
+ ^' |5 a' h6 A& ?) i4 e. G1 k
用布尔术语表示,前面关于一个用户权限如何计算的描述可以这样总结:
' `+ O: d9 F- w- V+ d( ^. u/ K
global privileges
4 N; T6 H. L1 b" D, Z, aOR (database privileges AND host privileges)
; f1 `2 E8 E- X+ B6 P% f: [OR table privileges
# F/ l8 V; |- O: U9 POR column privileges 0 l. P! B; B& s* O o. g
0 Q7 o6 M5 P; {: o" s2 `
它可能不明显,为什么呢,如果全局user条目的权限最初发现对请求的操作不
' Q1 P& I& b; X5 u0 Y+ }7 K+ T+ ]够,服务器以后把这些权限加到数据库、表和列的特定权限。原因是一个请求可能 & x) U8 _4 |/ W X
要求超过一种类型的权限。例如,如果你执行一个INSERT ... SELECT语句,你就都
^- m; E) O: {4 G! E% Z. \5 J要insert和select权限。你的权限必须如此以便user表条目授予一个权限而db表条 ; D3 {0 m5 H) b( e& E2 @
目授予另一个。在这种情况下,你有必要的权限执行请求,但是服务器不能自己把
% e* @5 d2 a1 l) z/ z' x两个表区别开来;两个条目授予的权限必须组合起来。 * k5 t1 D5 U$ E2 D3 U
& p5 p8 L5 D% P
host表能被用来维护一个“安全”服务器列表。在TcX,host表包含一个在本
4 D9 g: u4 }9 p8 d3 ^ ^地的网络上所有的机器的表,这些被授予所有的权限。
( l( J1 d" J/ ~5 U6 X9 i4 S
9 A, L0 P9 F0 G5 \: N$ ? U$ q( z" G) R你也可以使用host表指定不安全的主机。假定你有一台机器public.your. ' a r* S6 N! \
domain,它位于你不认为是安全的一个公共区域,你可以用下列的host表条目子允 " P9 X$ {2 ~" P9 z( z" l3 I
许除了那台机器外的网络上所有主机的存取:
! T( Z c6 x% Y# k9 X. }) ^
$ M' U/ |8 C: E+ u7 C
5 K+ m$ j" c. D3 J2 l0 \+--------------------+----+- " k8 @; f3 F3 V$ Z
│ Host │ Db │ ... ' Y4 v; f5 N+ D) n, l8 {
+--------------------+----+- 0 C( C/ S! {( Z4 {$ l0 \' ]* P ?
│ public.your.domain │ % │ ... (所有权限设为 'N') " W/ I4 a5 A" |) @* A! O6 Z
│ %.your.domain │ % │ ... (所有权限设为 'Y') & V8 ]! @8 q$ [! l: U7 v
+--------------------+----+- 9 V! Q& V' ?' u- z6 ]2 C) k6 s& L. s
, ] e- ]6 A& D9 f, ^, C6 e7 }0 Y
当然,你应该总是测试你在授权表中的条目(例如,使用mysqlaccess)让你确保
) O1 _+ N- v9 p4 \你的存取权限实际上以你认为的方式被设置。 ) J y: w, U- W1 P$ r: ]! Y' }
4 r4 i+ ~ ~- D/ B
权限更改何时生效
4 h4 i$ K- l6 X% U当mysqld启动时,所有的授权表内容被读进存储器并且从那点生效。 : l9 @! F" \% @" P5 a
. ~' I# O% S; _: Z& F: i' V
用GRANT、REVOKE或SET PASSWORD对授权表施行的修改会立即被服务器注意到。 " f- R& n7 d6 d$ P3 T0 Q* X1 V
2 v, K5 R+ q" \如果你手工地修改授权表(使用INSERT、UPDATE等等),你应该执行一个FLUSH
& {4 Z0 e5 z( J: N9 E- k/ v/ U# aPRIVILEGES语句或运行mysqladmin flush-privileges告诉服务器再装载授权表,否
' S3 `& {6 t9 F则你的改变将不生效,除非你重启服务器。 ! i3 h' m* a3 R N
0 ~- z2 J! ^; W# O8 a: a6 l* b
当服务器注意到授权表被改变了时,现存的客户连接有如下影响:
0 U8 o6 E) d! o2 A/ [
9 O$ F1 q$ ]. j" N3 K$ s表和列权限在客户的下一次请求时生效。 4 u* D9 M0 z8 F8 F. V9 @! {9 f) R
数据库权限改变在下一个USE db_name命令生效。
# c7 J* a4 E; X4 n5 ~! G& f0 p" ]全局权限的改变和口令改变在下一次客户连接时生效。
; S/ i0 S) `, C/ ^8 W3 y2 W7 w4 n+ t0 ~1 r; r! D! s
建立初始的MySQL权限
& B+ _5 _9 V- W1 L5 C在安装MySQL后,你通过运行scripts/mysql_install_db安装初始的存取权限。
8 \( ^4 u- m, k3 N* oscripts/mysql_install_db脚本启动mysqld服务器,然后初始化授权表,包含下列
8 Q% O3 S0 F; _& M2 O+ c权限集合: 7 K! p4 u3 D7 U$ Z' f3 M
- e( g6 O; k# t3 }( i6 q
MySQL root用户作为可做任何事情的一个超级用户被创造。连接必须由本地主 ' o& {3 I2 q- @ ]: c; ^% N
机发出。注意:出世的root口令是空的,因此任何人能以root而没有一个口令进行 6 C6 J9 V+ o: s( c, H3 H$ E
连接并且被授予所有权限。
* P$ b# E6 x' Q; [* a一个匿名用户被创造,他可对有一个'test'或以'test_'开始的名字的数据库 6 f) {3 S5 F. A# a c, c
做任何时期事情,连接必须由本地主机发出。这意味着任何本地用户能连接并且视 ; j1 M9 u) K2 g7 f9 g2 {% r
为匿名用户。
, U! a; t* M9 w其他权限被拒绝。例如,一般用户不能使用mysqladmin shutdown或 - Y' [ Z1 m+ n
mysqladmin processlist。
' z6 o3 G: d+ o1 {注意:对Win32的初始权限是不同的。
+ C, ], Q- I2 W$ f3 o; n1 n# c8 C0 q. t+ O
既然你的安装初始时广开大门,你首先应该做的事情之一是为MySQL root用户
( V: R+ G9 A( o指定一个口令。你可以做如下(注意,你使用PASSWORD()函数指定口令): 8 R& a- O) n* p4 f- X8 D
& p& V; B H& Z& O: P2 @
shell> mysql -u root mysql
! O% d7 n& i P/ R# nmysql> UPDATE user SET Password=PASSWORD('new_password') & \8 [# I" E0 |9 N6 v$ A
WHERE user='root';
& ^- n* z0 N9 emysql> FLUSH PRIVILEGES; ; v. R6 m! ~: }
% _& t% _3 e" K/ y; _
在MySQL 3.22和以上版本中,你可以使用SET PASSWORD语句: 3 i) _+ x* `" @ W3 q" R
9 a" T& f2 T! }7 ~
shell> mysql -u root mysql
% T# c' P0 c( n1 c# dmysql> SET PASSWORD FOR root=PASSWORD('new_password'); + ?9 ^) w: E1 o+ b( H9 j7 ~
; @# N( u8 @* P4 @
设置口令的另一种方法是使用mysqladmin命令:
$ s7 b) F% Q1 S( u: t& q5 F+ f4 K! H, ~
shell> mysqladmin -u root password new_password 3 l; q: G* h3 Q; E N u8 m
: n/ p0 g2 W: r. @: w注意:如果你使用第一种方法在user表里直接更新口令,你必须告诉服务器 6 v; V- C/ |+ S" w+ e, s3 x
再次读入授权表(用FLUSH PRIVILEGES),因为否则改变将不被注意到。 ! Y! G' w% Q# ? Q
3 _, q* U) U# Y M一旦root口令被设置,此后当你作为root与服务器连接时,你必须供应那个
( ?1 G( o7 D2 o1 \! _( `9 u口令。
. Y2 j7 ~: v6 q% x+ K( Z+ k$ T4 l* t- c7 ^8 A2 b3 U( Q" r
你可能希望让root口令为空白以便当你施行附加的安装时,你不需要指定它
a# b$ ~& l4 ^( Z: C% G或测试,但是保证在任何真实的生产工作中使用你的安装之前,设置它。 0 A/ }( \( k, r: r1 x
& `- m: j# ^' @* }/ H |. ~6 @看看scripts/mysql_install_db脚本,看它如何安装缺省的权限。你可用它 0 j. K8 E j* C ?8 w; W7 r9 S
作为一个研究如何增加其他用户的基础。
. Q; i! Q+ N2 z" Y$ i. E! b( m) W' w: F J6 j1 A
如果你想要初始的权限不同于上面描述的那些,在你运行mysql_install_db 6 D( k. Q' V0 E8 M
之前,你可以修改它。 / d( E, L; N- c# G6 d- o' M
2 Q) A* [/ e8 X/ ^& ?为了完全重建权限表,删除在包含mysql数据库的目录下所有“*.frm”, $ `5 `# n( i5 G: e) p
“*.MYI”和“*.MYD”文件。(这是在数据库目录下面命名为“mysql”的目录, 8 l5 k) K- D9 A0 @: F+ c& g
当你运行mysqld --help时,它被列出。)然后运行mysql_install_db脚本,可能 ( z+ v# t, p) i) G9 m; k8 x
在首先编辑它拥有你想要的权限之后。
0 X% u$ D! R3 e3 I5 r' p1 z+ I
注意:对于比MySQL 3.22.10旧的版本,你不应该删除“*.frm”文件。如果
$ n- s. X( _1 k7 _. z) s: X你偶然做了,你应该在运行mysql_install_db之前你的MySQL分发中拷回它们。
7 g. r/ V% B# g& G* c1 X3 J5 A2 q- m/ |8 m/ f* b, K
向MySQL增加新用户权限
; Y# M; p) n1 u0 M; c9 N! u你可以有2个不同的方法增加用户:通过使用GRANT语句或通过直接操作MySQL授
' D5 o/ h. b% t7 x T权表。比较好的方法是使用GRANT语句,因为他们是更简明并且好像错误少些。 ( K" q3 G4 \$ ?3 M6 T0 I* w5 ~
/ R! C/ H4 U/ \. k4 x5 y下面的例子显示出如何使用mysql客户安装新用户。这些例子假定权限根据以前
0 z' N- x, O# p的章节描述的缺省被安装。这意味着为了改变,你必须在mysqld正在运行同一台
f# c3 o# X! c& X% f' O机器上,你必须作为MySQL root用户连接,并且root用户必须对mysql数据库有
6 X; x7 ]: l6 Rinsert权限和reload管理权限。另外,如果你改变了root用户口令,你必须如下
, D$ [) ]9 o2 V的mysql命令指定它。 0 o4 I! r" I9 i, M2 V
h, y! Y2 R% ~7 Q: s# F! \/ z你可以通过发出GRANT语句增加新用户: ( S$ f, ^9 W" M8 C
% N/ M7 V" d6 J; f$ D; I4 r6 lshell> mysql --user=root mysql
5 Y& i" r' C: \$ K7 _mysql> GRANT ALL PRIVILEGES ON *.* TO monty@localhost
' X) X) Z% n/ ZIDENTIFIED BY 'something' WITH GRANT OPTION; : k8 D0 m3 B1 [3 a3 U0 ?* `: K
mysql> GRANT ALL PRIVILEGES ON *.* TO monty@"%"
( s) M! X8 i G! ~, v3 m& \IDENTIFIED BY 'something' WITH GRANT OPTION;
) q# {( h* n9 [) C5 W# \' rmysql> GRANT RELOAD,PROCESS ON *.* TO admin@localhost;
! V/ e: c3 b9 H& ^2 fmysql> GRANT USAGE ON *.* TO dummy@localhost;
, g) y4 j7 O" E6 G/ o p
$ _7 x* o" ^5 g" [0 S这些GRANT语句安装3个新用户: # Y* ]/ h% E9 u/ _% B; L
! {/ m# k* `3 X) h
monty 9 V0 W8 p0 e% | v- D) }
可以从任何地方连接服务器的一个完全的超级用户,但是必须使用一个 . b y# g( b5 O1 B* n
口令('something'做这个。注意,我们必须对monty@localhost和monty@"%"
4 I1 I8 F* Q. |6 t3 G) ~发出GRANT语句。如果我们增加localhost条目,对localhost的匿名用户条目
; P. n9 c* k5 v' r在我们从本地主机连接接时由mysql_install_db创建的条目将优先考虑,因为 3 s- d1 F$ B* V! F" R; }' u. z
它有更特定的Host字段值,所以以user表排列顺序看更早到来。 2 m2 l- `5 w' a. \
admin
1 }1 p$ _2 c' S* o' J可以从localhost没有一个口令进行连接并且被授予reload和process管理 I- n- `( C9 G$ p3 ^0 g
权限的用户。这允许用户执行mysqladmin reload、mysqladmin refresh和
! p( j' s1 ^; H; q3 K0 W- dmysqladmin flush-*命令,还有mysqladmin processlist。没有授予数据库有
' m: \8 w: e+ K% L0 D5 D7 ~关的权限。他们能在以后通过发出另一个GRANT语句授权。
7 n( D6 \* ?0 s7 q6 Y7 V3 Adummy 5 D: D4 m% i* z' r
可以不用一个口令连接的一个用户,但是只能从本地主机。全局权限被设
; c; F# _6 h) T9 j6 C置为'N'--USAGE权限类型允许你无需权限就可设置一个用户。它假定你将在以
( G3 J y! Z7 l后授予数据库相关的权限。 ! V6 g! |- {8 K F o
你也可以直接通过发出INSERT语句增加同样的用户存取信息,然后告诉服
: i' }! C% X: x# y/ I+ \. A- z* W务器再次装入授权表:
# X$ s9 y$ M) ~. I! o9 n. @. j0 ]5 S( ^* Q+ u6 X: p" ~3 j+ Y
shell> mysql --user=root mysql : ?" {, E7 ?! I) Q
mysql> INSERT INTO user VALUES('localhost','monty',PASSWORD * [% _4 O. O5 C/ e% |0 s
('something'), $ g- M) D f- Z1 l- ^9 z8 Z
'Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y', * |/ g$ U2 p! p4 D
'Y','Y')
% T- a; A. K1 G" n0 lmysql> INSERT INTO user VALUES('%','monty',PASSWORD('something'),
! m4 a5 h. Y% y, p'Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y',
; _9 {8 e9 }6 e! }; k! K" D9 Q0 I'Y') ( w2 c& U8 z' O/ H8 D' M/ P
mysql> INSERT INTO user SET Host='localhost',User='admin',
9 \2 m$ d7 @1 U% H1 d& Z" @Reload_priv='Y', Process_priv='Y'; ' d7 C E; [# n: }% g: m; _
mysql> INSERT INTO user (Host,User,Password) % Q& W9 z4 a- t6 s* g
VALUES('localhost','dummy',''); - S6 y. x4 D [( v# B
mysql> FLUSH PRIVILEGES;
4 t6 j( h+ t+ n9 o
5 ]5 U3 z4 R1 X8 m: Z* U, ?3 S取决于你的MySQL版本,对上述,你可能必须使用一个不同数目'Y'值(在 6 A+ b' M. ~/ V# `! s5 a$ r \
3.22.11以前的版本有更少的权限列)。对admin用户,只用在3.22.11开始的版
- _6 A. _9 k. T$ I i# f本具有的更加可读的INSERT扩充的语法。
( P+ {$ O) x& h/ \7 g- J
) r" D# ^ ]8 V( d+ d7 ~: \0 d) J; v2 x3 [注意,为了设置一个超级用户,你只需创造一个user表条目,其权限字段设为
" s( x6 b# [. Z' e% L# S'Y'。不需要db或host表的条目。 ! d: M( a: i" Z. a) z- p
. W" e& `1 j' Y+ e& R9 g0 N y
在user表中的权限列不是由最后一个INSERT语句明确设置的(对dummy用户), 4 _5 P& |( X( l
因此那些列被赋予缺省值'N'。这是GRANT USAGE做的同样的事情。 * ]. k c j% ?6 ^
z0 |2 ?% ^3 `+ e$ h
下列例子增加一个用户custom,他能从主机localhost、server.domain和
9 W0 M1 V% q" O$ V! lwhitehouse.gov连接。他只想要从localhost存取bankaccount数据库,从
! t2 U/ z, x7 e4 S2 i7 Kwhitehouse.gov存取expenses数据库和从所有3台主机存取customer数据库。他 . p/ ^, k; }& ]. h! Z$ q
想要从所有3台主机上使用口令stupid。
6 ?/ J/ F- l7 h) U
( s; `7 T; v( P6 `% d8 F; a- f6 b8 U为了使用GRANT语句设置个用户的权限,运行这些命令: + i: V5 m1 p8 l; j& g0 @3 u3 z2 {
2 }' B6 {# S) [6 r
shell> mysql --user=root mysql 4 ]" ~8 f( J; Z3 \$ ~
mysql> GRANT SELECT,INSERT,UPDATE,DELETE,CREATE,DROP ! Z6 b+ q/ V/ X; G
ON bankaccount.* / N! Z0 w; k/ A; _9 R3 i+ g- {
TO custom@localhost # V9 M3 J( D: F8 b
IDENTIFIED BY 'stupid';
9 w' {5 |% y0 B% z' U- @3 ~/ k9 ~mysql> GRANT SELECT,INSERT,UPDATE,DELETE,CREATE,DROP
7 I- }6 y- h& o# C, e. b @$ {6 qON expenses.*
4 F: t% ?- J U! G C3 FTO custom@whitehouse.gov
9 ~% W2 w8 J6 A9 F+ I# N4 p8 KIDENTIFIED BY 'stupid';
* b% C* n3 y2 F9 y+ r5 Xmysql> GRANT SELECT,INSERT,UPDATE,DELETE,CREATE,DROP
) v$ F- |9 t! H1 Q# jON customer.* * A5 I9 s" v! I, x$ v& {$ |
TO custom@'%'
% P) S# N' C. ` ZIDENTIFIED BY 'stupid';
0 x/ Z1 O0 c: Y8 y. G( L c
`+ t* C, c. U# N4 Q6 g通过直接修改授权表设置用户权限,运行这些命令(注意,在结束时 0 w7 B5 j4 A; C' y
FLUSH PRIVILEGES): * r2 e& G& S+ q3 ^; f: I3 i1 K- E7 I
9 S5 I# U8 V. e6 H4 A
shell> mysql --user=root mysql
8 I' z' b$ [0 z1 \/ Z. y8 c: Emysql> INSERT INTO user (Host,User,Password)
4 U1 v; I& o) K7 a; xVALUES('localhost','custom',PASSWORD('stupid'));
4 {0 U0 \. @% hmysql> INSERT INTO user (Host,User,Password)
6 f; @. R! s; z8 R% ZVALUES('server.domain','custom',PASSWORD('stupid')); # u% F7 Q6 Y$ ~
mysql> INSERT INTO user (Host,User,Password)
: V H+ I$ l6 `1 U7 F7 q8 vVALUES('whitehouse.gov','custom',PASSWORD('stupid'));
) C2 U; P" ]/ ^% vmysql> INSERT INTO db
; g4 I3 y. P* @7 {/ m( V2 w' c) L(Host,Db,User,Select_priv,Insert_priv,Update_priv,Delete_priv,
5 M: X, i- g+ hCreate_priv,Drop_priv)
+ u# Z9 r, S- B( t0 NVALUES 7 o; A) v1 k1 u
('localhost','bankaccount','custom','Y','Y','Y','Y','Y','Y');
! i0 a* m0 g- Y0 C! emysql> INSERT INTO db 8 q# c8 {: ^, d2 J/ I
(Host,Db,User,Select_priv,Insert_priv,Update_priv,Delete_priv, ( [* S+ {$ h# p/ m4 F [, m
Create_priv,Drop_priv)
, ^, P8 m! E# Z9 _VALUES / \/ B& N4 P- z* w k
('whitehouse.gov','expenses','custom','Y','Y','Y','Y','Y','Y'); / b/ y+ M8 u+ T( J8 i0 ]- t' N. j+ @
mysql> INSERT INTO db
% Q3 v* Z: h. S# i# P7 g(Host,Db,User,Select_priv,Insert_priv,Update_priv,Delete_priv, 7 f: ^& P% S+ w3 _5 Z! E- U
Create_priv,Drop_priv) 0 i( ~4 q R0 t9 M' B: B4 m' \1 H
VALUES('%','customer','custom','Y','Y','Y','Y','Y','Y'); & R' P( K( P- c4 b; `5 ^: K
mysql> FLUSH PRIVILEGES; 0 _! g) O0 A7 U2 K; ~* @
- \/ T8 P3 B5 u8 B5 h8 ~! N
头3个INSERT语句增加user表条目,允许用户custom用给定口令从不同的主机
" V) x: v2 {+ q5 t+ M进行连接,但是没有授予任何许可(所有权限被设置为缺省值'N')。后3个INSERT
( R. D8 g% Z& ]2 j& a4 [语句增加db表条目,授予custom以bankaccount、expenses和customer数据库权限, 3 k6 N2 w, g7 }- y
但是只能在从正确的主机存取时。通常,在授权表直接被修改时,服务器必须被告
8 B, x' ^/ C/ x& ]$ S知再次装入他们(用FLUSH PRIVILEGES)以便使权限修改生效。 , z2 W6 `+ Q* }+ N1 D8 U, Z+ q
1 ?6 T5 q* E/ ?8 Q! r1 l( c! ]如果你想要给特定的用户从一个给定的域上的任何机器上存取权限,你可以发
}5 @0 b$ R6 o# w3 g# J1 k( s出一个如下的GRANT语句:
' d- ?4 K; U" R5 ~, P, `5 G* O6 Y4 b; h T1 i& S1 O
mysql> GRANT ...
' x/ F3 O( f5 ~5 W9 pON *.* ( S7 O) H; x- l
TO myusername@"%.mydomainname.com" 5 g o6 P6 D) [! k. D4 G& N
IDENTIFIED BY 'mypassword';
4 y$ P: N" G5 {) D# M# I) H/ V& Z. C" t, L2 K% L, o. F4 ^: }
为了通过直接修改授权表做同样的事情,这样做:
! C4 ~1 F5 O5 q! c
( O0 j. V; x" n- F0 g( Hmysql> INSERT INTO user VALUES ('%.mydomainname.com', 'myusername', + ^) J2 W9 I- o, V! b! `
PASSWORD('mypassword'),...);
$ ~: }9 D: H1 w4 c. u9 Tmysql> FLUSH PRIVILEGES;
& F' ^. X w& h9 r! w' N3 P+ X& |. q
% s8 B$ c) b7 u你也可以使用xmysqladmin、mysql_webadmin甚至xmysql在授权表中插入、改变 8 e ^% R; `% }+ S
和更新值。你可以在MySQL的Contrib目录找到这些实用程序。
5 x6 n+ D6 A7 U; X* Y' n. j6 O$ m% l: P
怎样设置口令
8 O0 b) _( R! l# W/ V+ Q在前面小节的例子里说明了一个重要的原则:当你使用INSERT或UPDATE语句存 ) x& X3 n8 C' Z- ?1 z
储一个非空的口令时,你必须使用PASSWORD()函数加密它。这是因为在user表中以
0 E, g8 u @ S: a. e6 |加密形式存储口令,而不是作为纯文本。如果你忘记这个事实,你可能像这样试图 ! r8 @1 N+ ^; A3 F
设置口令: , K5 E+ W" S: c0 w$ ~9 i1 r
- |! C- m' m9 ~) \, m8 E
shell> mysql -u root mysql
% m6 c) i5 n8 R0 Bmysql> INSERT INTO user (Host,User,Password) VALUES('%','jeffrey',
$ s" o' |$ g' D% M, s/ g8 k'biscuit'); ; u) k9 a. _4 Z. n
mysql> FLUSH PRIVILEGES
: x# C5 r8 t0 j, Q9 N# J2 u
# X7 u Z5 u5 k+ H$ V结果是纯文本值'biscuit'作为口令被存储在user表中。在用户jeffrey试图用 1 t1 H/ d& T- o3 W
这个口令连接服务器时,mysql客户用PASSWORD()加密它并且将结果送给服务器,服
$ }1 |: l m) v; i* O! Y! d& p务器比较在user表中的值(它是纯文本值'biscuit')和加密的口令(而不是
# `! n+ ]9 T; U: G'biscuit'),比较失败并且服务器拒绝连接: 7 h* g& Y% E6 u5 R4 h! N
5 s+ t: s/ d/ z2 |
shell> mysql -u jeffrey -pbiscuit test 0 H4 a9 B b+ e0 d/ {. p2 ?
Access denied
( x. }. ^8 M; t! k7 R' V( B l: i; n7 U. E9 ?' D* i# h2 @
因为当他们被插入user表时,口令必须被加密,相反,INSERT语句应该象这样
/ f, T1 e* `+ m7 o3 F8 N被指定: $ D. H6 A8 I$ N- a8 ^) ?
' i+ H+ F* f+ {. V! x
mysql> INSERT INTO user (Host,User,Password)
4 g+ C& u: N2 k) C5 I1 [VALUES('%','jeffrey',PASSWORD('biscuit')); 5 D* X$ ]( B" C( h6 z
o" j6 s( z6 Y; E8 p当你使用SET PASSWORD语句时,你也必须使用PASSWORD()函数: ; w# S `% {+ q% W7 P6 H0 i3 @8 O/ F
7 z( l# g0 \8 J3 a# A5 R8 a, `$ |
mysql> SET PASSWORD FOR jeffrey@"%" = PASSWORD('biscuit'); ) L2 K# U3 S( f Y3 x5 N
+ m$ |/ r% R! ]5 S
如果你使用GRANT ... IDENTIFIED BY语句或mysqladmin password命令设置口
/ Y' {2 F- `9 s* l6 j令,PASSWORD()函数是不必要的。他们都考虑到为你加密口令,多以你可像这样指 * [- f+ j+ B* p& U! h1 t% d% T
定一个口令'biscuit':
- E6 l# X j, ]! n- `9 N( J% `' x2 M( F/ N4 \
mysql> GRANT USAGE ON *.* TO jeffrey@"%" IDENTIFIED BY 'biscuit';
) n4 n. ~ x! e8 f" r
$ x2 _5 C0 ~4 |) u( H- G. r6 B或 ( c8 S9 H. J* o# U$ Z' b
( f3 e* a6 |% F; X: c! R4 ?9 m
shell> mysqladmin -u jeffrey password biscuit
# _, S+ s# H# J注意: PASSWORD()不是以在Unix口令加密的同样方法施行口令加密。你不应
& q0 H) i+ D' J该假定如果你的Unix口令和你的MySQL口令是一样的,PASSWORD()将导致与在Unix & M* ^/ _1 l! T y+ m1 W; b
口令文件被存储的同样的加密值。见6.2 MySQL 用户名和口令。 1 m% ~& Z7 |8 ?0 m0 c
! f( A# s: z" y) m* Y% u5 gAccess denied错误的原因 " _; A5 `0 C) `+ v3 {
当你试着联接MySQL服务器时,如果你碰到Access denied错误,显示在下面 3 a- @8 q. e0 l2 M
的表指出一些你能用来更正这个问题的动作: 4 J, }2 _0 w3 c! C3 j$ W% D
4 c( A: I Y8 |: p/ h2 K3 Z+ w2 u你是在安装MySQL以后运行mysql_install_db的脚本,来设置初始授权表内容 2 Q1 H- V1 g7 B, n+ @& b! ]: z
吗?如果不是,这样做。见6.10 设置初始MySQL权限。通过执行这个命令测试初 1 r# B S3 B T* g
始权限:
5 `2 `& r8 N oshell> mysql -u root test
$ n" {$ b5 B$ D& R& y1 B
+ y' m5 y) O2 q5 J- b3 [服务器应该让你无误地连接。你也应该保证你在MySQL数据库目录有一个文件 1 [7 [$ @0 M% y( u, u7 Y
“user.MYD”。通常,它是“PATH/var/mysql/user.MYD”,在此PATH是MySQL安
, R1 H) l9 y2 r4 y3 A1 ]装根目录的路径。 ' R% k+ Q$ `* Z' I, \6 G
' Y7 c4 |9 F8 b- [9 [9 m
在一个新的安装以后,你应该连接服务器并且设置你的用户及其存取许可: ) U& R) Y3 t, ~: I
shell> mysql -u root mysql , \4 z. ^" J$ B% v: ?: M. f
6 N8 @6 W8 X$ K7 A! T服务器应该让你连接,因为MySQL root用户初始时没有口令。既然那也是一个
9 c6 X) T! M+ j# \+ \ K% d安全风险,当你正在设置其他MySQL用户时,设定root口令是一件重要的事请。如 - s/ B9 T& p9 m, v, R. Y! K
果你作为root尝试连接并且得到这个错误: % p8 _1 e0 c% t; k9 K
Q1 y, I+ \$ R
Access denied for user: '@unknown' to database mysql
" Z8 o$ p4 h; P# J# [1 `6 z
+ g* \( f, X+ E' B' K这意味着,你没有一个条目在user表中的一个User列值为'root'并且mysqld 8 @1 ?* j8 E7 C! r# Y
不能为你的客库解析主机名。在这种情况下,你必须用--skip-grant-tables选项 5 ^5 ], V. x) [& M# U2 W
重启服务器并且编辑你的“/etc/hosts”或“\windows\hosts”文件为你的主机
{8 E1 z, u" k( s! g6 n增加一个条目。
# ~3 `8 V' }/ n- p4 v/ D& p* a- q9 j* o1 J3 e1 H
如果你从一个3.22.11以前的版本更新一个现存的MySQL安装到3.22.11版或以 }) C, M. m' W/ z5 e$ J
后版本,你运行了mysql_fix_privilege_tables脚本吗?如果没有,运行它。在
1 s1 t4 ~9 S& B- S( t( g, y, i& kGRANT语句变得能工作时,授权表的结构用MySQL 3.22.11修改 。 8 z j% c& a. X- \9 h1 ^
如果你直接对授权表做修改(使用INSERT或UPDATE语句)并且你的改变似乎被 ' I2 r( i' T' Y) l- J" Y' b1 b, e# w
忽略,记住,你必须发出一个FLUSH PRIVILEGES语句或执行一个mysqladmin 4 Y% [; C9 v- {! \' F$ H
flush-privileges命令导致服务器再次读入表,否则你的改变要道下一次服务器被 3 o2 ^; S: z5 m) m
重启时再生效。记住在你设定root口令以后,你将不需要指定它,直到在你清洗
. D, e# [/ \! I G8 V0 v(flush)权限以后,因为服务器仍然不会知道你改变了口令! 0 T" t. a4 W: l) j" q n
如果你的权限似乎在一个会话(session)当中改变了,可能是一个超级用户改变 + P3 q: [& y. n1 f& C- n
了他们。再次装入授权表作用于新客户连接,但是它也影响现存的连接,如6.9 权 $ X/ b- W- A# h2 E
限改变何时生效小节所述。 2 M/ c( Q; z# Q( A: ?
为了测试,用--skip-grant-tables选项启动mysqld守护进程,然后你可以改变
- Q! S. t" ?3 w( q) k( ?MySQL授权表并且使用mysqlaccess脚本检查你的修改是否有如期的效果。当你对你的
1 H# ^* a" j' x4 \6 Z改变满意时,执行mysqladmin flush-privileges告诉mysqld服务器开始使用新的权
+ a# g; T1 M( }& P+ _- K限表。注意:再次装入授权表覆盖了--skip-grant-tables选项。这允许你告诉服务
$ a" e) T. j/ W2 C1 I' K# }* d器开始使用授权表,而不用停掉并重启它。
k/ l1 b: X) t8 f+ [0 g. J/ \如果你有一个Perl、Python或ODBC程序的存取问题,试着用mysql -u user_name
" z" h3 T& J3 A- j0 b8 Qdb_name或mysql -u user_name -pyour_pass db_name与服务器连接。如果你能用
) @+ s" v# x7 C) cmysql客户连接,这是你程序的一个问题而不是存取权限的问题。(注意在-p和口令 2 }; }) T& A. y; z. J
之间没有空格;你也能使用--password=your_pass句法指定口令。)
( t* V3 ]/ V/ A7 U; @0 b如果你不能让口令工作,记得如果你用INSERT, UPDATE或SET PASSWORD语句
( D- U' B" a( D6 r$ J设置口令,你必须使用PASSWORD()函数。如果你用GRANT ... INDENTIFIED BY语
! N1 @; w( e2 @0 ?句或mysqladmin password命令指定口令,PASSWORD()函数是不需要的。
8 i. Q3 x: B2 [/ blocalhost是你本地主机名的一个同义词,并且也是如果你不明确地指定主机
/ q! H& c" o+ E: {: H! H' k而客户尝试连接的缺省主机。然而,如果你正在运行于一个使用MIT-pthreads的系
# ^3 L' x$ k; ~8 ]统上,连接localhost是不行的(localhost连接使用Unix套接字进行,它没被 MIT
3 A/ V6 c) R; _, Z2 _6 ~9 q0 z-pthreads支持),为了在这样的系统上避免这个问题,你应该使用--host选项明确
0 P% |$ s( F, H. R: z' r地命名服务器主机,这将做一个 TCP/IP连接到mysqld服务器。在这种情况下,你 ' t" c/ Z3 P) `
必须有在服务器主机上的user表中条目的你真实的主机名。(即使你在服务器同一 ! X, n, C& z9 b
台的主机上运行一个客户程序,这也是真的。) ' b8 a& {3 }* ]
当尝试用mysql -u user_name db_name与数据库连接时,如果你得到一个
" U" U) u) ?9 UAccess denied错误,你可能有与user桌有关的问题,通过执行mysql -u root
- K I7 G) y0 mmysql并且发出下面的SQL语句检查:
5 i3 q; G( A/ T% Pmysql> SELECT * FROM user; 1 v2 a2 b' E! u5 @. s
1 I' h; T' K6 t
结果应该包含一个有Host和User列的条目匹配你的计算机主机名和你的MySQL用户
1 E" X+ r9 W4 i2 C6 P名。
' [& V/ ^2 W7 d3 D7 g. D; |8 T) @6 M* l( U
Access denied错误消息将告诉你,你正在用哪个用户尝试登录,你正在试图 4 T5 m% j. [* K i: ~1 G# h. a% b, e
用连接哪个主机,并且你是否正在使用一个口令。通常,你应该在user表中有一 . z c# H& h$ l& |
个条目,正确地匹配在错误消息给出的主机名和用户名。 5 _6 V2 w2 H V1 S0 ?
如果当你试着从一个不是MySQL服务器正在运行的主机上连接时,你得到下列 8 \7 ]% f4 m' C; B# ?
错误,那么在user表中没有匹配那台主机行:
* Z# ^5 W3 M- F9 G KHost ... is not allowed to connect to this MySQL server
) T; O* l# m2 F9 I( _$ K* h2 K& Q# q: d8 C5 o( n# Y
你可以通过使用mysql命令行工具(在服务器主机上!)修正它,把你正在试 L3 s' C! m2 H. i5 _( { q, o
图连接的用户/主机名组合新加一行到user表中。如果你不在运行MySQL 3.22并且 Q7 |; d( @! p$ l5 S
你不知道你正在从它连接的机器的IP数字或主机名,你应该把一个'%'条目作为 ( t# e# V0 \! A8 z! d; M' Y# R1 Y
Host列值放在user表中并且在服务器机器上使用--log选项重启mysqld。在试图从
$ @; f& M- I5 v: o) P# ~客户机器连接以后,在MySQL记录文件中的信息将显示你如何真正进行连接。(
+ Q2 ~: p5 m: E' o! Z然后用在记录文件上面显示出的实际的主机名代替user表中的'%'条目。否则,
B f8 X+ ?8 O9 I0 o你将有一个不安全的系统。) ; w, W b3 I, E( b* \4 v& g
1 [* K! a' z8 R( ~
如果mysql -u root test工作但是mysql -h your_hostname -u root test
4 p( s( h2 ?( o* D& q导致Access denied,那么在user表中你可能没有你的主机的正确名字。这里的 N, l; H. [, {: B; P' x
一个普遍的问题是在user表条目中的Host值指定一个唯一的主机名,但是你系统 " f8 u! z) `0 W2 ^/ B8 t, K6 r5 p
的名字解析例程返回一个完全正规的域名(或相反)。例如,如果你在user表中有
- w* @+ p0 }' j一个主机是'tcx'的条目,但是你的 DNS告诉MySQL你的主机名是'tcx.subnet.
$ w9 k, s, O) _8 ~se',条目将不工作。尝试把一个条目加到user表中,它包含你主机的IP数字作 . f. j+ w- q+ f; j# J3 P9 Q
为Host列的值。(另外,你可以把一个条目加到user表中,它有包含一个通配符
" g7 |0 @& Y2 H如'tcx.%'的Host值。然而,使用以“%”结尾的主机名是不安全的并且不推荐!) % F7 s6 J' j/ o0 i4 j$ T
如果mysql -u user_name test工作但是mysql -u user_name other_db_name
o5 H9 @, }& s1 l不工作,对other_db_name,你在db表中没有没有一个条目列出。 5 E0 P. E& k& w6 H8 ?' W+ f7 s+ e/ H
当在服务器机器上执行mysql -u user_name db_name时,它工作,但是在其 6 s, L+ F/ m/ p' k$ [; X
它客户机器上执行mysql -h host_name -u user_name db_name时,它却不工作,
+ ~- m* ~) e7 F2 g& P2 N5 {1 }: q' M你没有把客户机器列在user表或db表中。
, D* |4 b. \: ^如果你不能弄明白你为什么得到Access denied,从user表中删除所有Host
7 Z% x3 m8 O ~& ~! t包含通配符值的条目(包含“%”或“_”的条目)。一个很普遍的错误是插入用 ' p& F& M: {& L2 e6 j
Host='%'和User='some user'插入一个新条目,认为这将允许你指定localhost
" S+ l( k E+ ^1 P" X从同一台机器进行连接。它不工作的原因是缺省权限包括一个有Host='localhost' / U/ x4 [4 a5 C, J z" G
和User=''的条目,因为那个条目一个比'%'更具体的Host值'localhost',当从 * x8 J2 J; \. V! N! P
localhost连接时,它用于指向新条目!正确的步骤是插入Host='localhost'和 ' t0 b% ~6 _ b1 e# k ^
User='some_user'的第2个条目,或删除Host='localhost'和User=''条目。
$ Z' z. F( h9 z9 q0 C' r7 n如果你得到下列错误,你可以有一个与db或host表有关的问题: 8 k+ [; D o1 B4 F$ c5 a
Access to database denied
5 }$ k" I& D( J; g2 J
5 ]- P+ k- R* Q, R; T: S/ X如果从db表中选择了在Host列有空值的条目,保证在host表中有一个或多
( Y! _6 t. \6 U$ ]个相应的条目,指定运用db表中的哪些主机。如果在使用SQL命令SELECT ...
- e' `: E$ D1 mINTO OUTFILE或LOAD DATA INFILE时,你得到错误,在user表中的你的条目可
2 Y% m+ \1 p4 g$ r. t- I, X- F$ c能启用file权限。
6 D- ], s; T0 z4 y3 L! P5 z8 _/ r$ b" g. c7 ^3 x. a* ~
记住,客户程序将使用在配置文件或环境变量被指定了的连接参数。如果
N2 o" T4 @, X Y, N' Q& B2 k当你不在命令行上指定他们时,一个客户似乎正在发送错误的缺省连接参数, ) y* `% R, j% z( C
检查你的环境和在你的主目录下的“.my.cnf”文件。你也可以检查系统范围
( L9 ]9 X k+ R6 b的MySQL配置文件,尽管更不可能将在那里指定那个客户的连接参数。如果当 / l3 f1 A/ n$ F. R
你没有任何选项运行一个客户时,你得到Access denied,确认你没在任何选 ) S" r+ g) t$ q! c; E
项文件里指定一个旧的口令!见4.15.4 选项文件。 * l1 }& J- j6 B! ]: ^+ E3 D# A. K
如果任何其它事情失败,用调试选项(例如,--debug=d,general,query) : h5 `1 `2 g" e9 `$ p+ f
启动mysqld守护进程。这将打印有关尝试连接的主机和用户信息,和发出的每 6 w: L* P) e! R: y/ A. v
个命令的信息。见G.1 调试一个MySQL服务器。
% Y. i; V6 {0 q- I+ G. l如果你有任何与MySQL授权表的其它问题,而且觉得你必须邮寄这个问题
O0 u# M* u& q. B/ y% X到邮寄表,总是提供一个MySQL授权表的倾倒副本(dump)。你可用mysqldump % l, b, y! u' h
mysql命令倾倒数据库表。象平时一样,用mysqlbug脚本邮寄你的问题。在一 7 g9 {. B9 `, ^) W. C x- C
些情况下你可能用--skip-grant-tables重启mysqld以便能运行mysqldump。 J" q4 e9 u3 l, ]+ \% N* `; U) r+ Z
怎样使MySQL安全以对抗解密高手
+ }/ o4 ?# b' v5 o1 Q7 K当你连接一个MySQL服务器时,你通常应该使用一个口令。口令不以明文 6 F! X+ D9 `0 S8 C W, \
在连接上传输。 . p' x4 m( w A* U3 t) p
j5 I0 V& S/ X$ Z: Y8 c
所有其它信息作为能被任何人读懂的文本被传输。如果你担心这个,你可
' l8 f. v! i4 N0 w& o3 m使用压缩协议(MySQL3.22和以上版本)使事情变得更难。甚至为了使一切更安全
' u; F4 }$ @/ H2 J; v6 M,你应该安装ssh(见http://www.cs.hut.fi/ssh)。用它,你能在一个MySQL服
" E/ {. w* d8 Y1 R务器与一个MySQL客户之间得到一个加密的TCP/IP连接。 6 m1 @$ d# {0 l6 D
}/ G3 g* A% U7 V& D
为了使一个MySQL系统安全,强烈要求你考虑下列建议:
: W2 ]* D* ?/ B+ k0 W- T* K5 L. W) I& _+ {* z9 R
对所有MySQL用户使用口令。记住,如果other_user没有口令,任何人能简
# s/ c, o+ [2 m单地用mysql -u other_user db_name作为任何其它的人登录。对客户机/服务器 % ~) H0 p$ d# y" m
应用程序,客户可以指定任何用户名是常见的做法。在你运行它以前,你可以通
3 P0 X# H8 s9 [. W, \4 g y过编辑mysql_install_db脚本改变所有用户的口令,或仅仅MySQL root的口令, $ y* C2 H% B. h6 \
象这样: ' C2 n8 y) s% C U& Z7 y
shell> mysql -u root mysql $ Q* _3 R+ H# D" z" \5 J
mysql> UPDATE user SET Password=PASSWORD('new_password')
% M9 M+ ^* a+ ~7 i$ M3 K$ e. E8 ~8 q, VWHERE user='root'; ( N8 M, R$ c' w
mysql> FLUSH PRIVILEGES;
7 _) L! V* v- U1 p/ [% y. Y; v" r0 e0 ~9 M
不要作为Unix的root用户运行MySQL守护进程。mysqld能以任何用户运行, * [) K4 Y! i" U2 D0 r
你也可以创造一个新的Unix用户mysql使一切更安全。如果你作为其它Unix用户
6 q, |8 B( {2 d运行mysqld,你不需要改变在user表中的root用户名,因为MySQL用户名与Unix + z) m7 a4 R M9 W7 X* n1 u+ K
用户名没关系。你可以作为其它Unix用户编辑mysql.server启动脚本mysqld。
" m: v' h, P) O/ v5 z% w! \6 L1 B通常这用su命令完成。对于更多的细节,见18.8 怎样作为一个一般用户运行 & L4 l+ c; s3 O V' h
MySQL。
. g* ^# ~) B+ j" L# z3 O如果你把一个Unix root用户口令放在mysql.server脚本中,确保这个脚本 / X: N" p5 a4 I. i! j# H
只能对root是可读的。
/ o0 i0 T, n# p L检查那个运行mysqld的Unix用户是唯一的在数据库目录下有读/写权限的用 7 }% o/ r( P/ c( Z
户。
; t% @, s1 d$ K/ I! ^2 p- k不要把process权限给所有用户。mysqladmin processlist的输出显示出当 + a& E- ?7 {. j
前执行的查询正文,如果另外的用户发出一个UPDATE user SET password=
; _4 z! b5 p8 v* e. [0 T" UPASSWORD('not_secure')查询,被允许执行那个命令的任何用户可能看得到。
2 I; v& q4 Y# Q! D1 Vmysqld为有process权限的用户保留一个额外的连接, 以便一个MySQL root用
+ D# H# v5 ^5 p" u- J9 L. ^+ g7 K+ L户能登录并检查,即使所有的正常连接在使用。
# o. W, p) P% ^' `2 D" S3 u不要把file权限给所有的用户。有这权限的任何用户能在拥有mysqld守护
' E9 t4 Q( o) {# A进程权限的文件系统那里写一个文件!为了使这更安全一些,用SELECT ...
( g) F/ }* O# ~. L$ LINTO OUTFILE生成的所有文件对每个人是可读的,并且你不能覆盖已经存在的 ( n! ]" t: r$ ?: w; p* g- }$ z0 B
文件。file权限也可以被用来读取任何作为运行服务器的Unix用户可存取的文
" o! W! v. p z' _. w" n8 K件。这可能被滥用,例如,通过使用LOAD DATA装载“/etc/passwd”进一个数
. J8 r* I9 a8 ?& _6 n6 V据库表,然后它能用SELECT被读入。 . G! t1 f, [+ u& v$ w# m% O/ j
如果你不信任你的DNS,你应该在授权表中使用IP数字而不是主机名。原则 7 d) m& t: y" x' m& }
上讲,--secure选项对mysqld应该使主机名更安全。在任何情况下,你应该非常 . F, ?, ^7 O3 _8 y1 _
小心地使用包含通配符的主机名! / j6 J; f! n' z/ c8 ?
下列mysqld选项影响安全:
k0 ~4 i' B& R' r2 z8 s
+ y3 r* n. @' J# c* g--secure
C o; b6 t$ R7 h* [! y; I由gethostbyname()系统调用返回的IP数字被检查,确保他们解析回到原来 # r4 [/ Q g) O
的主机名。这对某些外人通过模仿其它主机获得存取权限变得更难。这个选项也
5 s* n9 r: x2 s& K" z6 w+ s/ h5 R增加一些聪明的主机名检查。在MySQL3.21里,选择缺省是关掉的,因为它有时 6 G9 T- X6 l+ t9 S% g
它花很长时间执行反向解析。MySQL 3.22缓存主机名并缺省地启用了这个选项。 / j) R0 V4 K9 B, o% u- D
--skip-grant-tables * }. }, }1 B) v
这个选项导致服务器根本不使用权限系统。这给每个人以完全存取所有的数
' p5 K( S3 P6 M E% P4 u0 i据库的权力!(通过执行mysqladmin reload,你能告诉一个正在运行的服务器 $ r) ?& H. j! K9 E) L1 L o! H
再次开始使用授权表。) . {1 }+ z4 y( Y4 t9 `; a; d: v4 [$ U
--skip-name-resolve
# a$ n- Z; f' H: h0 F @6 [: C; H主机名不被解析。所有在授权表的Host的列值必须是IP数字或localhost。 I- o! b: J) |% X+ m" p4 [
--skip-networking
X# X6 V/ |+ r; s2 I$ o7 W在网络上不允许TCP/IP连接。所有到mysqld的连接必须经由Unix套接字进 $ `; R0 U* E% T" r% I
行。这个选项对使用MIT-pthreads的系统是不合适的,因为MIT-pthreads包不 ' l( h& x# q1 S( X' W1 h3 }3 W
支持Unix套接字。 |
|