文章目录
本篇文章主要说一下MySQL数据中身份鉴别控制点中a测评项的相关知识点和理解。
MySQL数据库对于用户的标识和其它数据库有些不一样,不仅仅是用户名,而是username + host。
MySQL数据中user表的一部分字段如下:
这三个用户的用户名虽然都是root,但其实是三个不同的用户,其密码也是单独设置的。
查询当前登录账户,也可以看到用户的标识组成为username+host:
既然用户的标示是两个字段的组合,匹配的时候也要这两个字段都匹配上了才行,这里我简单的说一说(根据官方文档)。
当客户端对MySQL发起连接后,MySQL会先对user表进行排序,然后从第一行开始,逐行与传入的host、username进行匹配,当匹配到了某一行之后,就不往下继续匹配了。(如果任何一行都无法匹配,则登录失败)
此时,再来对比传入的口令和存储的口令是否一致,如果口令一致,那么该行即为这次登陆后所使用的行(用户身份)。
如果不一致,则登录失败。
举个例子,如果用户表如下所示:
那么当验证时,会首先对其进行排序,排序如下:
注意,Host字段可以使用匹配符%,%则代表匹配任何Ip地址。另外,空字符串也代表匹配任何Ip地址。
而User字段不使用匹配符%,但是如果为空字符串,则代表匹配任何用户名。
MySQL排序时是先对Host进行排序,然后才是User。
Host的排序为明确的值排在前面,比如文字主机名和IP地址即为明确的地址值,所以%和空字符串排在它们之后,其中空字符串又排在%之后。
当Host字段向同时,则对User字段进行排序,对于User字段也是明确的值排在前面,所以在排序结果图中,root@localhost排在了@localhost(空字符串用户名)的前面。
如果Host字段和User字段都一样,那么排序的顺序是不确定的(可能和创建该用户的先后有关)。
所以客户端连接MySQL数据库时,使用给定的用户名,不一定会以该用户名的身份登入数据库。
比如使用用户名jeffrey和它的口令,在本地的mysql中进行登录时,会按照排序结果图中,一行行的去匹配:
对于第一行,客户端的Host(localhost或者127.0.0.1)可以和Host字段的localhost匹配上,但是User不一样,无法完全匹配,所以往下走。
对于第二行,客户端的Host(localhost或者127.0.0.1)可以和Host字段的localhost匹配上,而第二行的用户名是空字符串,可以匹配任何用户名,所以也能匹配jeffrey,如果口令一致,则完成了匹配,到此匹配过程结束。
这样,虽然使用了用户名jeffrey,但最后却会以@localhost的身份登入数据库。
最后,User表的口令字段可以为空字符串,这代表口令为空字符串,而不是与任何口令都匹配。
MySQL中存在user()函数和current_user()函数。
user()函数会显示你当前的登录用户具体是使用了什么用户名和什么ip地址去进行登录的。(注,ip地址是指连接数据库的客户端的ip地址,不是自己设置的值)
例子如下:
这里代表在ip地址为192.168.203.132的客户端上,使用用户名test对MySQL数据库进行了连接。
current_user()函数会显示你最终使用的用户身份(也就是最后匹配到的那一行),例子如下:
也就是,最后在User表中匹配到了Host字段为192.168.%.%、User字段为test的那一行,以[email protected]..%.%的用户身份登录了MySQL数据库。
在MySQL5.7之前,User表中的口令字段为Password,从MySQL5.7开始,口令字段变成了authentication_string。
不过在MySQL5.7之前,比如MySQL5.5.53,也存在着authentication_string字段,不知道其用途是什么。
a)应对登录的用户进行身份标识和鉴别,身份标识具有唯一性,身份鉴别信息具有复杂度要求并定期更换;
应对登录的用户进行身份标识和鉴别
对于MySQL来说,如上文所言,用户的身份标识为username + host,鉴别就是通过username + host + password来进行登录验证。
所以,对于这个要求,就是不能出现空用户名、空密码、任意host的用户,也就是鉴别的因素三者同时皆空。
其中任何一个不为空或%(对Host而言),则都算实现了鉴别(部分鉴别)。
身份标识具有唯一性
对于MySQL来说,如上文所言,用户的身份标识为username + host,MySQL并没有禁止出现完全一样的username + host行,所以这里是可能出现身份标识不唯一的情况的。
在安装MySQL完成后,会存在3个默认账户,如下:
这三个用户的User都是root,虽然Host看上去不一样,实际上也都是本机地址。
127.0.0.1就是本地的ip地址,localhost则是在hosts文件里(linux系统中)和ip地址进行了映射,其实映射的还是127.0.0.1地址,至于::1应该是ipv6格式的本机地址。
::1这个我不知道要如何才能连上,当用户名为root的行只剩下host值为::1的行的时候,使用用户名root怎么连都不可能连上。
对于127.0.0.1和localhost,在windows系统上没啥区别,登录时其排序是不确定的(对于这种,应该是谁先创建谁在前)。
对于127.0.0.1和localhost,好像在linux上有一点区别:MySQL主机127.0.0.1与localhost区别总结
从正常的业务需求来说,明显这三个用户的身份标识是不唯一的,应该删掉::1和另外一个。
身份鉴别信息具有复杂度要求
这个要从两个方面看,我个人觉得两个方面都符合才能算达到要求。
第一个方面即实际的口令是否具有一定的复杂度,也即口令至少8位,且包含大写字母、小写字母、数字、特殊字符这四类字符种的三种,且口令不包含简单排列规律,如admin!@#123此类弱口令。
第二个方面即MySQL是否进行了口令复杂度策略的设置,强制要求口令具有一定的复杂度,也即在MySQL中使用了validate_password插件。
这时候,可以用以下命令查看该插件的相关参数:
为了达到要求,参数需要进行设置(初级教程):
各个参数的代表的意思:mysql之validate_password_policy
他这里说得挺详细的,我这里就不写了。
要求并定期更换
和口令复杂度一样,一个方面是看实际的口令更换周期,这里可以通过访谈相关人员来得知,也可以通过查看user表中的password_last_changed字段(注意,只有高于某个版本的MySQL才有这个字段)。
而MySQL中的口令更换策略,则和版本有一些关系。
从MySQL5.6.6开始,User表中多了一个password_expired字段,默认值是N,当设置为Y后,则这个用户还是可以登陆到MySQL服务器,但是在用户未设置新密码之前不能运行任何查询语句,而且会得到如下错误消息提示:
mysql> SHOW DATABASES;
ERROR 1820 (HY000): You must SET PASSWORD before executing this statement
Keep in mind that this does not affect any current connections the account has open.
所以对于这个版本,定期修改口令的策略需要通过定时器任务等方式来实现了。
而从5.7.4这个版本开始,MySQL多了一个全局变量default_password_lifetime:
并且在User字段表中增加了两个字段:password_lifetime、password_last_changed:
给大家解释一下,首先无论是全局变量default_password_lifetime还是User表中的字段password_lifetime,它们的单位都是天。
当password_lifetime为null的时候,则代表该用户当前口令的有效期使用的是全局变量default_password_lifetime的值。
当password_lifetime为一个具体的值的时候,则代表该用户当前口令的有效期不使用全局变量default_password_lifetime的值,使用的是字段password_lifetime的值。
对于default_password_lifetime和password_lifetime而言,值为0则代表有效期为永远。
另外,mysql-5.7.4 ~ mysql-5.7.10 这些版本中default_password_lifetime的默认值是360,从mysql-5.7.11开始,default_password_lifetime这个参数的默认值为0。
关于口令过期的具体内容,可以看:mysql-5.7 密码过期详解、Mysql5.7.9密码已过有效期的处理过程 ,说得挺清楚的。
*本文原创作者:起于凡而非于凡 ,本文属于FreeBuf原创奖励计划,未经许可禁止转载