第5章:数据库管理 / 5.6. 一般安全问题 / 5.6.1. 通用安全指南

任何在与Internet联网的计算机上使用MySQL的用户都应仔细阅读本节,以避免最常见的安全问题。

讨论安全时,我们强调必须完全保护整个服务器主机的安全(而不只是MySQL服务器)防范各种类型的可能的攻击:偷听、修改、重放和拒绝服务。我们在这里不能覆盖各方面的内容和措施。

MySQL根据访问控制列表(ACL)对所有连接、查询和其它用户尝试执行的操作进行安全管理。MySQL客户端和服务器之间还支持SSL-加密连接。这儿讨论的许多概念并不是MySQL专有的;该思想几乎同样适合所有应用程序。

运行MySQL时,应尽量遵从下面的指导:

·         不要让任何人(除了MySQL root账户)访问mysql数据库中的user表!这很关键。加密的密码才是MySQL中的真正的密码。知道user表中所列的密码并且能访问该账户客访问的主机的人可以很容易地用该用户登录

·         学习MySQL访问权限系统。用GRANTREVOKE语句来控制对MySQL的访问。不要授予超过需求的权限。决不能为所有主机授权。

检查清单:

o        试试mysql -u root。如果你能够成功连接服务器而没有要任何密码,则说明有问题。任何人可以作为MySQLroot用户用它的全部权限来连接MySQL服务器!查阅MySQL安装说明,应特别注意关于设置root密码的信息。参见2.9.3节,“使初始MySQL账户安全”

o        通过SHOW GRANTS语句检查查看谁已经访问了什么。然后使用REVOKE语句删除不再需要的权限。

·         不要将纯文本密码保存到数据库中。如果你的计算机有安全危险,入侵者可以获得所有的密码并使用它们。相反,应使用MD5()SHA1()或单向哈希函数。

·         不要从词典中选择密码。有专门的程序可以破解它们。即使象“xfish98”这样的密码也很差。而“duag98”要好得多,虽然包含了相同的字“fish”,但从标准QWERTY键盘向左输入。另一种方法是使用“Mhall”,来自句子“Mary had a little lamb.”中每个字的第一个字符。这样很容易记住并输入,但是不知道的人很难猜出来。

·         购买防火墙。这样可以保护你防范各种软件中至少50%的各种类型的攻击。把MySQL放到防火墙后或隔离区(DMZ)

检查清单:

o        试试从Internet使用nmap工具扫描端口。MySQL默认使用端口3306。不应从不可信任主机访问该端口。另一种检查是否MySQL端口打开的简单方式是从远程机器试试下面的命令,其中server_hostMySQL服务器运行的主机:

o                     shell> telnet server_host 3306

如果得到连接并得到一些垃圾字符,则端口打开着,则应从防火墙或路由器上关闭,除非你有合理的理由让它开着。如果telnet挂起或连接被拒绝,则端口被阻塞,这是你所希望的。

不要信任应用程序的用户输入的任何数据。它们可以用Web形式、URL或构建的应用程序输入特殊或逃溢字符序列来尝试欺骗你的代码。如果某个用户输入“; DROP DATABASE mysql;”等内容,应确保你的应用程序保持安全。这是特例,但当黑客使用类似技术时,如果你没有做好准备,结果可能会出现大的安全漏洞和数据丢失。

一个常见的错误是只保护字符串数据值。一定要记住还应检查数字数据。如果当用户输入值234时,应用程序生成查询SELECT * FROM table WHERE ID=234用户可以输入值234 OR 1=1使应用程序生成查询SELECT * FROM table WHERE ID=234 OR 1=1。结果是服务器查找表内的每个记录。这样会暴露每个记录并造成过多的服务器负载。保护防范这类攻击的最简单的方法是使用单引号将数字常量引起来:SELECT * FROM table WHERE ID='234'。如果用户输入其它信息,均变为字符串的一部分。在数字部分,MySQL自动将字符串转换为数字并剥离字符串包含的附加的非数字字符。

有时候人们会认为如果数据库只包含供公共使用的数据,则不需要保护。这是不正确的。即使允许显示数据库中的任何记录,你仍然应保护防范拒绝服务攻击(例如,基于前面段落中所述的技术的攻击,会使服务器浪费资源)。否则,你的服务器不再响应合法用户。

检查清单:

o        试试用Web形式输入单引号和双引号('’和‘")。如果得到任何形式的MySQL错误,立即分析原因。

o        试试修改动态URL,可以在其中添加%22(")%23(#)%27(')

o        试试在动态URL中修改数据类型,使用前面示例中的字符,包括数字和字符类型。你的应用程序应足够安全,可以防范此类修改和类似攻击。

o        试试输入字符、空格和特殊符号,不要输入数值字段的数字。你的应用程序应在将它们传递到MySQL之前将它们删除或生成错误。将未经过检查的值传递给MySQL是很危险的!

o        将数据传给MySQL之前先检查其大小。

o        用管理账户之外的用户名将应用程序连接到数据库。不要给应用程序任何不需要的访问权限。

·         许多应用程序编程接口提供了措施逃逸数据值中的特殊字符。如果使用正确,可以防止应用程序用户输入使应用程序生成不期望的效果的语句的数值:

o        MySQL C API:使用mysql_real_escape_string() API调用。

o        MySQL++:查询流使用escapequote修订符。

o        PHP:使用mysql_escape_string()函数基于MySQL C API中的同名函数。(PHP 4.0.3之前,使用addslashes()PHP 5,可以使用mysqli扩展名,它支持改进的MySQL鉴定协议和密码,以及用占位符编写的语句。

o        Perl DBI:使用quote()方法或使用占位符。

o        Java JDBC:使用一个PreparedStatement对象和占位符。

其它编程接口有类似的功能。

·         不要通过Internet传送明文(未加密的)数据。该信息可以被有足够时间和能力来截取它并用于个人目的的任何人访问。相反,应使用加密协议,例如SSLSSHMySQL支持内部SSL连接,例如版本 4.0.0。可以使用SSH端口映射为通信创建加密(并压缩)的隧道。

·         学会使用tcpdumpstrings工具。在大多数情况下,你可以使用下面的命令检查是否MySQL数据流未加密:

·                shell> tcpdump -l -i eth0 -w - src or dst port 3306 | strings

(该命令在Linux中可以工作,在其它系统中经过小小的修改后应可以工作)警告:如果你没有看见明文数据,并不一定说明信息实际上被加密了。如果你需要较高级别的安全,你应咨询安全专家。