当前位置: 首页 > 文档资料 > MySQL 中文手册 >

5.6. 一般安全问题

优质
小牛编辑
154浏览
2023-12-01
5.6.1. 通用安全指南
5.6.2. 使MySQL在攻击者面前保持安全
5.6.3. Mysqld安全相关启动选项
5.6.4. LOAD DATA LOCAL安全问题

本节描述一些常见的需要注意的安全问题,以及一些可以使你的MySQL安装更加安全以防止黑客和误用的措施。关于MySQL用于设置用户账户并检查数据库访问的访问控制系统的具体信息,参见5.7节,“MySQL访问权限系统”。

5.6.1. 通用安全指南

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

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

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

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

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

·学习MySQL访问权限系统。用GRANT和REVOKE语句来控制对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_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用管理账户之外的用户名将应用程序连接到数据库。不要给应用程序任何不需要的访问权限。

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

oMySQL C API:使用mysql_real_escape_string() API调用。

oMySQL++:查询流使用escape和quote修订符。

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

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

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

5.6.2. 使MySQL在攻击者面前保持安全

当你连接到MySQL服务器时,你应使用一个密码。密码不以明文在上传输。客户端连接序列中的密码处理在MySQL 4.1.1中已经升级,很安全。如果你仍然使用pre-4.1.1-风格的密码,加密算法不如新算法强;通过一些工作,可以窃取客户端和服务器之间的通信的聪明的攻击者可以破解密码。(关于不同的密码处理方法的讨论参见5.7.9节,“MySQL 4.1中的密码哈希处理”)。 如果客户端和服务器之间的连接通过不可信任网络,你应使用SSH隧道来加密通信。

所有其它信息以文本传送,可以被可以看到连接的任何人读取。如果你担心这个,你可以使用压缩协议来使通信更难以解密。要想使连接更加安全,你应使用SSH来获得加密的MySQL服务器和MySQL客户端之间的TCP/IP连接。你可以从http://www.openssh.org/找到开放源码SSH客户端,并可以从http://www.ssh.com/获得商业SSH客户端。

你还可以使用MySQL内部OpenSSL支持。参见5.8.7节,“使用安全连接”。

为了使MySQL系统安全,强烈要求你考虑下列建议:

·对所有MySQL用户使用密码。客户端程序不需要知道运行它的人员的身份。对于客户端/服务器应用程序,用户可以指定客户端程序的用户名。例如,如果other_user没有密码,任何人可以简单地用mysql -u other_user db_name冒充他人调用mysql程序进行连接。如果所有用户有密码,使用其它用户的账户进行连接要困难得多。

要想更改用户的密码,应使用SET PASSWORD语句。还可以直接更新mysql数据库中的user表。例如,要更改所有root用户的MySQL账户的密码,应:

shell> mysql -u root
mysql> UPDATE mysql.user SET Password=PASSWORD('newpwd')
    -> WHERE User='root';
mysql> FLUSH PRIVILEGES;

·绝对不要作为Unix的root用户运行MySQL服务器。这样做非常危险,因为任何具有FILE权限的用户能够用root创建文件(例如,~root/.bashrc)。为了防止,mysqld拒绝用root运行,除非使用--user=root选项明显指定。

应可以(并且应该)用普通非特权用户运行mysqld。你可以创建独立的Unix中的mysql账户来以便使所有内容更加安全。该账户只用于管理MySQL。要想用其它Unix用户启动mysqld,增加user选项指定/etc/my.cnf选项文件或服务器数据目录的my.cnf选项文件中的[mysqld]组的用户名。例如:

[mysqld]
user=mysql

该命令使服务器用指定的用户来启动,无论你手动启动或通过mysqld_safemysql.server启动。详细信息参见A.3.2节,“如何以普通用户身份运行MySQL”。

作为其它Unix用户而不用root运行mysqld,你不需要更改user表中的root用户名,因为MySQL账户的用户名与Unix账户的用户名无关。

·不要允许使用表的符号链接。(可以用--skip-symbolic-links选项禁用)。如果你用root运行mysqld则特别重要,因为任何对服务器的数据目录有写访问权限的人则能够删除系统中的任何文件!参见7.6.1.2节,“在Unix平台上使用表的符号链接”。

·确保mysqld运行时,只使用对数据库目录具有读或写权限的Unix用户来运行。

·不要将PROCESS或SUPER权限授给非管理用户。mysqladmin processlist的输出显示出当前执行的查询正文,如果另外的用户发出一个UPDATE user SET password=PASSWORD('not_secure')查询,被允许执行那个命令的任何用户可能看得到。

mysqld为有SUPER权限的用户专门保留一个额外的连接,因此即使所有普通连接被占用,MySQLroot用户仍可以登录并检查服务器的活动。

可以使用SUPER权限来终止客户端连接,通过更改系统变量的值更改服务的器操作,并控制复制服务器。

·不要向非管理用户授予FILE权限。有这权限的任何用户能在拥有mysqld守护进程权限的文件系统那里写一个文件!为了更加安全,由SELECT ... INTO OUTFILE生成的所有文件对每个人是可写的,并且你不能覆盖已经存在的文件。

file权限也可以被用来读取任何作为运行服务器的Unix用户可读取或访问的文件。使用该权限,你可以将任何文件读入数据库表。这可能被滥用,例如,通过使用LOAD DATA装载“/etc/passwd”进一个数据库表,然后能用SELECT显示它。

·如果你不信任你的DNS,你应该在授权表中使用IP数字而不是主机名。在任何情况下,你应该非常小心地使用包含通配符的主机名来创建授权表条目!

·如果你想要限制单个账户允许的连接数量,你可以设置mysqld中的max_user_connections变量来完成。GRANT语句也可以支持 资源控制选项来限制服务器对一个账户允许的使用范围。参见13.5.1.3节,“GRANT和REVOKE语法”。

5.6.3. Mysqld安全相关启动选项

下列mysqld选项影响安全:

·--allow-suspicious-udfs

该选项控制是否可以载入主函数只有xxx符的用户定义函数。默认情况下,该选项被关闭,并且只能载入至少有辅助符的UDF。这样可以防止从未包含合法UDF的共享对象文件载入函数。参见27.2.3.6节,“用户定义函数安全注意事项”。

·--local-infile[={0|1}]

如果用--local-infile=0启动服务器,则客户端不能使用LOCAL in LOAD DATA语句。参见5.6.4节,“LOAD DATA LOCAL安全问题”。

·--old-passwords

强制服务器为新密码生成短(pre-4.1)密码哈希。当服务器必须支持旧版本客户端程序时,为了保证兼容性这很有用。参见5.7.9节,“MySQL 4.1中的密码哈希处理”。

·(OBSOLETE)--safe-show-database

在以前版本的MySQL中,该选项使SHOW DATABASES语句只显示用户具有部分权限的数据库名。在MySQL 5.1中,该选项不再作为现在的默认行为使用,有一个SHOW DATABASES权限可以用来控制每个账户对数据库名的访问。参见13.5.1.3节,“GRANT和REVOKE语法”。

·--safe-user-create

如果启用,用户不能用GRANT语句创建新用户,除非用户有mysql.user表的INSERT权限。如果你想让用户具有授权权限来创建新用户,你应给用户授予下面的权限:

mysql> GRANT INSERT(user) ON mysql.user TO 'user_name'@'host_name';

这样确保用户不能直接更改权限列,必须使用GRANT语句给其它用户授予该权限。

·--secure-auth

不允许鉴定有旧(pre-4.1)密码的账户。

·--skip-grant-tables

这个选项导致服务器根本不使用权限系统。这给每个人以完全访问所有的数据库的权力!(通过执行mysqladmin flush-privilegesmysqladmin reload命令,或执行FLUSH PRIVILEGES语句,你能告诉一个正在运行的服务器再次开始使用授权表。)

·--skip-name-resolve

主机名不被解析。所有在授权表的Host的列值必须是IP号或localhost。

·--skip-networking

在网络上不允许TCP/IP连接。所有到mysqld的连接必须经由Unix套接字进行。

·--skip-show-database

使用该选项,只允许有SHOW DATABASES权限的用户执行SHOW DATABASES语句,该语句显示所有数据库名。不使用该选项,允许所有用户执行SHOW DATABASES,但只显示用户有SHOW DATABASES权限或部分数据库权限的数据库名。请注意全局权限指数据库的权限。

5.6.4. LOAD DATA LOCAL安全问题

LOAD DATA语句可以装载服务器主机上的文件,若指定LOCAL关键字,可以装载客户端文件。

支持LOCAL版本的LOAD DATA语句有两个可能的安全问题:

·由MySQL服务器启动文件从客户端向服务器主机的传输。理论上,打过补丁的服务器可以告诉客户端程序传输服务器选择的文件,而不是客户用LOAD DATA语句指定的文件。这样服务器可以访问客户端上客户有读访问权限的任何文件。

·在Web环境中,客户从Web服务器连接,用户可以使用LOAD DATA LOCAL来读取Web服务器进程有读访问权限的任何文件(假定用户可以运行SQL服务器的任何命令)。在这种环境中,MySQL服务器的客户实际上是Web服务器,而不是连接Web服务器的用户运行的程序。

要处理这些问题,我们更改了MySQL 3.23.49和MySQL 4.0.2(Windows中的4.0.13)中的LOAD DATA LOCAL的处理方法:

·默认情况下,现在所有二进制分中的发MySQL客户端和库是用--enable-local-infile选项编译,以便与MySQL 3.23.48和以前的版本兼容。

·如果你从源码构建MySQL但没有使用--enable-local-infile选项来进行configure,则客户不能使用LOAD DATA LOCAL,除非显式调用mysql_options (...MYSQL_OPT_本地_INFILE,0)。参见25.2.3.48节,“mysql_options()”。

·你可以用--local-infile=0选项启动mysqld从服务器端禁用所有LOAD DATA LOCAL命令。

·对于mysql命令行客户端,可以通过指定--local-infile[=1]选项启用LOAD DATA LOCAL,或通过--local-infile=0选项禁用。类似地,对于mysqlimport,--local or -L选项启用本地数据文件装载。在任何情况下,成功进行本地装载需要服务器启用相关选项。

·如果你使用LOAD DATA LOCAL Perl脚本或其它读选项文件中的[client]组的程序,你可以在组内添加local-infile=1选项。但是,为了便面不理解local-infile的程序产生问题,则规定使用loose- prefix:

·[client]
·loose-local-infile=1

·如果LOAD DATA LOCAL INFILE在服务器或客户端被禁用,试图执行该语句的客户端将收到下面的错误消息:

ERROR 1148: The used command is not allowed with this MySQL version