ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

等保三级MySQL访问控制整改指南:账号权限会话网络全覆盖

等保三级MySQL访问控制整改指南:账号权限会话网络全覆盖 做等保三级改造MySQL 访问控制是测评必查项也是最容易丢分的地方。很多系统上线几年数据库账号一直是 root 通打天下权限粗放来源不限制登录失败也没有任何锁定机制测评老师现场一问就露馅。这篇是这个系列的第二篇上一篇我们处理了身份鉴别这一篇集中说访问控制按账号、权限、会话、网络四个层面把 MySQL 的整改动作完整过一遍以 5.7 和 8.0 两个主流版本为主适合正在做整改的运维、DBA还有要和测评机构对接的同事参考。访问控制解决的是“你能连进来干什么、从哪里连进来、能连多久”的问题。等保测评不会只看参数配置还会访谈实际使用方式比如账号是不是还在被多个人共用一个 root运维是不是还在从公网直连数据库。所以这篇文章不止讲参数还讲怎么让整改动作真正落进日常运维流程里。1. 等保三级对MySQL访问控制的要求拆解1.1 访问控制在等保体系中的位置等保三级的安全计算环境里身份鉴别和访问控制是两条并行的主线。身份鉴别解决“你是谁”访问控制解决“你能干什么、你在什么条件下能干”。数据库层面的访问控制做不到位哪怕前面做了多因子认证、高强度密码业务账号被拖库之后照样能拿全库权限前面的功夫等于白做。在 MySQL 层面访问控制通常从四个维度考察账号体系是否存在匿名账号、默认账号、共享账号是否有人离职后账号还在用。权限粒度是 all privileges 还是最小授权管理员与操作员权限是否分离。会话管理登录失败有无锁定空闲会话是否超时退出并发连接是否被限制。网络控制监听地址是否暴露3306 端口是否对公网开放传输是否加密。测评标准原文不会逐条写 MySQL 参数它考察的是管理要求和安全功能是否具备。落实到 MySQL就是上面这四类。做整改前我习惯先把这四条拆成可执行的 SQL 和配置文件项再进服务器动手。1.2 等保三级访问控制的控制点具体到三级等保访问控制相关的控制点大概可以归纳成下面七条。我之前做整改的时候把这七条打印出来贴在工位上每改一项就划掉一项避免漏项。账户唯一性每个用户必须有唯一标识不允许多人共用一个账号。默认账户清理重命名或删除默认账号修改默认口令比如 root 和系统内置账号。无用账户处置及时删除或停用多余、过期的账户。最小权限只授予完成任务所需的最小权限禁止 all privileges 和 super 类权限泛滥。权限分离管理、操作、审计三类权限不能集中在一个账号上。登录失败处理连续失败达到阈值后锁定或延迟防止暴力破解。会话与远程限制设置超时退出、并发会话限制禁止策略外的远程访问。下面按整改顺序展开每一步都有可以直接抄的命令和配置文件。2. 账号体系整改从“裸奔”到权责清晰2.1 清理默认账号与匿名用户登录 MySQL 后第一件事先把家底盘清楚。我最常用下面这条 SQL把当前所有账号拉出来看一遍SELECT user, host, authentication_string, plugin, account_locked FROM mysql.user;重点关注这四类问题匿名账号也就是 user 字段为空的情况例如localhost。空密码账号authentication_string为空且插件是 mysql_native_password 的。root 的远程登录账号例如root%。测试库遗留账号比如test、demo之类或者历史项目留下的业务账号。匿名账号直接删除即可。执行之前先确认没有程序在用这种账号连接一般来说不会有正规应用都会显式指定用户。DROP USER localhost; DROP USER hostname;注意 8.0 里有几个系统内置账号不能动包括mysql.infoschema、mysql.session、mysql.sys它们是 MySQL 内部组件使用的删了会导致实例异常。5.7 里也有mysql.session和mysql.sys。测评老师一般不会因为保留这些账号扣分但要能解释清楚它们是系统账号不能删除。root 账号的处理要谨慎。MySQL 的 root 不能从 mysql.user 里彻底删掉删了系统会有隐患测评也认这个事实。常见做法是保留rootlocalhost把root%删掉或者锁掉ALTER USER root% ACCOUNT LOCK;如果确认root%没人用可以彻底删除DELETE FROM mysql.user WHERE user root AND host localhost; FLUSH PRIVILEGES;这里有个很现实的坑很多老系统的应用连接串里写的就是 root你删了root%业务立刻断。所以清理之前一定要先和开发核对把所有应用的账号摸清楚先把专用账号建好确认连接正常了再处理 root。顺序反了就是事故。2.2 密码策略与密码生命周期管理访问控制的前提是账号安全账号安全的第一步是密码强度。等保三级要求密码复杂度MySQL 5.7 和 8.0 都支持校验插件或组件。5.7 安装 validate_password 插件INSTALL PLUGIN validate_password SONAME validate_password.so;8.0 从 8.0.19 起默认以组件方式提供校验能力安装命令INSTALL COMPONENT file://component_validate_password;建议直接设成 STRONG 策略并配合长度和字符组合要求。8.0 里变量名带点5.7 不带点这条容易被忽略-- 8.0 SET GLOBAL validate_password.policy STRONG; SET GLOBAL validate_password.length 12; SET GLOBAL validate_password.mixed_case_count 1; SET GLOBAL validate_password.number_count 1; SET GLOBAL validate_password.special_char_count 1; -- 5.7 SET GLOBAL validate_password_policy STRONG; SET GLOBAL validate_password_length 12; SET GLOBAL validate_password_mixed_case_count 1; SET GLOBAL validate_password_number_count 1; SET GLOBAL validate_password_special_char_count 1;这些参数也要写进 my.cnf否则重启后恢复默认。要长期生效的配置不要只 SET GLOBAL实例重启就丢了。密码过期策略同样重要。很多数据库密码设完就“永生”违背等保对定期更换的要求。全局设置[mysqld] default_password_lifetime 90也可以对单个账号设置ALTER USER app_rw% PASSWORD EXPIRE INTERVAL 90 DAY;注意一点密码过期策略生效后应用账号如果到了过期时间不换密码连接会被拒绝这对很多应用是致命的。整改时建议先把过期时间定得宽一点比如 90 天同时通知开发排期改密不要一上来就设 30 天又没人跟进最后变成生产事故。2.3 三权分立账号设计等保三级对权限分离的要求落到数据库上就是三类账号管理员、操作员、审计员。我一般在整改里设计成下面这个矩阵账号职责权限范围连接来源mysql_admin账号管理、参数管理、权限分配CREATE USER、ALTER USER、DROP USER、PROCESS、RELOAD、SHOW DATABASES运维跳板机网段app_rw业务读写业务库的 SELECT、INSERT、UPDATE、DELETE、EXECUTE应用服务器网段app_ro报表查询、只读分析业务库的 SELECT报表/分析网段audit_r审计日志查看仅审计相关权限对业务库无读写审计员管理网段创建命令参考CREATE USER mysql_admin10.0.0.% IDENTIFIED BY 强密码; GRANT CREATE USER, ALTER USER, DROP USER, PROCESS, RELOAD, SHOW DATABASES ON *.* TO mysql_admin10.0.0.%; CREATE USER app_rw10.0.1.% IDENTIFIED BY 强密码; GRANT SELECT, INSERT, UPDATE, DELETE, EXECUTE ON appdb.* TO app_rw10.0.1.%; CREATE USER app_ro10.0.2.% IDENTIFIED BY 强密码; GRANT SELECT ON appdb.* TO app_ro10.0.2.%; CREATE USER audit_r10.0.3.% IDENTIFIED BY 强密码; GRANT PROCESS ON *.* TO audit_r10.0.3.%;这里要先声明一个数据库产品的现实矛盾MySQL 里要给别的账号授权授权者自己必须拥有对应权限和 GRANT OPTION所以严格意义上的三权分立很难在 MySQL 单实例内纯粹实现。真实项目里最常见的组合是root 保留在 localhost只能通过堡垒机登录所有 root 操作被堡垒机录像日常运维通过审批流发起应用账号只有业务权限审计账号只能看日志。也就是说技术手段加管理流程一起满足要求而不是指望着数据库自己变出三个互不干扰的超级账号。和测评老师沟通时能把这一套流程讲清楚基本不会被判不符合。3. 权限分配与最小授权落地3.1 基于角色的授权方式MySQL 8.0 引入了角色这是做等保改造特别顺手的功能。角色可以理解成一组权限的集合先定义角色再把角色授予账号权限变更只改角色不用逐个改账号尤其适合几十个应用账号的场景。比如有两个业务账号都只需要读写 appdb建一个角色统一管理CREATE ROLE appdb_rw_role; GRANT SELECT, INSERT, UPDATE, DELETE ON appdb.* TO appdb_rw_role; CREATE USER app_online10.0.1.% IDENTIFIED BY 强密码; CREATE USER app_report_writer10.0.1.% IDENTIFIED BY 强密码; GRANT appdb_rw_role TO app_online10.0.1.%; GRANT appdb_rw_role TO app_report_writer10.0.1.%; SET DEFAULT ROLE ALL TO app_online10.0.1.%; SET DEFAULT ROLE ALL TO app_report_writer10.0.1.%;注意只执行 GRANT role 不执行 SET DEFAULT ROLE账号登录后角色不会自动激活权限不会生效。这是 8.0 角色使用里最常见的坑。5.7 没有角色可以写一套统一的授权脚本通过脚本给同一类账号执行相同的 GRANT权限复核也靠脚本输出结果本质上也是角色化思路只是少了一层抽象。3.2 最小权限清单最小权限的落地重点是把常用账号的权限控制在明确范围里。下面是我在整改项目里常用的基准账号类型可授权限明确禁止应用读写账号SELECT、INSERT、UPDATE、DELETE、EXECUTEDDL 权限、GRANT OPTION、SUPER、FILE应用只读账号SELECT一切写权限、SUPER、FILE备份账号SELECT、RELOAD、LOCK TABLES、SHOW VIEW、PROCESS、REPLICATION CLIENT对业务数据的写权限监控账号PROCESS、REPLICATION CLIENT、SHOW DATABASES对业务库表的任何访问管理员账号账号管理、参数管理相关权限业务库表的读写通过流程配合FILE 权限要特别警惕它允许 MySQL 把本地文件读出来也能写文件到 MySQL 所在服务器历史上很多提权攻击都从 FILE 入手。等保整改时我的原则是默认不给 FILE确实需要导入导出再临时授予用完立刻回收。另一个值得做的小改动是打开 read_only前提是应用账号不是 SUPER 用户。read_onlyON 后非 SUPER 用户无法执行写操作对误操作是很好的兜底。SET GLOBAL read_only ON;先确保没有应用账号是 SUPER再开 read_only否则应用会大面积报错。权限复核不能省。我每次整改都会把关键账号的 grants 拉出来逐条过SHOW GRANTS FOR app_rw10.0.1.%;也会定期跑一遍所有非系统账号的权限清单脚本对比上个月的记录看有没有多出不该有的权限。测评时候拿出这些记录比空口解释有效得多。3.3 禁用 root 远程登录和高风险启动项等保测评检查里root 能不能远程登录是必查项。除了账号表的配置还要查 mysqld 启动参数。禁止 root 远程逻辑很简单让 mysql.user 表里 root 对应的 host 只有 localhostSELECT user, host FROM mysql.user WHERE user root;如果出现root%、root10.0.0.1这种一律锁掉或删掉。更危险的是 mysqld 开启了 skip-grant-tables这个参数一旦开启任何人都能绕过认证直接进库等保测评里属于一票否决的严重问题。检查方法SHOW VARIABLES LIKE skip_grant_tables;必须是 OFF。如果查到是 ON立刻去掉配置文件里的skip-grant-tables并重启数据库。8.0 版本默认对 skip-grant-tables 有更强限制但任何版本都不允许在生产环境开这个参数。还有一个常被忽略的细节local_infile 开关。如果开启客户端可以执行LOAD DATA LOCAL INFILE配合 FILE 相关漏洞有数据泄露风险。整改建议关闭[mysqld] local_infile 0关闭后应用如果依赖 load data 功能会有报错需要先确认。4. 登录会话与失败处理机制4.1 登录失败锁定connection_control 插件暴力破解是数据库安全的老大难等保三级要求登录失败必须有处理机制。MySQL 5.7 和 8.0 都支持 connection_control 插件它会在连续失败次数超过阈值后对来自相同来源的连接做延迟处理等效于一种动态惩罚。安装插件INSTALL PLUGIN connection_control SONAME connection_control.so;配置参数[mysqld] plugin-load-addconnection_control.so connection_control_failed_connections_threshold5 connection_control_min_connection_delay1000 connection_control_max_connection_delay600000含义分别是连续失败 5 次后开始惩罚第一次延迟 1 秒后续逐渐增加最长延迟 10 分钟。配置后可以用错误密码连续登录验证。比如故意输错 6 次密码观察连接耗时是否明显增加。我之前遇到过阈值设成 3 的场景一个开发同事连续输错几次密码之后整个办公室 IP 连接数据库都变慢严重影响排障。阈值设 5 比较合适既给了正常输错的缓冲也能拦住大部分无脑暴力尝试。8.0.19 及以上版本还有原生账号锁定机制比插件更直观ALTER USER app_rw10.0.1.% FAILED_LOGIN_ATTEMPTS 5 PASSWORD_LOCK_TIME 10;意思是连续失败 5 次后锁定该账号 10 分钟。查看锁没锁SELECT user, host, account_locked FROM mysql.user WHERE user app_rw;账号被锁后可以用管理员执行解锁ALTER USER app_rw10.0.1.% ACCOUNT UNLOCK;两种方式可以同时用插件管来源地址账号锁定管具体账号纵深防御。4.2 会话超时与并发连接限制等保测评会检查数据库是否支持空闲会话自动退出MySQL 对应的参数是 wait_timeout 和 interactive_timeout。默认值是 28800 秒也就是 8 小时太长了不符合访问控制要求。整改我一般设 600 秒[mysqld] wait_timeout 600 interactive_timeout 600wait_timeout 和非交互连接有关程序通过连接池建立的连接算这类interactive_timeout 针对命令行这种交互会话。两个都设避免钻空子。并发限制看两个参数[mysqld] max_connections 500 max_user_connections 100max_connections 是实例级别的最大连接数防止连接耗尽拖垮数据库max_user_connections 限制单个账号的最大并发连接数防止一个账号被滥用。注意 max_user_connections 不是越多越好要结合应用服务器的连接池大小计算假设 10 台应用服务器每台连接池配 20那连接上限至少给 200 或更高否则白天流量一起来连接池疯狂报 resource busy。超时参数还有个实践细节修改后用 SHOW VARIABLES 看到的是会话级值旧连接可能还是原来的值新连接才用新配置。验证时要新建连接查看不要拿已经存在的连接判断。4.3 账号锁定的版本差异与升级建议MySQL 5.7 做访问控制改造登录失败只能依赖 connection_control而且密码校验、角色、密码历史这些能力都比 8.0 弱。8.0 在账号管理上多了一整块能力除了前面的 FAILED_LOGIN_ATTEMPTS还有密码历史记录和角色。密码历史可以防止改回旧密码SET GLOBAL password_history 5; SET GLOBAL password_reuse_interval 365;如果条件允许正在做等保改造的 5.7 实例我强烈建议至少规划升级到 8.0。访问控制只是其中一个理由审计、加密、密码策略这些等保控制点在 8.0 里都有原生支持能少踩很多第三方插件的坑。升级要评估应用兼容性尤其是老客户端对 caching_sha2_password 的支持不能为了合规盲目升级但可以在整改清单里把升级作为中期计划。5. 网络层访问控制与传输安全5.1 绑定监听地址与防火墙白名单访问控制不止数据库内部网络层才是第一道门。MySQL 默认监听所有接口意味着只要 3306 端口通任何能路由到这台机器的人都可能连上来。整改第一件事就是收紧监听地址。需求分两种应用和数据库同机部署绑 127.0.0.1直接不对外开监听。应用和数据库分离部署绑数据库服务器的内网 IP不要绑 0.0.0.0。配置文件里[mysqld] bind-address 192.168.10.20改完后netstat -lntp检查应该只能看到 192.168.10.20:3306 和 127.0.0.1:3306不再有 0.0.0.0:3306。网络层再叠一层防火墙白名单。Linux 上我用 firewalld 举例如下firewall-cmd --permanent --remove-servicemysql firewall-cmd --permanent --add-rich-rulerule familyipv4 source address10.0.1.0/24 port protocoltcp port3306 accept firewall-cmd --reload云环境和物理机同样处理在安全组或交换机 ACL 里只放行应用网段和运维跳板机 IP。测评访谈时能拿出网络白名单列表访问控制的远程限制项基本稳了。MySQL 账号的 host 字段也能限制来源比如只允许10.0.1.%网段的机器连接。host 字段不支持 CIDR 写法但支持通配符。注意 host 匹配的是客户端的源地址不是 DNS 名应用服务器 IP 会变的环境要谨慎别把合法访问挡在门外。5.2 SSL 加密连接配置明文传输在等保三级里是不合格的尤其是数据库和应用服务器分离部署时数据包在网络上裸奔。MySQL 支持 SSL/TLS 加密连接整改必须加上。先用 openssl 生成一套自签名证书我习惯单独建目录mkdir -p /etc/mysql/ssl cd /etc/mysql/ssl openssl genrsa 2048 ca-key.pem openssl req -new -x509 -nodes -days 365 -key ca-key.pem -out ca.pem openssl req -newkey rsa:2048 -days 365 -nodes -keyout server-key.pem -out server-req.pem openssl x509 -req -in server-req.pem -days 365 -CA ca.pem -CAkey ca-key.pem -set_serial 01 -out server-cert.pem生成后配置[mysqld] ssl-ca/etc/mysql/ssl/ca.pem ssl-cert/etc/mysql/ssl/server-cert.pem ssl-key/etc/mysql/ssl/server-key.pem重启后验证SHOW VARIABLES LIKE have_ssl; SHOW STATUS LIKE Ssl_cipher;have_ssl 是 YESSsl_cipher 不是空才算生效。只装证书还不够客户端默认不会强制走 SSL。对所有需要加密的账号强制启用ALTER USER app_rw10.0.1.% REQUIRE SSL;客户端连接方式对应调整。命令行mysql -h db.internal.example.com -u app_rw -p --ssl-modeREQUIREDJDBC 连接串jdbc:mysql://192.168.10.20:3306/appdb?useSSLtruerequireSSLtrueverifyServerCertificatefalse开启 SSL 后最常见的问题是应用报 SSL connection error原因一般是客户端证书链没配全或者 MySQL 5.7 和 8.0 的 SSL 相关变量不兼容。排查时先确认客户端是否支持再看报错是握手失败还是证书验证失败。需要说明的是自签名证书在生产环境最好换成内部 CA 签发的证书周期也建议控制在一年以内并纳入续期计划。SSL 加密有一定性能开销高并发场景实测通常有 10%~30% 的吞吐下降但为了合规和数据安全这个成本必须付。5.3 运维通道跳板机优先运维人员连数据库最忌讳直接暴露 3306 到办公网。我经历过的合规项目数据库的 3306 端口基本都是只对跳板机网段开放运维先登录跳板机再从跳板机连数据库全程有录屏审计。MySQL 的 host 限制也写明只允许跳板机 IP。如果跳板机不适用还可以用 SSH 隧道做通道在本地把远程 3306 端口转发到本地端口再通过本机回环地址连接数据库。重点是数据库监听地址只保留回环或内网地址同时收紧 SSH 访问来源。这类方案在测评中能通过的关键是讲清楚访问路径用户从哪进、经过哪道验证、操作有没有留痕。访问控制本身是环环相扣的网络白名单、账号来源限制、运维审计三者配合才是一个完整的闭环。6. 常见问题与整改现场实录6.1 改密码策略后旧账号密码失效一次整改中我先把 validate_password 策略设成 STRONG然后去改一个旧账号的密码密码长度 8 位、只有字母结果 ALTER USER 一直报错。密码策略只对新建和修改密码生效但设成 STRONG 后修改任何账号的密码都必须满足新规则旧账号原本的简单密码不会被自动检测。解决方式是先用脚本扫描有哪些账号的密码强度可能不达标统一规划密码重置。现场连续输错几个简单密码还被锁定的情况也要考虑改密前先确认账号没被锁。另一条经验密码策略设得再严如果应用代码里是明文传输也会被网络抓包看到。所以 SSL 和密码策略要一起上不能只做其中一项。6.2 connection_control 误伤整段办公室流量有次在一个客户现场开发反馈一段时间的数据库连接全部超时。排查后发现 connection_control_failed_connections_threshold 被设成了 3某个同事用客户端反复输错密码触发延迟惩罚而且随着失败次数增加延迟时间被拉到很长整个出口 IP 都受影响。connection_control 按来源地址做惩罚不具备精确到人的能力所以阈值不能太低同时要在网络层封禁明显在扫描的 IP而不是只靠数据库插件。这也是为什么我把阈值推荐在 5 而不是 3 的原因。如果用的是 8.0.19 的账号锁定机制情况会好一些因为它只锁定目标账号不影响其他账号从同一来源连接。6.3 测评检查的关键命令清单整改完成后我一般用下面这些命令做一次自检模拟测评老师现场检查的顺序-- 账号清单检查匿名账号、root远程、无用账号 SELECT user, host, account_locked FROM mysql.user WHERE user NOT IN (mysql.infoschema, mysql.session, mysql.sys); -- 密码策略 SHOW VARIABLES LIKE validate_password%; -- 登录失败处理 SHOW VARIABLES LIKE connection_control%; -- 会话超时 SHOW VARIABLES LIKE wait_timeout; SHOW VARIABLES LIKE interactive_timeout; -- 并发限制 SHOW VARIABLES LIKE max_connections; SHOW VARIABLES LIKE max_user_connections; -- SSL状态 SHOW VARIABLES LIKE have_ssl%; SHOW STATUS LIKE Ssl_cipher;配置文件的持久性也要查光 SET GLOBAL 不写 my.cnf重启就没了测评现场被要求展示配置文件时就会穿帮。6.4 整改前后对比参考表每次项目收尾我都会整理一张整改前后对照表给客户也给自己留底。这次访问控制部分的典型状态如下检查维度整改前常见状态整改后目标状态账号root% 远程可用存在匿名账号root 仅 localhost匿名账号清零业务使用专用账号密码策略无策略或弱策略密码永不过期长度 12 位且含大小写、数字、特殊字符90 天过期权限应用账号拥有全部权限角色化最小授权无 GRANT OPTION、无 FILE、无 SUPER登录失败无任何失败限制connection_control 或原生账号锁定5 次失败触发延迟/锁定会话wait_timeout 默认 8 小时10 分钟超时单账号并发受限网络监听0.0.0.0:3306仅内网 IP防火墙按网段白名单放行传输明文SSL 加密强制应用账号 REQUIRE SSL运维接入公网直连跳板机接入操作留痕这张表也是给测评老师看整改成效的直观材料比口头解释强很多。做这类整改我的体会有两点。第一先盘清楚家底再动手账号、权限、网络路径都搞清楚之后改配置其实是机械操作真正的风险在改的时候把业务断了。第二等保测评看的不只是参数更看运营方式有没有真正改变。MySQL 访问控制做到位技术是一半流程是一半。我会在整改结束前让开发和运维同事各自拿到一份自己账号的权限清单写明能做什么、不能做什么顺带约法三章权限申请走流程、密码定期换、运维连接走跳板机。这套机制跑起来等保测评的访问控制项才算真正落地。
返回列表