最近接受朋友的邀请为本地某公司开发一套Web版的销售管理系统,经过反复的讨论,最后决定选择Apache做为Web服务器,MySQL为数据库,PHP为开发平台建立这个系统。
在考虑到Apche和MySQL都非常稳定的同时,也考虑PHP强大的脚本语言功能也为实现这套系统提供了强有力的支持。经过近两个月的“煎熬”,终于推出了第一个试用的版本,随即给客户安装试用。兴奋的同时也感到了些许压力,因为大家觉得对MySQL都还没有非常深入的掌握,所以在提供试用版的时候,就向客户建议只录入些虚拟的数据进行测试,以免重要数据的丢失或失窃。
在所有的担心中,对MySQL数据库安全性的担心更多些。接下来大家把提高和增强MySQL安全性的任务交给了我,谁叫我是DBA呢,没办法。经过三天的搜集和整理,同时结合客户反映的实际情况,最后对MySQL做了一系列的调整和配置,不仅增强了安全性,还为将来的项目实施积累了难得的经验。
因为很多知识来源于书籍和网络,因此也想将这些经验与各位网友分享。
一、设置root和匿名用户的密码:
首先就是考虑如何设置DBA密码的问题,大家知道很多数据库在安装的过程中都会提示用户设置数据默认用户(root)的密码,而这些设置通常也正是容易被忽略的地方。一旦用户未设置root的密码,那么任何以root身份登陆的连接尝试都将可能获得MySQL的所有权限,后果也许将是灾难性的。因此笔者设置了字母+数字的组合式密码,同时强烈建议各位网友不要使用简单的数字作为密码,例如不要使用生日、用户名、电话号码或字典中的单词这些容易识别的启发式密码。
其实空密码可以是空或非空,不允许用通配符。一个空密码并不意味着匹配任何密码,它意味着用户必须不指定任何密码。密码以一个加密过的值存储在文件中的,不是一个字面上的明文文本。如果用户在Password列中存储一个照字面上的密码,用户将不能连接!
其次更容易被忽略的就是默认的匿名用户的密码,因为在默认设置下,这个匿名用户在localhost上几乎拥有和root一 样的权限,这也正是MySQL另外一个与其他类型的数据库不同的地方。熟悉PHP的朋友都知道,PHP有脚本语言的功能,功能虽然强大,但同时也带来了一定的安全隐患。试着写了一个 很简单的执行sql语句的 PHP文件上传上去,其中连接参数的user,password都设置成空,Host=Localhost,结 果发现我的SQL语句竟然可以顺利执行,于是执行select * from mysql.user;察看用户权限,发现这个用户在Localhost权限非常的高,连grant_priv的权限都有。令我们吃惊同时,接着又进行了另外一项测试,我用这个php页面创建一个新的用户,并grant给他较高的权限,结果一举成功,这样就可以用这个新用户通过本机的MySQL Client连接到客户网站的MySQL Server,并可以利用这个新建的用户管理权限对客户网站的MySQL Server进行管理了。当我想其他团队成员通告这个消息的时候,他们开始的时候没有一个相信,经过实际的演示后,大家都感慨数据库用户口令的重要性。
经过再三的讨论,最后我们大家都赞成将这个匿名用户删除,“斩草除根”以免后患。其实也可以使用更改root口令一样的方法设置这个匿名用户的密码:
Mysql> UPDATE user set password=PASSWORD(yournewpassword) where user=;
Mysql>FLUSH PRIVILEGES;因为大家对匿名用户的具体权限都不是非常的清楚,所以最后还是决定将这个用户删除,这虽然是个笨办法,但也是最有效的方法。
二、合理分配用户权限:
经过第一步的密码设置,客户的MySQL基本上杜绝了来自非法用户的登陆,这时有一个队员向大家提出了一个新问题(对于我们来说)“如果用户口令失窃的情况发生,将如何应对?”。由此引出下一个话题――合理配置用户权限。
检查mysql.user表,取消普通用户的Process_priv、Shutdown_priv、Reload_priv和File_priv权限,这些权限可能会泄漏服务器的信息包括非MySQL的其它信息。
在MySQL中,除了root用户外,其他用户包括匿名用户(如果没有删除这个匿名用户)不应该拥有grant权限,防止管理权限不受控制的扩散出去。为了防止用户的权限过高,我们采取了给新建用户设置最小权限的方式,将grant权限控制在最小的范围内。赋予用户Update、Delete、Alert、Create、Drop权限的时候,应该限定到指定的数据库,特别要避免让普通用户拥有对MySQL数据库做操作的权限。同时结合以往编程的经验,单独建立一张用户身份和权限的表,提供给程序使用,当用户访问业务逻辑时,先判断用户在该系统内是否拥有相应的权限,通过程序控制的方式提高数据库的安全性,也避免了敏感和特殊数据的未授权访问。还可以判断该用户的登陆次数,最好限制每个用户只能同时登陆一次,这样,当一个用户同时登陆时,系统将记录该用户的信息,便于安全管理和查询。最后建议:千万不要试用明码存放用户的密码。
通过上述步骤,就使MySQL合法用户在密码失窃的时候,将损失降到最小的程度。
三、外部安全性-保证网络访问的安全:
原本这套系统就是为了完成各个分公司远程的销售数据的采集和管理,因此来此远程的TCP/IP访问是不可避免的。
如果用户与服务器间的数据交互是以纯文本形式发生,黑客就非常容易地“嗅出”这些在网络上传送的数据包,从而获得这些机密的数据信息。可以激活MySQL数据库配置中的SSL,或者应用一个OpenSSH安全应用,来为传送的数据建立一个安全的加密“通道”,从而关闭这个漏洞。通过这样加密用户与服务器之间的连接,可使未经过授权的用户极难破解网络传输的往来数据。通过这个漏洞的关闭,使得我们在网络上传送数据的安全性得到极大的提高。
MySQL的安全系统是比较灵活的,它允许用户以多种不同的方式设置用户权限。一般地,用户可使用标准的SQL语句GRANT、REVOKE语句做,可以用此语句修改控制客户访问的授权表。但是,老版本的MySQL(3.22.11之前)是不支持这些语句的。或者发觉用户权限不是以你预计的方式工作。对于这种情况,了解MySQL授权表的结构和服务器如何利用它们决定访问权限是有帮助的,这样的了解允许你通过直接修改授权表增加、删除或修改用户权限,它也允许你在检查这些表时确定权限问题。
对GRANT和REVOKE语句详细描述,见《MySQL参考手册》,这里不再详述。
通过网络连接服务器的用户对MySQL数据库的访问由授权表的内容来得到控制。这些表位于mysql数据库中,并在第一次安装MySQL的过程中初始化(运行 mysql_install_db脚本)。授权表共有5个表:user、host 、db、columns_priv和tables_priv。具体的MySQL授权表的结构和内容见《MySQL的用户管理》。
每当用户发出一个查询时,服务器首先检查user表,匹配用户开始连接的记录,以查看用户有何全局权限。如果用户有此权限,并且它们对查询的权限足够,服务器则执行此查询。如果用户的全局权限不够,服务器将为用户在db表中寻找,并将该记录中的权限加到用户的全局权限中。如果结果对查询足够,服务器执行此查询。如果用户的全局和数据库级组合的权限不够,服务器将继续查找,首先是tables_priv表,然后是columns_priv表。如果服务器为用户检查过所有表之后仍无足够权限,服务器最终将拒绝用户执行此查询的请求。
接下来介绍一些在用户授权时的一些预防措施,以及不明智的选择可能会带来的风险。要尽量少地授予超级用户权限,即不要启用user表中条目中的权限,而使用其它授权表,以将用户权限限制于数据库、表、列。在user表中的权限允许将影响到用户的服务器操作可能访问所有数据库中的任何表。其中FILE权限尤其危险,不要轻易授权用户这个权限。FILE权限也能会危及到没有设置足够文件访问权限的系统和运行于此系统上的数据库。最好是设置数据目录只能由服务器自身读取。服务器上任何公开可读文件的内容都可能被拥有FILE权限的用户通过网络访问。
最后可使用压缩协议(MySQL3.22以上版本才有此功能)对网络上传输的信息进行压缩。甚至为了传输的信息更加安全,大家可以考虑安装ssh(详见http://www.cs.hut.fi/ssh)。使用此协议,我们能在一个MySQL服务器与一个MySQL用户之间得到一个经过加密的TCP/IP连接。
为了提高服务器连接的访问速度,我们把服务器管理员和单个用户的用户账号和密码存储在单用户MySQL选项文件中。由于这种密码是以纯文本格式存储在本地文件中的,存在很大安全风险。因此,必须确保这样的单用户配置文件不能被系统中的其他用户访问和查看,并且将其存储在非公共的位置。
首先需要考虑的就是数据文件的安全问题。如果数据文件存放在一个不安全的地方,那还有什么安全性意思呢?人们不是常说嘛,能够被物理上访问的计算机肯定不是安全的计算机。那么能被所有用户访问的数据文件也谈不上什么安全性,我们可以对数据文件加上一定的权限,比如利用操作系统的权限,在2000中利用NTFS的特性禁止所有用户对数据文件都能进行完全操作,在Linux/Unix下面用chmod来更改文件的权限。我们还可以利用MySQL自己的权限对数据进行访问控制,没有必要为每一位用户赋予所有的权限,如果用户只需要用到Select就可以了,那么就没有必要给它Drop或是Delete的权限,最大安全就是最小的权限加上最少的服务,可以通过在数据库录下执行ls -l命令确定你的数据库是否包含不安全的文件和目录。查找有“组”和“其他用户”权限设置的文件和目录。
如果有可能,为每一个用户量身设计权限,不过这样做需要向客户了解各个用户详细的身份,做好系统结构分析的同时,还要对系统的业务范围做详尽的权限划分。
五、监控MySQL访问记录:
因为以前开发的很多都是C/S结构的系统,即使开发过几个B/S结构的系统也都运行在企业局域网的内部,因此大家对B/S架构的网络安全性,以及重要性的理解还不是很深刻。而这次却是真正的运行与英特网上的B/S结构啊,大家心里都没底。所以,当系统试用版运行到第三天的时候,我们就查看了MySQL的查询日志,发现很多陌生的访问,这才使我们意识到监控MySQL访问记录的重要性。通过查询日志不仅可以查看正常的用户连接,还可以监控来自网络的许多非法行为。
一般和更新日志必须保证安全,因为他们包含查询文本。对日志文件有访问权限的任何人可以监视数据库进行过的操作。
通过了解,MySQL带有许多不同的日志记录文件,它们记录用户连接、用户查询和服务器发生的错误。其中尤为重要的是一般查询日志,它详细地记录每个用户的连接和中断的时间,同时记录了任何用户执行的每一个查询,如果管理人员怀疑发生了异常的行为,例如恶意篡改、网络入侵等,那么监控这个日志文件,得以了解这些攻击行为的最初来源是个非常好的办法。
六、坚持不懈:
虽然通过以上的设置,很大程度的提高了MySQL的安全性,但数据库的管理和维护是一项长期的、持续性的工作,更何况在开发之前就已经和客户达成了协议――免费维护一年。没办法,我(也包括所有DBA)的工作就是了解更多的安全建议,积极监控日志记录并及时更新系统安全,修补系统和数据库的漏洞。只有不断地提高管理员的素养才能使得我们的系统和数据更加的安全,毕竟再先进的计算机或者软件还是靠人来管理和使用的嘛!