数据库未授权访问的根因往往不在数据库本身,而在身份认证、网络暴露、权限模型和运维配置四个层面。攻击者能进入数据库,通常不是破解了加密算法,而是找到了一个未设密码的账号、一个暴露在公网的默认端口、一个拥有过高权限的应用连接串,或者一个忘记回收的临时账号。因此防止未授权访问的第一原则是:默认拒绝一切连接,只对明确需要的来源、身份和操作放行。

一、先解决网络暴露问题:数据库不应直接面向公网

生产数据库最基础的安全手段是网络隔离。数据库监听地址不应绑定在0.0.0.0或公网网卡上,而应只监听内网地址或本地回环地址。以MySQL为例,可以在配置文件中检查bind-address参数:

[mysqld]
bind-address = 192.168.10.20

这样数据库只接受来自内网网段的连接。对于PostgreSQL,则通过listen_addresses控制:

listen_addresses = '192.168.10.20'

如果业务架构允许,数据库应置于独立的安全组或子网中,只对应用服务器开放数据库端口,例如MySQL的3306、PostgreSQL的5432、Redis的6379、MongoDB的27017。防火墙规则应精确到源IP或源安全组,而不是对整个内网开放。云环境中,安全组就是数据库的第一道门禁,配置错误等于把数据库钥匙挂在门外。

二、身份认证是核心:强制强密码与唯一账号策略

未授权访问最直接的原因是弱口令和默认账号。很多数据库安装后带有默认账号,如MySQL的root无密码或弱密码、MongoDB早期版本默认无认证、Redis默认无密码。上线前必须完成以下动作:

第一,为所有数据库账号设置强密码,密码长度至少16位,包含大小写字母、数字和特殊字符,避免使用字典词、生日、默认密码。第二,删除或禁用默认账号和匿名账号。MySQL中应删除匿名用户:

DELETE FROM mysql.user WHERE User='';
FLUSH PRIVILEGES;

第三,禁止使用root或管理员账号作为应用连接账号。每个应用使用独立的最小权限账号,这样即使某个应用被攻破,也不会直接拿到数据库的最高控制权。第四,启用认证插件。MySQL 8.0默认使用caching_sha2_password,比旧的mysql_native_password更安全。PostgreSQL的pg_hba.conf应使用scram-sha-256而不是md5或trust。

三、权限模型要细粒度:按需授权,定期回收

很多数据库被入侵后,攻击者能快速拖库,是因为应用账号拥有SELECT、INSERT、UPDATE、DELETE之外的额外权限,比如FILE、SUPER、PROCESS或DROP。授权应遵循最小权限原则,只授予业务必需的权限。MySQL中,应用账号通常只需要对特定库的增删改查:

GRANT SELECT, INSERT, UPDATE, DELETE ON app_db.* TO 'app_user'@'10.0.1.100' IDENTIFIED BY '强密码';

注意授权语句中的主机部分,'app_user'@'10.0.1.100'表示该账号只能从指定IP连接,而不是'%'。如果写成'%',等于允许任意来源使用该账号,一旦密码泄露,数据库直接沦陷。

对于需要执行备份、监控或迁移的运维账号,应单独创建并限制来源IP,且只授予必要权限。例如备份账号只需要SELECT和LOCK TABLES,不需要DROP或CREATE。定期审查账号权限,使用MySQL的SHOW GRANTS或PostgreSQL的\du命令查看所有账号及其权限,发现异常权限立即回收。离职员工、临时项目、测试用途的账号应在使用完毕后立即删除或锁定。

四、连接加密与传输安全

即使数据库在内网,传输层也不应明文。内网中可能存在嗅探、ARP欺骗或已被入侵的主机。启用TLS/SSL加密连接可以防止账号密码和数据在传输中被截获。MySQL启用SSL需要配置证书:

[mysqld]
ssl-ca=/etc/mysql/certs/ca.pem
ssl-cert=/etc/mysql/certs/server-cert.pem
ssl-key=/etc/mysql/certs/server-key.pem

然后创建用户时要求SSL连接:

ALTER USER 'app_user'@'10.0.1.100' REQUIRE SSL;

PostgreSQL可以在postgresql.conf中开启ssl=on,并在pg_hba.conf中使用hostssl而不是host。对于Redis,可以使用stunnel或Redis 6以上版本自带的TLS支持。MongoDB同样支持TLS/SSL,生产环境应强制启用。

五、审计与监控:未授权访问的发现与追溯

防不住所有攻击,但必须能发现攻击。数据库应开启审计日志,记录所有连接尝试、认证失败、权限变更和敏感操作。MySQL的企业版有审计插件,社区版可以使用MariaDB的审计插件或开启general_log(性能影响较大,建议只记录连接和关键操作)。PostgreSQL可以配置log_connections和log_disconnections:

log_connections = on
log_disconnections = on
log_statement = 'ddl'

认证失败日志尤其重要。短时间内大量认证失败往往意味着暴力破解或撞库。可以设置数据库参数限制失败尝试,例如MySQL的connection_control插件可以设置失败延迟。同时,将数据库日志接入集中日志平台,设置告警规则:非工作时间连接、新IP首次连接、高权限账号登录、大量失败认证等都应触发告警。

六、补丁与版本管理

数据库软件本身存在漏洞,未授权访问漏洞也时有发生。例如MongoDB的CVE-2019-2386、MySQL的权限提升漏洞、Redis的未授权访问配合写公钥或写计划任务实现服务器入侵。保持数据库版本更新是基础工作。生产环境应建立补丁评估和升级机制,关注数据库厂商的安全公告,对高危漏洞在测试环境验证后尽快升级。对于无法立即升级的系统,应通过配置加固、网络隔离或WAF等补偿措施降低风险。

七、针对特定数据库的加固要点

不同数据库有各自的未授权访问风险点。Redis默认无密码,且支持写文件,攻击者可以利用未授权访问写入SSH公钥或crontab实现服务器控制。加固方法是设置requirepass强密码,禁止危险命令:

rename-command FLUSHALL ""
rename-command CONFIG ""
rename-command EVAL ""

同时将Redis绑定到内网地址,不要使用默认端口6379暴露公网。MongoDB应启用认证,使用SCRAM认证机制,并配置authorization: enabled。Elasticsearch应启用X-Pack或Search Guard等安全插件,禁止匿名访问。Memcached如果暴露公网,可以被利用进行UDP反射放大攻击,应绑定内网并启用SASL认证。

八、应用层与数据库的联合防御

数据库未授权访问很多时候源于应用层的SQL注入。即使数据库账号权限最小化,SQL注入仍可能读取敏感数据。应用层应使用参数化查询或预编译语句,避免拼接SQL。数据库账号的权限限制可以作为第二道防线,例如应用账号不应有权限访问mysql.user表、information_schema中的敏感视图或执行LOAD_FILE。对于高并发业务,可以使用数据库防火墙或代理层,如ProxySQL、MaxScale,在代理层实现SQL过滤、连接限制和审计。

九、定期安全评估与渗透测试

安全配置会随着业务变更、人员流动和版本升级而退化。建议每季度进行一次数据库安全配置核查,检查项包括:是否有账号使用弱密码、是否有账号允许从任意主机连接、是否有账号拥有过高权限、是否开启了审计日志、是否绑定了安全的内网地址、是否更新了安全补丁。同时可以模拟攻击者视角进行渗透测试,尝试从外部和内部扫描数据库端口,测试默认口令,验证未授权访问是否可能。

十、应急响应与恢复准备

即使所有防护都到位,也要假设数据库可能被未授权访问。备份是最后的防线。备份应加密存储,且备份文件不应与数据库放在同一台服务器上。定期演练恢复流程,确保备份可用。一旦发现未授权访问,应立即隔离数据库,切断可疑连接,修改所有账号密码,审计日志确定入侵路径和影响范围,根据备份恢复数据,并修复导致入侵的配置漏洞。

数据库未授权访问防护是一个系统工程,网络隔离、身份认证、权限控制、传输加密、审计监控、补丁管理、应用安全、定期评估和应急响应缺一不可。任何一环的疏忽都可能让前面的努力付诸东流。真正有效的安全不是某一条配置,而是一套持续运行、不断修正的机制。