任何在与Internet 联网的计算机上使用MySQL 的用户都应仔细阅读本节,以避免最常见的安全问题。
讨论安全时,我们强调必须完全保护整个服务器主机的安全( 而不只是MySQL 服务器) 防范各种类型的可能的攻击:偷听、修改、重放和拒绝服务。我们在这里不能覆盖各方面的内容和措施。
MySQL 根据访问控制列表(ACL) 对所有连接、查询和其它用户尝试执行的操作进行安全管理。MySQL 客户端和服务器之间还支持SSL- 加密连接。这儿讨论的许多概念并不是MySQL 专有的;该思想几乎同样适合所有应用程序。
运行MySQL 时,应尽量遵从下面的指导:
· 不要让任何人( 除了MySQL root 账户) 访问 mysql 数据库中的 user 表! 这很关键。加密的密码才是MySQL 中的真正的密码。 知道user 表中所列的密码并且能访问该账户客访问的主机的人可以很容易地用该用户登录 。
· 学习MySQL 访问权限系统。用GRANT 和REVOKE 语句来控制对MySQL 的访问。不要授予超过需求的权限。决不能为所有主机授权。
检查清单:
o 试试mysql -u root 。如果你能够成功连接服务器而没有要任何密码,则说明有问题。任何人可以作为MySQLroot 用户用它的全部权限来连接MySQL 服务器!查阅MySQL 安装说明,应特别注意关于设置root 密码的信息。
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_host 是MySQL 服务器运行的主机:
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++ :查询流使用escape 和quote 修订符。
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 传送明文( 未加密的) 数据。该信息可以被有足够时间和能力来截取它并用于个人目的的任何人访问。相反,应使用加密协议,例如SSL 或SSH 。MySQL 支持内部SSL 连接,例如版本 4.0.0 。可以使用SSH 端口映射为通信创建加密( 并压缩) 的隧道。
· 学会使用tcpdump 和strings 工具。在大多数情况下,你可以使用下面的命令检查是否MySQL 数据流未加密:
· shell> tcpdump -l -i eth0 -w - src or dst port 3306 | strings
( 该命令在Linux 中可以工作,在其它系统中经过小小的修改后应可以工作)。 警告:如果你没有看见明文数据,并不一定说明信息实际上被加密了。如果你需要较高级别的安全,你应咨询安全专家。