您的位置:首页 > 博客中心 > 数据库 >

ch4 MySQL 安全管理

时间:2022-03-14 03:03

第 4 章 MySQL 安全管理

前言

对于任何一个企业来说,其数据库系统中所保存数据的安全性无疑是非常重要的,尤其是公司的有些商业数据,可能数据就是公司的根本,失去了数据的安全性,可能就是失去了公司的一切。本章将针对????MySQL????的安全相关内容进行较为详细的介绍。

41 数据库系统安全相关因素

  1. 外围网络:

MySQL 的大部分应用场景都是基于网络环境的,而网络本身是一个充满各种入侵危险的环境,所以要保护他的安全,在条件允许的情况下,就应该从最外围的网络环境开始"布防",因为这一层防线可以从最大范围内阻止可能存在的威胁。

在网络环境中,任意两点之间都可能存在无穷无尽的"道路"可以抵达,是一个真正"条条道路通罗马"的环境。在那许许多多的道路中,只要有一条道路不够安全,就可能被入侵者利用。当然,由于所处的环境不同,潜在威胁的来源也会不一样。有些 MySQL 所处环境是暴露在整个广域网中,可以说是完全"裸露"在任何可以接入网络环境的潜在威胁者面前。而有些 MySQL 是在一个环境相对小一些的局域网之内,相对来说,潜在威胁者也会少很多。处在局域网之内的 MySQL,由于有局域网出入口的网络设备的基本保护,相对于暴露在广域网中要安全不少,主要威胁对象基本上控制在了可以接入局域网的内部潜在威胁者,和极少数能够突破最外围防线(局域网出入口的安全设备)的入侵者。所以,尽可能的让我们的

MySQL 处在一个有保护的局域网之中,是非常必要的。

  1. 主机:

有了网络设备的保护,我们的 MySQL 就足够安全了么?我想大家都会给出否定的回答。因为即使我们局域网出入口的安全设备足够的强大,可以拦截住外围试图入侵的所有威胁者,但如果威胁来自局域网内部呢?比如局域网中可能存在被控制的设备,某些被控制的有权限接入局域网的设备,以及内部入侵者等都仍然是威胁者。所以说,吉使在第一层防线之内,我们仍然存在安全风险,局域网内部仍然会有不少的潜在威胁存在。

这个时候就需要我们部署第二道防线"主机层防线"了 。"主机层防线"主要拦截网络(包括局域网内)或者直连的未授权用户试图入侵主机的行为。因为一个恶意入侵者在登录到主机之后,可能通过某些软件程序窃取到那些自身安全设置不够健壮的数据库系统的登入口令,从而达到窃取或者破坏数据的目的。如一个主机用户可以通过一个未删除且未设置密码的无用户名本地帐户轻易登入数据库,也可以通过 MySQL 初始安装好之后就存在的无密码的"root@localhost"用户登录数据库并获得数据库最高控制权限。非法用户除了通过登入数据库获取(或者破坏)数据之外,还可能通过主机上面相关权限设置的漏洞,跳过数据库而直接获取 MySQL 数据(或者日志)文件达到窃取数据的目的,或者直接删除数据(或者日志)文件达到破坏数据的目的。

  1. 数据库:

通过第二道防线"主机层防线"的把守,我们又可以挡住很大一部分安全威胁者。但仍然可能有极少数突破防线的入侵者。而且即使没有任何"漏网之鱼",那些有主机登入权限的使用者呢?是否真的就是完全可信任对象?No,我们不能轻易冒这个潜在风险。对于一个有足够安全意识的管理员来说,是不会轻易放任任何一个潜在风险存在的。

这个时候,我们的第三道防线,"数据库防线"就需要发挥他的作用了。"数据库防线" 也就是 MySQL 数据库系统自身的访问控制授权管理相关模块。这道防线基本上可以说是 MySQL 的最后一道防线了,也是最核心最重要的防线。他首先需要能够抵挡住在之前的两层防线都没有能够阻拦住的所有入侵威胁,同时还要能够限制住拥有之前二层防线自由出入但不具备数据库访问权限的潜在威胁者,以确保数据库自身的安全以及所保存数据的安全。

之前的二层防线对于所有数据库系统来说基本上区别不大,都存在着基本相同的各种威胁,不论是 Oracle 还是 MySQL,以及任何其他的数据库管理系统,都需要基本一致的"布防"策略。但是这第三层防线,也就是各自自身的"数据库防线"对于每个数据库系统来说都存在较大的差异,因为每种数据库都有各自不太一样的专门负责访问授权相关功能的模块。不论是权限划分还是实现方式都可能不太一样。

对于 MySQL 来说,其访问授权相关模块主要是由两部分组成。一个是基本的用户管理模块,另一个是访问授权控制模块。用户管理模块的功能相对简单一些,主要是负责用户登录连接相关的基本权限控制,但其在安全控制方面的作用却不比任何环节小。他就像 MySQL 的一个"大门门卫"一样,通过校验每一位敲门者所给的进门"暗号"(登入口令),决定是否给敲门者开门。而访问授权控制模块则是随时随地检查已经进门的访问者,校验他们是否有访问所发出请求需要访问的数据的权限。通过校验者可顺利拿到数据,而未通过校验的访问者,只能收到"访问越权了"的相关反馈。

上面的三道防线组成了如图 4-1 所示的三道坚固的安全保护壁垒,就像三道坚固的城墙一样保护这 MySQL 数据库中的数据。只要保障足够,基本很难有人能够攻破这三道防线。

gxlsystem.com,布布扣

图 4-1

四、代码:

    4.2.3 权限级别

    MySQL 中的权限分为五个级别,分别如下:

    1、Global????Level:

    Global????Level 的权限控制又称为全局权限控制,所有权限信息都保存在 mysql.user 表中。Global????Level 的所有权限都是针对整个 mysqld 的,对所有的数据库下的所有表及所有字段都有效。如果一个权限是以 Global????Level 来授予的,则会覆盖其他所有级别的相同权限设置。比如我们首先给 abc 用户授权可以 UPDATE????指定数据库如 test 的 t 表,然后又在全局级别 REVOKE 掉了 abc 用户对所有数据库的所有表的 UPDATE 权限。则这时候的 abc 用户将不再拥有用对 test.t 表的更新权限。Global????Level 主要有如下这些权限(见表 4-1):

    表????4-1

    图 4-2 1、 用户管理我们先看看用户管理模块是如何工作的。在 MySQL 中,用户访问控制部分的实现比较简单,所有授权用户都存放在一个系统表中:mysql.user,当然这个表不仅仅存放了授权用户的基本信息,还存放有部分细化的权限信息。用户管理模块需要使用的信息很少,主要就是

    Host,User,Password 这三项,都在 mysql.user 表中,如下: sky@localhost : (none) 12:35:04> USE mysql; Database changed sky@localhost : mysql 12:35:08> DESC user;

    +---------------+--------------------+------+-----+---------+-------+

    ????|????Field????|????Type????|????Null????|????Key????|????Default????|????Extra????|

    +---------------+--------------------+------+-----+---------+-------+

    root@localhost????:????mysql????01:18:12>????SELECT????host,user,password????FROM????user????ORDER????BY user; +--------------------+------+-------------------------------------------+

    |????host????|????user????|????password????|

    +--------------------+------+-------------------------------------------+

    图 4-3

    在前面我们了解到 MySQL 的 grant tables 有 mysql.user,mysql.db,mysql.host, mysql.table_priv 和 mysql.column_priv 这五个,我想出了 mysql.host 之外的四个都是非常容易理解的,每一个表针对 MySQL 中的一种逻辑对象,存放某一特定 Level 的权限,唯独 mysql.host 稍有区别。我们现在就来看看 mysql.host 权限表到底在 MySQL 的访问控制中充当了一个什么样的角色呢?

    mysql.host 在 MySQL 访问控制模块中所实现的功能比较特殊,和其他几个 grant tables 不太一样。首先是 mysql.host 中的权限数据不是(也不能)通过 GRANT 或者 REVOKE 来授予或者去除,必须通过手工通过 INSERT、UPDATE 和 DELETE 命令来修改其中的数据。其次是其中的权限数据无法单独生效,必须通过和 mysql.db 权限表的数据一起才能生效。而且仅当 mysql.db 中存在不完整(某些场景下的特殊设置)的时候,才会促使访问控制模块再结合 mysql.host 中查找是否有相应的补充权限数据实现以达到权限校验的目的,就比如上图中所示。在 mysql.db 中无法找到满足权限校验的所有条件的数据(db.User = ‘abc‘ AND db.host = ‘localhost‘ AND db.Database_name = ‘test‘),则说明在 mysql.db 中无法完成权限校验,所以也不会直接就校验 db.Select_priv 的值是否为‘Y‘。但是 mysql.db 中有 db.User = ‘abc‘ AND db.Database_name = ‘test‘ AND db.host = ‘‘ 这样一条权限信息存在,大家可能注意到了这条权限信息中的 db.host 中是空值,注意是空值而不是‘%‘这个通配符哦。当 MySQL 注意到有这样一条权限信息存在的时候,就该是 mysql.host 中所存放的权限信息出场的时候了。这时候,MySQL 会检测 mysql.host 中是否存在满足如下条件的权限信息:host.Host = ‘localhost‘ AND host.Db = ‘test‘。如果存在,则开始进行 Select_priv 权限的校验。由于权限信息存在于 mysql.db 和 mysql.host 两者之中,而且是两者信息合并才能满足要求,所以 Select_priv 的校验也需要两表都为‘Y‘才能满足要求,通过校验。

    我们已经清楚,MySQL 的权限是授予"username@hostname"的,也就是说,至少需要用户名和主机名二者才能确定一个访问者的权限。又由于 hostname 可以是一个含有通配符的域名,也可以是一个含有通配符的 IP 地址段。那么如果同一个用户有两条权限信息,一条是针对特定域名的,另外一个是含有通配符的域名,而且前者属于后者包含。这时候 MySQL 如何来确定权限信息呢?实际上 MySQL 永远优先考虑更精确范围的权限。在 MySQL 内部会按照 username 和 hostname 作一个排序,对于相同 username 的权限,其 host 信息越接近访问者的来源 host,则排序位置越靠前,则越早被校验使用到。而且,MySQL 在权限校验过程中 ,只要找到匹配的权限之后,就不会再继续往后查找是否还有匹配的权限信息,而直接完成校验过程。

    大家应该也看到了在 mysql.user 这个权限表中有 max_questions,max_updates, max_connections,max_user_connections 这四列,前面三列是从 MySQL4.0.2 版本才开始有的,其功能是对访问用户进行每小时所使用资源的限制,而最后的 max_user_connections 则是从 MySQL5.0.3 版本才开始有的,他和 max_connections 的区别是限制耽搁用户的连接总次数,而不是每小时的连接次数。而要使这四项限制生效,需要在创建用户或者给用户授权的时候加上以下四种子句:

    max_questions????:

    WITH????MAX_QUERIES_PER_HOUR n;

    max_updates????:

    WITH????MAX_UPDATES_PER_HOUR n;

    max_connections????:

    WITH????MAX_CONNECTIONS_PER_HOUR n;

    max_user_connections:

    MAX_USER_CONNECTIONS。

    四个子句可以同时使用,如:

    ????"????WITH????MAX_QUERIES_PER_HOUR????5000????MAX_CONNECTIONS_PER_HOUR????10

    MAX_USER_CONNECTIONS 10000"。

    43 MySQL 访问授权策略

    在我们了解了影响数据库系统安全的相关因素以及 MySQL 权限系统的工作原理之后,就需要为我们的系统设计一个安全合理的授权策略。我想,每个人心里都清楚,要想授权最简单最简单方便,维护工作量最少,那自然是将所有权限都授予所有的用户来的最简单方便了 。但是,我们大家肯定也都知道,一个用户所用有的权限越大,那么他给我们的系统所带来的潜在威胁也就越大。所以,从安全方面来考虑的话,权限自然是授予的越小越好。一个有足够安全意识的管理员在授权的时候,都会只授予必要的权限,而不会授予任何多余的权限。既然我们这一章是专门讨论安全的,那么我们现在也就从安全的角度来考虑如何设计一个更为安全合理的授权策略。

    首先,需要了解来访主机。

    由于 MySQL 数据库登录验证用户的时候是出了用户名和密码之外,还要验证来源主机。所以我们还需要了解每个用户可能从哪些主机发起连接。当然,我们也可以通过授权的时候直接通过"%"通配符来给所有主机都有访问的权限,但是这样作就违背了我们安全策略的原则,带来了潜在风险,所以并不可取。尤其是在没有局域网的防火墙保护的情况下,更是不能轻易允许可以从任何主机登录的用户存在。能通过具体主机名或者 IP 地址指定的尽量通过使用具体的主机名和 IP 地址来限定来访主机,不能用具体的主机名或者 IP 地址限定的也需要用尽可能小的通配范围来限定。

    其次,了解用户需求。

    既然是要做到仅授予必要的权限,那么我们必须了解每个用户所担当的角色,也就是说 ,我们需要充分了解每个用户需要连接到数据库上完成什么工作。了解该用户是一个只读应用的用户,还是一个读写都有的帐户;是一个备份作业的用户还是一个日常管理的帐户;是只需要访问特定的某个(或者某几个)数据库(Schema),还是需要访问所有的数据库。只有了解了需要做什么,才能准确的了解需要授予什么样的权限。因为如果权限过低,会造成工作无法正常完成,而权限过高,则存在潜在的安全风险。

    再次,要为工作分类。

    为了做到各司其职,我们需要将需要做的工作分门别类,不同类别的工作使用不同的用户,做好用户分离。虽然这样可能会带来管理成本方面的部分工作量增加,但是基于安全方面的考虑,这部分管理工作量的增加是非常值得的。而且我们所需要做的用户分离也只是一个适度的分离。比如将执行备份工作、复制工作、常规应用访问、只读应用访问和日常管理工作分别分理出单独的特定帐户来授予各自所需权限。这样,既可以让安全风险尽量降低,也可以让同类同级别的相似权限合并在一起,不互相交织在一起。对于 PROCESS,FILE 和

    SUPER 这样的特殊权限,仅仅只有管理类帐号才需要,不应该授予其他非管理帐号。

    ????最后,确保只有绝对必要者拥有 GRANT????OPTION????权限。

    之前在权限系统介绍的时候我们已经了解到 GRANT????OPTION 权限的特殊性,和拥有该权限之后的潜在风险,所以在这里也就不再累述了。总之,为了安全考虑,拥有 GRANT OPTION 权限的用户越少越好,尽可能只让拥有超级权限的用户才拥有 GRANT OPTION 权限。

    44 安全设置注意事项

    在前面我们了解了影响数据库系统安全的几个因素,也了解了 MySQL 权限系统的相关原理和实现,这一节我们将针对这些因素进行一些基本的安全设置讨论,了解一些必要的注意事项。

    首先,自然是最外围第一层防线的网络方面的安全。

    我们首先要确定我们所维护的 MySQL 环境是否真的需要提供网络服务?是否可以使我们的 MySQL 仅仅提供本地访问,而禁止网络服务?如果可以,那么我们可以在启动 MySQL 的时候通过使用"--skip-networking"参数选项,让 MySQL 不通过 TCP/IP 监听网络请求,而仅仅通过命名管道或共享内存(在 Windows 中)或 Unix 套接字文件(在 Unix 中)来和客户端连接交互。

    当然,在本章最开始的时候,我们就已经讨论过,由于 MySQL 数据库在大部分应用场景中都是在网络环境下,通过网络连接提供服务。所以我们只有少部分应用能通过禁用网络监听来断绝网络访问以保持安全,剩下的大部分还是需要通过其他方案来解决网络方面存在的潜在安全威胁。

    使用私有局域网络。我们可以通过使用私有局域网络,通过网络设备,统一私有局域网的出口,并通过网络防火墙设备控制出口的安全。

    使用 SSL 加密通道。如果我们的数据对保密要求非常严格,可以启用 MySQL 提供的 SSL 访问接口,将传输数据进行加密。使网络传输的数据即使被截获,也无法轻易使用。

    访问授权限定来访主机信息。在之前的权限系统介绍中我们已经了解到 MySQL 的权限信息是针对用户和来访主机二者结合定位的。所以我们可以在授权的时候,通过指定主机的主机名、域名或者 IP 地址信息来限定来访主机的范围。

    其次,在第二层防线主机上面也有以下一些需要注意的地方。

    OS 安全方面。关闭 MySQL????Server 主机上面任何不需要的服务,这不仅能从安全方面减少潜在隐患,还能减轻主机的部分负担,尽可能提高性能。使用网络扫描工具(如 nmap 等)扫描主机端口,检查除了 MySQL 需要监听的端口 3306(或者自定义更改后的某个端口)之外,还有哪些端口是打开正在监听的,并去掉不必要的端口。严格控制 OS 帐号的管理,以防止帐号信息外泄,尤其是 root 和 mysql 帐号。对 root 和 mysql 等对 mysql 的相关文件有特殊操作权限的 OS 帐号登录后做出比较显眼的提示,并在 Terminal 的提示信息中输出当前用户信息,以防止操作的时候经过多次用户切换后出现人为误操作。

    用非 root 用户运行 MySQL。这在 MySQL 官方文档中也有非常明显的提示,提醒用户不要使用 root 用户来运行 MySQL。因为如果使用 root 用户运行 MySQL,那么 mysqld 的进程就会拥有 root 用户所拥有的权限,任何具有 FILE 权限的 MySQL 用户就可以在 MySQL 中向系统中的任何位置写入文件。当然,由于 MySQL 不接受操作系统层面的认证,所以任何操作系统层级的帐号都不能直接登录 MySQL,这一点和 Oracle 的权限认证有些区别,所以在这一方面我们可以减少一些安全方面的顾虑。

    文件和进程安全。合理设置文件的权限属性,MySQL 相关的数据和日志文件和所在的文件夹属主和所属组都设置为 mysql,且禁用其他所有用户(除了拥有超级权限的用户,如 root)的读写权限。以防止数据或者日志文件被窃取或破坏。因为如果一个用户对 MySQL 的数据文件有读取权限的话,可以很容易将数据复制。binlog 文件也很容易还原整个数据库。而如果有写权限的话就更糟了,因为有了写权限,数据或者日志文件就有被破坏或者删除的风险存在。保护好 socket 文件的安全,尽量不要使用默认的位置(如/tmp/mysql.sock),以防止被有意或无意的删除。

    确保 MySQL????Server 所在的主机上所必要运行的其他应用或者服务足够安全,避免因为其他应用或者服务存在安全漏洞而被入侵者攻破防线。

    在 OS 层面还有很多关于安全方面的其他设置和需要注意的地方,但考虑到篇幅问题,这里就不做进一步分析了,有兴趣的读者可以参考各种不同 OS 在安全方面的专业书籍。

    再次,就是最后第三道防线 MySQL 自身方面的安全设置注意事项。

    到了最后这道防线上,我们有更多需要注意的地方。

    用户设置。我们必须确保任何可以访问数据库的用户都有一个比较复杂的内容作为密码,而不是非常简单或者比较有规律的字符,以防止被使用字典破解程序攻破。在 MySQL 初始安装完成之后,系统中可能存在一个不需要任何密码的 root 用户,有些版本安装完成之后还会存在一个可以通过 localhost 登录的没有用户名和密码的帐号。这些帐号会给系统带来极大的安全隐患,所以我们必须在正式启用之前尽早删除,或者设置一个比较安全的密码。对于密码数据的存放,也不要存放在简单的文本文件之中,而应该使用专业密码管理软件来管理(如 KeePass)。同时,就像之前在网络安全注意事项部分讲到的那样,尽可能为每一个帐户限定一定范围的可访问主机。尤其是拥有超级权限的 MySQL root 帐号,尽量确保只能通过 localhost 访问。

    安全参数。在 MySQL 官方参考手册中也有说明,不论是从安全方面考虑还是从性能以及功能稳定性方面考虑,不需要使用的功能模块尽量都不要启用。例如,如果不需要使用用户自定义函数,就不要在启动的时候使用"--allow-suspicious-udfs"参数选项,以防止被别有居心的潜在威胁者利用此功能而对 MySQL 的安全造成威胁;不需要从本地文件中 Load 数据到数据库中,就使用"--local-infile=0"禁用掉可以从客户端机器上 Load 文件到数据库中;使用新的密码规则和校验规则(不要使用"--old-passwords"启动数据库),这项功能是为了兼容旧版本的密码校验方式的,如无额数必要,不要使用该功能,旧版本的密码加密方式要比新的方式在安全方面弱很多。

    除了以上这三道防线,我们还应该让连接 MySQL 数据库的应用程序足够安全,以防止入侵者通过应用程序中的漏洞而入侵到应用服务器,最终通过应用程序中的数据库相关关配置而获取数据库的登录口令。

    45 小结

    安全无小事,一旦安全出了问题一切都完了。数据的安全是一个企业安全方面最核心最重要的内容,只有保障的数据的安全,企业才有可能真正"安全"。希望这一章????MySQL????安全方面的内容能够对各位读者在构筑安全的企业级????MySQL????数据库系统中带来一点帮助。

热门排行

今日推荐

热门手游