
简介《数据库安全加固手册》是一份面向数据库管理员与安全工程师的实操型文档系统覆盖 MySQL、SQL Server 2008、Oracle、PostgreSQL、Redis 五种主流数据库的安全加固要点。内容从用户与密码配置、权限管理、通信加密到日志审计、文件权限设置均有涉及并针对每种数据库给出具体措施和操作步骤如禁止 MySQL root 远程登录、限制 SQL Server guest 账户访问、配置 Oracle 密码策略等。压缩包共 1 个文件为 docx 格式体积 4.78MB便于直接阅读和检索。资源还包含问题复现与异常信息处理案例帮助读者在实际环境中定位和解决安全漏洞。目前已有 232 人学习下载适合具备一定数据库管理基础、从事运维与安全工作的技术人员作为自查与加固参考。1. 数据库安全加固为什么先别急着装防火墙如果你手里同时管着 MySQL、Oracle、SQL Server、PostgreSQL 和 Redis大概有过这种经历某天漏洞扫描报告出来五类数据库的弱口令、未授权访问、默认端口全开、超级管理员裸奔安全部门一封邮件甩过来要求“一周内完成加固”。这时候最容易被带偏的方向是一上来就部署数据库防火墙、装各种审计插件结果业务连夜报错回滚都来不及。数据库加固的本质不是“加多少层防护”而是先把每个数据库的暴露面收敛到最小谁在监听、谁能连、连上能干什么、干了什么是否留痕。这四件事做扎实比任何高价设备都顶用。本文围绕 MySQL、Oracle、SQL Server、PostgreSQL、Redis 五种数据库从通用基线到各自落地配置再到我踩过的坑和验证脚本给你一条能照着做的路径。适合既要保业务稳定、又必须扛住合规检查的运维、DBA 和后端开发。2. 通用加固基线先行端口、账号、权限、日志的四件套2.1 端口与监听减少暴露面是第一道防线做数据库加固第一个动作永远是确认它到底在监听谁。默认安装下MySQL 的 3306、PostgreSQL 的 5432、Redis 的 6379 通常会绑定到 0.0.0.0这在云服务器上等于把数据库裸奔在公网。常见做法是统一改成监听 127.0.0.1 或内网网卡地址业务侧通过应用服务器中转访问。# 查看各数据库监听情况 ss -tlnp | grep -E 3306|5432|1521|1433|6379 # MySQL 示例只监听内网 # my.cnf 中设置 [mysqld] bind-address 10.0.0.10 skip-name-resolve参数说明bind-address指定 MySQL 监听地址改成内网 IP 后外部无法直连skip-name-resolve跳过域名反查既加速连接也避免因 DNS 异常出现授权表匹配不到的“玄学”问题。判断是否生效用ss -tlnp看到监听地址变为内网 IP 即完成。PostgreSQL 的监听在postgresql.conf里改listen_addresses可写成内网 IP 或逗号分隔的多个地址。Oracle 的监听配置在listener.ora中一般把HOST从0.0.0.0改为实际网卡 IP改完要lsnrctl reload。SQL Server 在 SQL Server 配置管理器里将 TCP/IP 协议的“侦听所有”改为指定 IP。Redis 相对特殊它的bind指令支持多 IP但即便绑定内网也要配合密码和 protected-mode三者缺一不可后面章节单独展开。2.2 账号与口令策略密码策略、过期时间、登录失败锁定端口收敛解决的是“谁能碰”的问题口令策略则决定“碰了能不能进”。很多加固项目翻车不是没设强密码而是设了强密码但策略不生效或者业务账号全部共用同一个密码等保测评一查一个准。# MySQL 8.0 启用密码校验组件 INSTALL COMPONENT file://component_validate_password; SET GLOBAL validate_password.policy STRONG; SET GLOBAL validate_password.length 12; # 配置密码过期与失败锁定MySQL 8.0.13 ALTER USER app_user% PASSWORD EXPIRE INTERVAL 90 DAY; CREATE USER etl_user% IDENTIFIED BY Strong#Pass123 FAILED_LOGIN_ATTEMPTS 3 PASSWORD_LOCK_TIME 1;逻辑说明validate_password.policy从 LOW 到 STRONG 控制密码复杂度STRONG 会额外检查密码中是否包含字典词FAILED_LOGIN_ATTEMPTS和PASSWORD_LOCK_TIME是 MySQL 8.0 自带失败锁定能力的参数不需要额外装插件。注意这个功能在 8.0.13 之前只能靠第三方插件实现老版本升级后配置会失效。PostgreSQL 的密码复杂度策略不像 MySQL 一条命令搞定一般是两层配合password_encryption scram-sha-256保证传输和存储加密密码复杂度依赖passwordcheck扩展或外部认证。我在生产上更推荐用 PAM 做统一认证但小规模场景下用passwordcheck就够了。Oracle 用 profile 管理FAILED_LOGIN_ATTEMPTS 5、PASSWORD_LIFE_TIME 90、PASSWORD_VERIFY_FUNCTION启用自定义密码复杂度函数。SQL Server 则依赖 Windows 策略或 SQL Server 自身的CHECK_POLICY、CHECK_EXPIRATION一个常见的坑是只加了CHECK_POLICY但忘了开CHECK_EXPIRATION导致密码永不过期。2.3 最小权限原则分权管理与角色隔离加固里最容易被业务方抵触的就是收权限——因为收错了真的会炸。我的原则是“收回公开账号、拆分超级管理员、按职责给最小权限”DBA 用管理账号应用用只读或增删改账号报表账号只读做数据导入导出用独立账号。-- MySQL 最小权限示例 -- 应用账号只允许 SELECT/INSERT/UPDATE/DELETE CREATE USER app_rw10.0.0.% IDENTIFIED BY App#2024rw; GRANT SELECT, INSERT, UPDATE, DELETE ON biz_db.* TO app_rw10.0.0.%; -- 报表账号只读 CREATE USER report_ro10.0.0.% IDENTIFIED BY Rep#2024ro; GRANT SELECT ON biz_db.* TO report_ro10.0.0.%; -- 禁止用 root 跑业务 RENAME USER rootlocalhost TO dba_adminlocalhost;权限配置的逻辑核心是“授权主机也限制”。10.0.0.%限定了来源 IP即使密码泄露外部也无法利用。另一个要点是回收默认权限MySQL 安装后root的 host 往往是localhost和127.0.0.1都有PHP 项目里常见rootlocalhost密码空着务必先设密码再改名。Oracle 和 SQL Server 的权限模型更复杂。Oracle 建议把SYSTEM和SYS分开管理业务库单独建表空间和用户只授予CONNECT和RESOURCE角色DBA角色绝不授予业务账号。SQL Server 则建议将sa账号改名或禁用应用账号用db_datareader加db_datawriter固定角色绝不给sysadmin。PostgreSQL 里对应的是pg_hba.conf控制连接认证 行级安全策略RLS做细粒度过滤后面实操章节展开。2.4 日志与审计留痕才能追溯很多加固方案把大量精力放在防入侵忽略了“出事之后能不能查”。审计日志的价值在于事后溯源和合规留痕——现在不用等安全事件发生时才想起来没开就晚了。五类数据库的审计能力差异很大落地时按“先有、再全、后优化”走。-- MySQL 开启通用日志和慢查询便于定位异常 -- my.cnf general_log ON general_log_file /var/log/mysql/mysql-general.log slow_query_log ON long_query_time 2 log_output TABLE -- 查看审计插件是否加载MySQL Enterprise Audit 或社区版 log_bin SHOW VARIABLES LIKE log_bin; SHOW VARIABLES LIKE audit_log%;参数说明general_log记录所有 SQL包括失败的连接尝试排查安全事件非常有价值但代价是性能和磁盘。生产环境我一般开在独立的日志盘且按天做日志切割。log_output TABLE会把日志写到 mysql.general_log 表里查询方便但表会膨胀记得定期清理。PostgreSQL 的日志在postgresql.conf里以log_*开头常用组合是log_connections on、log_disconnections on、log_statement ddl或mod。Oracle 从 11g 开始有 Unified Audit推荐直接开启ENABLE_UNIFIED_AUDIT按用户或按对象做审计策略。SQL Server 默认有错误日志但 SQL 审计需要新建“服务器审计”对象再绑定“服务器审计规范”SQL Server 2017 以上支持ADD AUDIT语句。Redis 本身没有 SQL 审计概念但日志级别要调到notice以上且配置CONFIG REWRITE后的持久化日志会暴露配置变更痕迹也属于审计的一部分。3. 关系型数据库加固实操MySQL 与 PostgreSQL 的典型配置3.1 MySQL从 skip-networking 到 validate_password 的完整链路MySQL 是五种数据库里加固文档最全、但也是最容易漏配的。一个完整的 MySQL 加固链路应该是连接层端口/绑定→ 认证层密码策略/账号锁定→ 权限层最小授权→ 传输层SSL→ 日志层审计。# my.cnf 加固核心参数MySQL 8.0 [mysqld] port 3307 bind-address 10.0.0.10 skip-name-resolve ON require_secure_transport ON max_connections 500 max_connect_errors 100 wait_timeout 600 interactive_timeout 600参数说明require_secure_transport ON强制所有连接走 SSL/TLS能防局域网内的嗅探代价是老旧业务驱动可能不支持升级驱动或临时关闭的“后悔药”要在变更窗口留好。max_connect_errors限制连接错误次数超过后该 IP 被临时封锁防止密码爆破。wait_timeout调短能减少死连接占用但太短会让连接池频繁重建我一般控制在 600 秒上下。MySQL 8.0 的caching_sha2_password认证插件安全性优于老版的mysql_native_password但部分老语言驱动比如某些 PHP 5.x 版本不兼容。遇到这种情况我建议优先升级驱动确实升不了才退回到mysql_native_password而且要让 DBA 明确知道这是 2024 年还在用的“历史遗留风险”。3.2 PostgreSQLpg_hba.conf、SSL 强制与行级安全PostgreSQL 的加固核心不在 my.cnf 这类参数文件而在pg_hba.conf—— 它是客户端认证的黑白名单总入口。很多新手在这里翻车改了 pg_hba.conf 之后忘了 reload导致配置半天不生效或者把scram-sha-256写成了md5密码策略形同虚设。# pg_hba.conf 关键配置示例 # 类型 数据库 用户 来源地址 认证方法 host all all 127.0.0.1/32 scram-sha-256 host all all 10.0.0.0/8 scram-sha-256 hostssl all all 0.0.0.0/0 scram-sha-256 host replication admin 10.0.0.0/8 scram-sha-256配置逻辑认证方法统一用scram-sha-256MySQL 的密码策略管复杂度PostgreSQL 的 scarm 管加密强度。hostssl强制远程连接必须走 SSL如果业务方没法开 SSL先单独给那个网段写一条host规则而不是把hostssl删掉——这是我的血泪经验。PostgreSQL 还提供了 MySQL 没有的行级安全RLS。比如订单表想让运营账号只能查自己负责区域的数据在表上启用 RLS 并用 policy 限定条件。这个能力在等保、数据分类分级场景下特别好用但注意超级用户不受 RLS 限制必须配合前面讲的最小权限原则才有效。3.3 Oracle 与 SQL Server企业级数据库的加固要点Oracle 和 SQL Server 在企业内网环境里遇到的安全问题和 MySQL/PostgreSQL 很不一样它们默认不开外网监听但内置账号多、默认端口固定、patch 管理落后。Oracle 加固的优先级第一是锁掉没用的默认账号第二是开统一审计第三才是密码策略。-- Oracle 解锁策略与默认账号处理 -- 锁定用不到的默认账号 ALTER USER SCOTT ACCOUNT LOCK; ALTER USER HR ACCOUNT LOCK; -- 修改 SYS/SYSTEM 默认密码并设置 profile ALTER USER SYS IDENTIFIED BY New#Sys#Pass ACCOUNT UNLOCK; ALTER PROFILE DEFAULT LIMIT FAILED_LOGIN_ATTEMPTS 5 PASSWORD_LIFE_TIME 90 PASSWORD_REUSE_TIME 180; -- 开启统一审计需以 AUDIT_ADMIN 角色执行 BEGIN EXECUTE IMMEDIATE AUDIT POLICY ORA_LOGON_FAILURES; EXECUTE IMMEDIATE AUDIT POLICY ORA_ACCOUNT_MGMT; END;逻辑说明Oracle 12c 之后统一审计策略默认就有ORA_LOGON_FAILURES等预置策略但默认未启用开启后失败登录会写入UNIFIED_AUDIT_TRAIL视图。另一个重点REMOTE_LISTENER参数如果没设可能被利用做 TNS 投毒检查本地listener.ora中是否只监听了内网地址。SQL Server 的加固相对简单但容易遗漏三件事sa账号没禁用、xp_cmdshell没关、Server 级触发器缺失。xp_cmdshell是经典提权路径加固要直接关掉。SQL Server 2019 还推荐启用Ledger功能做防篡改账本但这是选配对合规要求严格、又愿意接受写入性能折损的项目才上。4. Redis 加固内存数据库的边界与数据安全4.1 Redis 未授权访问为什么到现在还在泛滥Redis 是五种数据库里最容易出安全事故的原因很反直觉它默认配置“太能用”了。安装完 Redisredis-server直接起不需要密码、不需要认证6379端口监听在0.0.0.0任何能访问到这个端口的人都可以读写数据。更危险的是Redis 在某些版本里可以通过CONFIG SET dir和CONFIG SET dbfilename把写好的命令落盘到 Web 目录这就是早期大量利用 Redis 写 crontab 反向 Shell 的原理。到现在还有大量内网 Redis 裸奔不是没人提醒而是很多人觉得“内网没事”“只是缓存而已”。# 检查 Redis 是否未授权危险操作仅供自查 redis-cli -h 10.0.0.x -p 6379 INFO server # 如果返回版本信息且无需密码说明未授权访问风险存在 # 应立刻通过 config set 临时加密码再改配置文件持久化 127.0.0.1:6379 CONFIG SET requirepass Str0ng#Redis#Pass OK 127.0.0.1:6379 CONFIG REWRITE OK第一段命令用于自查时要注意INFO server在未授权下返回内容就意味着这台 Redis 谁都能连。第二段的CONFIG SET是应急止血但如果CONFIG REWRITE不执行重启后密码就丢了——这是最常见的加固“白干”场景。4.2 bind、protected-mode 与 rename-command 三件套Redis 加固的标准三件套是bind 限定来源、protected-mode 兜底、rename-command 封禁危险命令。# redis.conf 安全加固关键配置 bind 127.0.0.1 10.0.0.10 protected-mode yes port 6379 requirepass Str0ng#Redis#Pass rename-command KEYS rename-command FLUSHALL DANGER_FLUSHALL_2024 rename-command FLUSHDB DANGER_FLUSHDB_2024 rename-command CONFIG DANGER_CONFIG rename-command SHUTDOWN DANGER_SHUTDOWN rename-command EVAL DANGER_EVAL参数说明protected-mode yes的作用是在“没有密码 绑定公网地址”时拒绝外部连接——它是兜底但不能替代requirepass。我见过不少配置只开了 protected-mode、没设密码结果内网其他机器照样能无密码连因为 protected-mode 只对非绑定地址才生效准确理解是当 Redis 配置了 bind 地址后protected-mode 的保护范围就变弱了所以密码必须配。rename-command是最有争议的一项关掉KEYS会影响不少监控脚本因为KEYS在大量 key 时会阻塞 Redis生产上一旦误执行直接卡死几分钟。把KEYS改名不是为了防外部攻击更多是防内网误操作。4.3 RDB/AOF 文件安全与持久化加密Redis 加固容易聚焦在访问控制上忽略落盘文件本身。Redis 默认把 RDB 快照写到/var/lib/redis/dump.rdb如果服务器被攻破或磁盘被脱走数据文件就是明文。传统做法是靠文件系统权限兜底Redis 进程以专用用户运行dump.rdb设为 600 权限目录不授权给其他用户。这个思路没错但要意识到它防不住 root 权限的读取。# RDB/AOF 文件权限加固 chown redis:redis /var/lib/redis/dump.rdb /var/lib/redis/appendonly.aof chmod 600 /var/lib/redis/dump.rdb /var/lib/redis/appendonly.aof # 确认 Redis 没有以 root 运行 ps -ef | grep redis-server # 如果输出第一列是 root立即改造为专用用户运行 useradd -r -s /sbin/nologin redis_prod chown -R redis_prod:redis_prod /var/lib/redis /var/log/redis有更严格的环境会要求对 RDB 做加密备份但社区版 Redis 本身不支持。在生产内网里我一般把重点放在进程降权、文件权限 600、备份传输走内网专用通道这三个做到位合规检查基本能过。真正的加密存储要么上企业版要么靠底层文件系统加密比如 LUKS但那已经是 OS 层面的活了不在 Redis 配置范围内。5. 数据库加固中的 5 个常见坑现象、原因与解法5.1 改完配置数据库起不来SELinux 和权限背了多少锅现象MySQL 改完my.cnf重启服务直接起不来error.log里报Permission denied或者直接没日志。原因最常见是两个。一是my.cnf里的datadir或socket路径权限不对MySQL 进程用户通常mysql没有读权限二是 SELinux 开启状态下自定义了数据目录或端口但没有给 SELinux 策略放行。解决先journalctl -u mysql看 systemd 日志确认是不是权限问题如果是自定义端口用semanage port -a -t mysqld_port_t -p tcp 3307放行。如果不想折腾 SELinux至少在加固文档里明确写出来“生产环境建议先评估 SELinux 模式”不要在加固中途关 SELinux那样改完没有任何保护反而比加固前更危险。5.2 MySQL 的 validate_password 把业务账号全拦了现象开完validate_password后应用连不上数据库报Access denied检查密码明明没改。原因validate_password.policy STRONG会要求密码至少包含大小写字母、数字、特殊字符并且长度不低于validate_password.length。你的业务账号密码如果是abc123或Admin123这类弱密码在开启 STRONG 策略后虽然连接时报的是 access denied因为密码确实不对但真实原因是ALTER USER改密时被策略拒绝旧密码已经被改掉或密码已过期。解决先临时把 policy 降到 LOW批量重置业务账号密码到一个合规值再恢复 STRONG。不要试图通过validate_password.enable OFF绕过等保测评一眼就能看出来。批量改密脚本务必备份原密码哈希万一业务方说“某账号不能动”至少能回滚。5.3 Redis 主从复制下 requirepass 不生效现象Redis 主从架构配好了requirepass从库同步正常但主库一重启从库就报MASTER - REPLICA sync started后马上断连。原因Redis 主从同步需要从库配置masterauth而不是只配requirepass。requirepass管的是“客户端连接 Redis 要密码”masterauth管的是“从库连主库要密码”。只配前者从库在主库重启后重连时拿不到认证同步就一直失败。这个坑在文档里写得清楚但实操中十有六七会漏。解决从库配置里加上masterauth并且值必须和主库requirepass一致。改完后先redis-cli -a 密码 CONFIG REWRITE再重启从库进程确认日志里不再出现MASTER aborted。5.4 审计日志把磁盘撑爆现象开启了 general_log 或 Oracle Unified Audit 后运行两周磁盘报警 90%业务开始报“磁盘只读”或写入超时。原因审计日志不仅记录 SQL 文本还记录连接时间、来源 IP、影响行数等元数据。尤其 MySQL 的 general_log 在log_output TABLE模式下mysql.general_log表膨胀极快而且这个表本身占了mysql库的空间OPTIMIZE TABLE都没法解决。Oracle 的 audit Trail 默认在 SYSAUX 表空间也会撑满。解决MySQL 侧把log_output改回FILE按天用 logrotate 切割保留 7~30 天并且用事件调度器定期清理general_log表更建议直接用slow_query_log代替 general_log记录所有执行超过阈值或全表扫描的语句安全审计够用且体积小一个量级。Oracle 侧用DBMS_AUDIT_MGMT定期清理审计记录同时开启AUDIT_SYS_OPERATIONS之外的按需审计别把整库的 SELECT 全审计那是给自己找罪受。5.5 加固后业务延迟明显变高到底卡在哪现象做完 SSL 强制 审计 行级安全后应用侧监测到 P99 延迟从 20ms 涨到 120ms部分接口直接超时。原因三个因素叠加。SSL 加密握手和加解密在长连接下代价可控但短连接频繁重建时代价显著MySQL 的require_secure_transport ON会让连接池脚本没用 SSL 的旧连接全部失败重试PostgreSQL 的行级安全策略在查询计划中加入了额外的过滤条件索引失效或者过滤代价高慢查询成倍增加。解决先分类排查不要一股脑回滚。如果是 SSL 导致短连接慢把应用侧连接池的ssl-moderequired配好并压测或让 DBA 临时改为PREFERRED观察如果是 RLS 导致慢查询用EXPLAIN ANALYZE看是否走了索引RLS policy 里的条件列必须建索引否则全表扫描代价陡增审计日志导致的写入放大把log_statement从all降到mod或ddl只审计关键操作能消掉七成开销。6. 用自动化脚本做加固核查一个可复用的基线检查思路手动加固定完五类数据库后最怕的是半年后再检查发现某个库的密码被改回弱口令、某台 Redis 被运维重装后裸奔上线。我最后的建议是把你加的每一项加固都变成可重复执行的核查脚本纳入月度巡检而不是靠“记得”来维护。#!/bin/bash # db_hardening_check.sh - 数据库加固基线核查脚本精简版 # 用法: ./db_hardening_check.sh mysql|redis|all check_mysql() { echo MySQL 加固核查 mysql -uroot -p$MYSQL_ROOT_PASS -e SHOW VARIABLES LIKE bind_address; SHOW VARIABLES LIKE require_secure_transport; SHOW VARIABLES LIKE validate_password.policy; SHOW VARIABLES LIKE log_bin; SELECT user, host, plugin FROM mysql.user WHERE userroot AND host%; if [ $? -eq 0 ]; then echo [OK] MySQL 连接正常 else echo [FAIL] MySQL 检查失败请确认账号密码 fi } check_redis() { echo Redis 加固核查 redis-cli -h 127.0.0.1 -p $REDIS_PORT -a $REDIS_PASS EOF 2/dev/null CONFIG GET bind CONFIG GET protected-mode CONFIG GET requirepass CONFIG GET rename-command EOF if redis-cli -h 127.0.0.1 -p $REDIS_PORT PING /dev/null 21; then echo [FAIL] Redis 未设置密码 else echo [OK] Redis 密码已设置 fi }这段脚本的思路不是“把参数全列出来”而是挑几个关键开关做“是/否”判断。bind_address是否为内网、require_secure_transport是否为 ON、root 是否允许从%登录、Redis 是否能无密码 PING——这四个点能暴露九成以上越权风险。你可以按同样思路扩展到 PostgreSQL 的pg_hba.conf里是否混入trust认证、Oracle 的默认账号是否锁定、SQL Server 的 sa 是否禁用。一个我养成的检查习惯每隔一个季度挑一台业务最低峰时段的数据库实例逐条对照她的基线项做一次“模拟加固演练”——就是把加固步骤在测试环境完整执行一遍确认新版本数据库的参数名没变、默认行为没变。数据库大版本升级之后很多加固参数会悄悄改名或失效这种“黑匣子”问题只有演练才暴露得出来。关于自动化核查这个方向我要补一句真心话开工第一天先做的不是写脚本而是把每类数据库的加固基线整理成一张表哪台机器、哪个实例、哪几项必须达标脚本只是把这张表数字化而已。否则做出来的检查脚本再完善也只是给自己一个“我在做安全”的心理安慰。希望这篇围绕 MySQL、Oracle、SQL Server、PostgreSQL、Redis 的加固笔记对你手上的项目有实际帮助——哪怕只帮你少踩一个“改完密码起不来”的坑也算值了。本文还有配套的精品资源点击获取