MySQL是最受DBA欢迎的数据库之一,易用性和高性能是MySQL数据库的标志。然而,高人气使得MySQL成为很多恶意个人和组织攻击的目标。默认安装的MySQL在安全措施方面存在较大隐患,特别是根密码空缺和缓冲区溢出的潜在漏洞,使其成为最容易受攻击的目标。在本文中,我们将介绍一些简单而有效的方法来加强数据库的安全性,以抵御本地以及远程的攻击。
常见安全行为
作为DBA,与安全相关的工作应当围绕以下三方面展开:
•打补丁
•限制访问
•避免有用信息收集
本文剩余部分将会在细节上讨论以上三个行为,并将重点放在对网络、操作系统以及数据库服务器的限制访问上。
安全补丁
尽管每个人都会尽最大努力去保护数据,但永远会有人发现可以利用的漏洞。数据库供应商会检查引起问题的漏洞,并提供相应的漏洞补丁程序。
为MySQL寻找相关安全补丁最好的去处之一便是Oracle的官方网站。你需要经常访问MySQL论坛,并关注相关动向。它们通常是安全警报最先发出的地方。
防止对系统的访问
有四项主要的来源是需要注意的:
•对网络的访问
•对数据库的直接访问
•对备份的访问
•对操作系统的访问,包括数据和日志文件
以上每一项都有其自身所面临的挑战和解决途径:
对网络的访问
如果你所在的局域网或广域网并不安全,你需要考虑对服务器和客户端之间的网络连接进行加密。非授权用户能够以某种方式获得对特权用户账户(例如root) 的访问权限么,他们可以利用类似tcpdump的工具嗅探发往MySQL的网络流并过滤数据包。这些数据包是会包含查询和数据的。
默认情况下,MySQL是以最佳性能配置的,因此除非对连接进行人工设置,否则所有连接都是非加密的。而通常是采用SSL协议对所有在MySQL客户端和服务器之间发送的数据进行加密。
MySQL可以基于每个连接进行加密,因此你可以根据各个应用程序的需求来选择使用非加密连接或是安全的加密SSL连接。
对数据库的访问
对于黑客来说,首要的潜在入口点之一就是root账户。因此,对密码进行重置和对ID重命名是至关重要的。
...当你拿到一个默认安装的MySQL时,首先要做的就是为root用户设置密码。
$ mysqladmin -u root password NEWPASSWORD
一旦设置了密码,将”root” 改成其他名字,安全性将会更好。一个黑客比较青睐于在MySQL服务器上将root用户作为目标,既是由于其超级用户身份,也是因为它是已知用户。通过改变root用户名,会让黑客进行成功攻击变得更困难。使用以下一系列命令可以重命名“root” 用户:
mysql> RENAME USER root TO new_user;
除此之外,让超级用户的数量保持在绝对意义上的最小对掌控数据库是非常关键的。而太多的超级账号是存在隐患的,实际上,就关键数据而言,如果你不小心就有可能失去很多东西。
有一个账户类型是DBA们所钟爱的,即只读用户。这是最好用的一类账户类型,因为持有它的用户实际上是无法对数据库或其数据造成破坏的。通常,用户会编造一些理由来解释他们为何需要写权限。而确定一个特定权限是否有其真正价值的试金石就是在某种程度上将其简单的移除,然后观察是否有人对此抱怨。如果什么都不发生就最好了。以我的经验,只有很少的用户渴望权限。而余下的用户并不需要额外的权限。其实,我并非提倡通过关闭用户权限来欺瞒你的客户,我所要阐释的是要对用户的工作模式加以正确的分析。有些事情可以通过简单的质量审计就可以非常轻易的完成。
对备份的访问
理想情况,只要对备份进行离线存储,这样当主站有故障发生时就不会对备份造成影响。此外,所有保护你数据库服务器网络的步骤同样适用于备份系统。有一些优秀的软件模型可以对你的数据进行加密,因此,即便是备份文件在不大可能的情况下落入他人之手,其内容对于偷盗者而言也是无用的。
这里是一个用PHP语言写的加密函数,它利用的是“rijndael-256”模型:
代码语言:javascript复制public function encrypt( $msg, $k, $base64 = false ) {
if ( ! $td = mcrypt_module_open('rijndael-256', '', 'ctr', '') ) return false;
$msg = serialize($msg);
$iv = mcrypt_create_iv(32, MCRYPT_RAND);
if ( mcrypt_generic_init($td, $k, $iv) !== 0 ) return false;
$msg = mcrypt_generic($td, $msg); # encrypt
$msg = $iv . $msg; # prepend iv
$mac = $this->pbkdf2($msg, $k, 1000, 32); # create mac
$msg .= $mac; # append mac
mcrypt_generic_deinit($td); # clear buffers
mcrypt_module_close($td); # close cipher module
if ( $base64 ) $msg = base64_encode($msg);
return $msg;
}
对操作系统的访问
本地操作系统可以使用认证,防火墙以及其他防病毒软件进行联合防护。其他的访问控制机制包括用户名密码策略,受管辖的使用组策略(GPO),以及过滤特定的访问对象。
Oracle对此有很好的在线资源供参考。
另外补充一些安全注意点:
1.如果客户端和服务器端的连接需要跨越并通过不可信任的网络,那么就需要使用SSH隧道来加密该连接的通信。
2.用set password语句来修改用户的密码,三个步骤 “先mysql -u root登陆数据库系统” 然后“mysql> update mysql.user set password=password('newpwd')” 最后执行“flush privileges”就可以了。
3.需要提防的***有,防偷听、篡改、回放、拒绝服务等,不涉及可用性和容错方面。对所有的连接、查询、其他操作使用基于ACL即访问控制列表的安全措施来完成。也有一些对SSL连接的支持。
4.除了root用户外的其他任何用户不允许访问mysql主数据库中的user表;
加密后存放在user表中的加密后的用户密码一旦泄露,其他人可以随意用该用户名/密码相应的数据库;
5.用grant和revoke语句来进行用户访问控制的工作;
6.不使用明文密码,而是使用md5()和sha1()等单向的哈系函数来设置密码;
7.不选用字典中的字来做密码;
8.采用防火墙来去掉50%的外部危险,让数据库系统躲在防火墙后面工作,或放置在DMZ区域中;
9.从因特网上用nmap来扫描3306端口,也可用telnet server_host 3306的方法测试,不能允许从非信任网络中访问数据库服务器的3306号TCP端口,因此需要在防火墙或路由器上做设定;
10.为了防止被恶意传入非法参数,例如where ID=234,别人却输入where ID=234 OR 1=1导致全部显示,所以在web的表单中使用''或""来用字符串,在动态URL中加入"代表双引号、#代表井号、'代表单引号;传递未检查过的值给mysql数据库是非常危险的;
11.在传递数据给mysql时检查一下大小;
12.应用程序需要连接到数据库应该使用一般的用户帐号,只开放少数必要的权限给该用户;
13.在各编程接口(C C PHP Perl Java JDBC等)中使用特定‘逃脱字符’函数;
在因特网上使用mysql数据库时一定少用传输明文的数据,而用SSL和SSH的加密方式数据来传输;
14.学会使用tcpdump和strings工具来查看传输数据的安全性,例如tcpdump -l -i eth0 -w -src or dst port 3306 | strings。以普通用户来启动mysql数据库服务;
15.不使用到表的联结符号,选用的参数 --skip-symbolic-links;
16.确信在mysql目录中只有启动数据库服务的用户才可以对文件有读和写的权限;
17.不许将process或super权限付给非管理用户,该mysqladmin processlist可以列举出当前执行的查询文本;super权限可用于切断客户端连接、改变服务器运行参数状态、控制拷贝复制数据库的服务器;
18.file权限不付给管理员以外的用户,防止出现load data '/etc/passwd'到表中再用select 显示出来的问题;
19.如果不相信DNS服务公司的服务,可以在主机名称允许表中只设置IP数字地址;
20.使用max_user_connections变量来使mysqld服务进程,对一个指定帐户限定连接数;
21.grant语句也支持资源控制选项;
22.启动mysqld服务进程的安全选项开关,--local-infile=0或1 若是0则客户端程序就无法使用local load data了,赋权的一个例子grant insert(user) on mysql.user to'user_name'@'host_name';若使用--skip-grant-tables系统将对任何用户的访问不做任何访问控制,但可以用mysqladmin flush-privileges或mysqladmin reload来开启访问控制;默认情况是show databases语句对所有用户开放,可以用--skip-show-databases来关闭掉。
23.碰到Error 1045(28000) Access Denied for user'root'@'localhost'(Using password:NO)错误时,你需要重新设置密码,具体方法是:先用--skip-grant-tables参数启动mysqld,然后执行mysql -u root mysql,mysql>update user set password=password('newpassword') where user='root';mysql>Flush privileges;,最后重新启动mysql就可以了。
结论
有各种各样保护MySQL数据的方法,在本文中我们只介绍了一些基础方法。在一场无尽的战斗中,要让数据库免受攻击,一种方法不可能一劳永逸。相反,必须始终保持警惕并保证自己熟悉最新的安全漏洞和相应对策。记住,打造世界上最安全的数据库并不是你的目标,你只需要让黑客们付出足够的精力才能攻破你的数据库,这样黑客们就会转向更易攻击的目标。
参考文章
更多相关知识和参考文章来源可以关注我的博客网站-互联网技术教程