权限系统工作原理 MySQL权限系统保证所有的用户可以严格地做他们假定被允许做的事情。当你连接一个MySQL服务器时, 你的身份由你从那连接的主机和你指定的用户名来决定,系统根据你的身份和你想做什么来授予权限。 MySQL在认定身份中考虑你的主机名和用户名字,是因为有很小的原因假定一个给定的用户在因特网上属于同一个人。例如,用户从whitehouse.gov连接的bill不必和从mosoft.com连接bill是同一个人。 MySQL通过允许你区分在不同的主机上碰巧有同样名字用户来处理它:你可以对从whitehouse.gov连接授与bill一个权限集,而为从microsoft.com的连接授予一个不同的权限集。 MySQL存取控制包含2个阶段: 阶段1:服务器检查你是否允许连接。 阶段2:假定你能连接,服务器检查你发出的每个请求。看你是否有足够的权限实施它。例如,如果你从数据库中一个表精选(select)行或从数据库抛弃一个表,服务器确定你对表有select权限或对数据库有drop权限。 服务器在存取控制的两个阶段使用在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 Reload_priv Shutdown_priv Process_priv File_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 每个授权表包含范围字段和权限字段。 范围字段决定表中每个条目的范围,即,条目适用的上下文。例如, 一个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表包含范围字段,指出每个条目适用的表或表/列的组合。 对于检查存取的用途,比较Host值是忽略大小写的。User、Password、Db和Table_name值是区分大小写的。Column_name值在MySQL3.22.12或以后版本是忽略大小写的。 权限字段指出由一个表条目授予的权限,即,可实施什么操作。服务器组合各种的授权表的信息形成一个用户权限的完整描述。为此使用的规则在6.8 存取控制, 阶段2:请求证实描述。 范围字段是字符串,如下所述;每个字段的缺省值是空字符串: 字段名 类型 Host CHAR(60) User CHAR(16) Password CHAR(16) Db CHAR(64) (tables_priv和columns_priv表为CHAR(60)) 在user、db和host表中,所有权限字段被声明为ENUM(N,Y)--每一个都可有值N或Y,并且缺省值是N. 在tables_priv和columns_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 简单地说,服务器使用这样的授权表: user表范围字段决定是否允许或拒绝到来的连接。对于允许的连接,权限字段指出用户的全局(超级用户)权限。 db和host表一起使用: db表范围字段决定用户能从哪个主机存取哪个数据库。权限字段决定允许哪个操作。 当你想要一个给定的db条目应用于若干主机时,host表作为db表的扩展被使用。例如,如果你想要一个用户能在你的网络从若干主机使用一个数据库,在用户的db表的Host条目设为空值,然后将那些主机的每一个移入host表。这个机制详细描述在6.8 存取控制, 阶段2:请求证实。 tables_priv和columns_priv表类似于db表,但是更精致:他们在表和列级应用而非在数据库级。 注意管理权限(reload, shutdown, 等等)仅在user表中被指定。这是因为管理性操作是服务器本身的操作并且不是特定数据库,因此没有理由在其他授权表中列出这样的权限。事实上,只需要请教user表来决定你是否执行一个管理操作。 file权限也仅在user表中指定。它不是管理性权限,但你读或谢在服务器主机上的文件的的能力独立于你正在存取的数据库。 当mysqld服务器启动时,读取一次授权表内容。对授权表的更改生效在6.9 权限更改何时生效描述。 当你修改授权表的内容时,确保你按你想要的方式更改权限设置是一个好主意。为帮助诊断问题,见6.13 “存取拒绝引起”错误的原因。对于安全问题上的忠告,见6.14 怎么对使MySQL安全对抗解密高手。 一个有用的诊断工具是mysqlaccess脚本,由Carlier Yves 提供给MySQL分发。使用--help选项调用mysqlaccess查明它怎样工作。注意:mysqlaccess仅用user、db和host表仅检查存取。它不检查表或列级权限。 6.7 存取控制, 阶段1:连接证实 当你试图联接一个MySQL服务器时,服务器基于你的身份和你是否能通过供应正确的口令验证身份来接受或拒绝连接。如果不是,服务器完全具结你的存取,否则,服务器接受连接,然后进入阶段2并且等待请求。 你的身份基于2个信息: 你从那个主机连接 你的MySQL用户名 身份检查使用3个user表(Host, User和Password)范围字段执行。服务器只有在一个user表条目匹配你的主机名和用户名并且你提供了正确的口令时才接受连接。 在user表范围字段可以如下被指定: 一个Host值可以是主机名或一个IP数字,或localhost指出本地主机。 你可以在Host字段里使用通配符字符“%”和“_”。 一个Host值%匹配任何主机名,一个空白Host值等价于%。注意这些值匹配能创建一个连接到你的服务器的任何主机! 通配符字符在User字段中不允许,但是你能指定空白的值,它匹配任何名字。如果user表匹配到来的连接的条目有一个空白的用户名,用户被认为是匿名用户(没有名字的用户),而非客户实际指定的名字。这意味着一个空白的用户名被用于在连接期间的进一步的存取检查(即,在阶段2期间)。 Password字段可以是空白的。这不意味着匹配任何口令,它意味着用户必须不指定一个口令进行连接。 非空白Password值代表加密的口令。 MySQL不以任何人可以看的纯文本格式存储口令,相反,正在试图联接的一个用户提供的口令被加密(使用PASSWORD()函数),并且与存储了user表中的已经加密的版本比较。如果他们匹配,口令是正确的。 下面的例子显示出各种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类子网的任何主机连接 既然你能在Host字段使用IP通配符值(例如,144.155.166.%匹配在一个子网上的每台主机),有可能某人可能企图探究这种能力,通过命名一台主机为144.155.166.somewhere.com。为了阻止这样的企图,MySQL不允许匹配以数字和一个点起始的主机名,这样,如果你用一个命名为类似1.2.foo.com的主机,它的名字决不会匹配授权表中Host列。只有一个IP数字能匹配IP通配符值。 一个到来的连接可以被在user表中的超过一个条目匹配。例如,一个由fred从thomas.loc.gov的连接匹配多个条目如上所述。如果超过一个匹配,服务器怎么选择使用哪个条目呢?服务器在启动时读入user表后通过排序来解决这个问题,然后当一个用户试图连接时,以排序的顺序浏览条目,第一个匹配的条目被使用。 user表排序工作如下,假定user表看起来像这样: +-----------+----------+- | Host | User | ... +-----------+----------+- | % | root | ... | % | jeffrey | ... | localhost | root | ... | localhost | | ... +-----------+----------+- 当服务器在表中读取时,它以最特定的Host值为先的次序排列(%在Host列里意味着“任何主机”并且是最不特定的)。有相同Host值的条目以最特定的User值为先的次序排列(一个空白User值意味着“任何用户”并且是最不特定的)。最终排序的user表看起来像这样: +-----------+----------+- | Host | User | ... +-----------+----------+- | localhost | root | ... | localhost | | ... | % | jeffrey | ... | % | root | ... +-----------+----------+- 当一个连接被尝试时,服务器浏览排序的条目并使用找到的第一个匹配。对于由jeffrey从localhost的一个连接,在Host列的localhost条目首先匹配。那些有空白用户名的条目匹配连接的主机名和用户名。(%/jeffrey条目也将匹配,但是它不是在表中的第一匹配。) 这是另外一个例子。假定user桌子看起来像这样: +----------------+----------+- | Host | User | ... +----------------+----------+- | % | jeffrey | ... | thomas.loc.gov | | ... +----------------+----------+- 排序后的表看起来像这样: +----------------+----------+- | Host | User | ... +----------------+----------+- | thomas.loc.gov | | ... | % | jeffrey | ... +----------------+----------+- 一个由jeffrey从thomas.loc.gov的连接被第一个条目匹配,