简介:面向数据库运维、安全管理人员及需要满足合规要求的政企IT团队,这份Sql Server数据库系统加固规范文档提供了一套可落地的安全配置基线。内容围绕账号管理、认证授权、日志配置、通信协议、设备安全等核心模块展开,细化到具体核查项与操作指引,涵盖最小权限分配、密码不少于12位且90天更新、登录失败锁定、双因素认证、SSL/TLS加密通信、防火墙与入侵检测、防病毒安装和定期安全更新等要求,能够直接对照企业内网环境逐项整改,也可作为等保测评、安全自查和加固方案编制的依据。
资源包包含1个doc文件,压缩包大小1.73MB,文档目录清晰、条目编号规范,便于翻阅和内部培训复用。目前已有245人学习下载,适合正在完善数据库安全基线、梳理加固清单或编写运维文档的读者快速参考。
1. SQL Server加固规范:一份能落地的检查清单,而不是文档库里的摆设
在数据库安全这件事上,很多人是被等保测评或安全扫描逼到墙角的。真正把 SQL Server 加固规范读进去的人会明白:它不是一堆抽象的"应开启""应配置",而是一份带编号、带实施命令、带回退方案的作业指导书。这套规范来自某运营商管理信息系统部 2022 年 3 月发布的 MSSQL 加固规范,覆盖账号管理、日志配置、通信协议、设备安全四个维度,所有检查项统一编号为 SHG-Mssql-xx-xx-xx,每一条都标了实施风险、重要等级和回退方案。适合接手存量数据库、要做安全合规整改的 DBA 和运维人员,照着逐条执行能避开大多数低级风险,也适合作为内审基线文档留存。
2. 账号管理与认证授权:六个检查项背后的权限收敛逻辑
账号管理是这套规范里条目最多、最容易被"照着删一删"的部分。六个编号从 SHG-Mssql-01-01-01 到 01-06,覆盖了账号分配、无效账号清理、服务账号权限、最小权限原则、数据库角色和强口令。拆完这六条你会发现,它其实在讲一件事:把每个账号的权限边界画清楚,把共享和默认的隐患全部消掉。
2.1 先盘点账号全景:从 syslogins 到 server_principals
规范第一条 SHG-Mssql-01-01-01 要求为不同管理员分配不同账号,避免共享账号。实施前先列出现有登录名,规范原文用的命令是:
USE master; SELECT name, password FROM syslogins ORDER BY name;这段命令在 SQL Server 2000 里能直接看到 password 字段,但在 2005 以后的版本里,syslogins 视图的 password 列默认返回乱码或 NULL,直接抄规范命令会得到一张基本没有参考价值的清单。常见做法是换成 2005+ 的系统视图:
SELECT principal_id, name, type_desc, is_disabled FROM sys.server_principals WHERE type IN ('S', 'U') ORDER BY name;type 为 S 的是 SQL 登录名,type 为 U 的是 Windows 登录名,is_disabled 标记是否被禁用。参数说明:这条查询能看到所有实例级主体,但看不到每个账号在哪些库里有权限,想看库级权限要再 join sys.database_principals。规范原文建议用 sp_addlogin 创建账号,那是 2000 时代的存储过程,2005 之后推荐用 CREATE LOGIN:
CREATE LOGIN user_name_1 WITH PASSWORD = 'password1', CHECK_POLICY = ON; CREATE LOGIN user_name_2 WITH PASSWORD = 'password2', CHECK_POLICY = ON;CHECK_POLICY = ON 是这条命令的关键参数,它让新密码必须满足 Windows 密码策略的长度、复杂度和过期要求,而不是像旧语法那样只检查非空。
2.2 无效账号与启动账号的清理边界
规范 SHG-Mssql-01-01-02 要求删除或锁定无效账号,原文操作路径是"企业管理器 -> SQL Server 组 -> 登录 -> 右键删除",并给出了判断依据:询问管理员哪些账号是无效账号。这句话看着像废话,其实是提醒你不要看哪个登录名不顺眼就删。我在实际拆解时遇到过两次翻车,都是把 SQL Server 服务的启动账号当成冗余账号给删了,结果服务直接起不来。删除前先做交叉核对,确认这个登录名不是服务账号,也不是某个作业的所有者:
SELECT servicename, service_account FROM sys.dm_server_services;这条命令能列出 SQL Server 相关 Windows 服务当前使用的登录账户。回退方案在规范里写得极简:"增加删除的帐户",但在生产环境想恢复一个被删的 SQL 登录名,最稳妥的办法是提前记录它的 sid 和密码哈希。2005+ 可以用 sys.sql_logins 查到这两样:
SELECT name, sid, password_hash FROM sys.sql_logins WHERE name = '待删除账号';有了 sid,恢复时可以用 CREATE LOGIN ... WITH SID = ... 把账号原样加回来,权限映射不会乱。这个动作是规范原文没有展开的,但遇到一次作业归属漂移你就懂了。
2.3 限制启动账号权限:三个边界,一个红线
规范 SHG-Mssql-01-01-03 是限制 SQL Server 服务启动账号的权限,原文建议新建服务账号后将其从 User 组中删除,且不提升为 Administrators 组成员,只授予启动 SQL Server 所需的最少权限。这里有个容易误解的点:"从 User 组删除"不是说账号不能登录系统,而是让它不具备交互式登录和普通用户权限,只保留"作为服务登录"这一项能力。现代 Windows Server 环境下最常用来替代的方案是使用虚拟账号或托管服务账号 gMSA,密码由域控制器自动轮换,运维人员不需要手动改服务密码。红线只有一条:不要图省事把 SQL Server 服务改成 LocalSystem 或本地管理员组成员。子进程的权限继承是实打实的,一旦数据库被注入或提权,攻击者拿到的直接是系统级权限,日志审计在这些场景里已经没有意义。
2.4 最小权限与数据库角色:用角色兜住权限,而不是直接撒给账号
规范 SHG-Mssql-01-01-04 和 01-05 连着看最有价值:先是取消业务账号不需要的服务器角色和数据库角色,再是引入统一角色来管理对象权限。原文给的权限范围是 SELECT、INSERT、UPDATE、DELETE、EXEC、DRI 六种,其中 DRI 是 REFERENCES 权限,很多初学者会漏掉,但业务表之间有外键约束时,缺了它表结构变更会报权限不足。常见做法是先在业务库里建角色,再把对象权限授给角色,最后把账号加入角色:
USE [business_db]; CREATE ROLE rw_role; GRANT SELECT, INSERT, UPDATE, DELETE ON dbo.orders TO rw_role; GRANT EXEC ON dbo.sp_order_sync TO rw_role; ALTER ROLE rw_role ADD MEMBER app_user;参数说明:rw_role 是自定义角色名,建议按业务模块命名,便于审计;GRANT EXEC 只给存储过程执行权,不要顺手给 ALTER 或 CONTROL;ALTER ROLE ... ADD MEMBER 在 SQL Server 2012+ 有效,2000 环境对应的是 sp_addrolemember。判断依据规范写的是"业务测试正常",实际操作时要注意:权限只从角色来,账号本身不持有任何直接对象权限,否则换人维护时权限追溯就是一场灾难。
2.5 空密码与 sa 强口令:最直观,也最容易被跳过
规范 SHG-Mssql-01-01-06 原文的命令非常有时代感:
USE master; SELECT name, password FROM syslogins WHERE password IS NULL ORDER BY name; EXEC sp_password '旧口令', '新口令', '用户名';syslogins 表里 password 列为 NULL 表示空密码,这在 SQL Server 2000 和兼容模式下有效;2005 以后强制密码策略,新登录名已经无法设置空密码,但历史升级库里可能仍残留旧账号。现代版本里对应做法是靠 CHECK_POLICY 兜底,修改口令用 ALTER LOGIN:
ALTER LOGIN sa WITH PASSWORD = '新强口令', CHECK_POLICY = ON;关于强口令的强度,规范正文只给了"sa 至少 10 位"的下限,我一般按更严格的标准执行:长度不少于 12 位,包含大写、小写、数字、特殊字符四类中的三类,90 天强制更换,登录失败超过 5 次锁定账号。注意一点:sa 账号在 2005+ 默认是禁用的,如果合规检查要求启用 sa,改完密码后要确认它没有被加入任何 SQL Agent 作业或维护计划的登录链中,否则密码轮换会连带影响一批自动化任务。
3. 日志与审计:把审计级别调到"全部"之前,先想清楚三件事
日志配置在规范里只有一条编号 SHG-Mssql-02-01-01,要求把审计级别调整为"全部",身份验证调整为"SQL Server 和 Windows"。命令本身简单到一句话,但全量审计对生产库的影响远不止翻一个下拉框,拆完这条规范我更确定:先想清楚三件事再动手。
3.1 审计级别"全部"到底记录了哪些内容
打开数据库属性选择安全性,把审计级别改为"全部"后,SQL Server 会把所有登录事件写入错误日志和 Windows 事件日志,包括登录账号、登录成功或失败、登录时间、远程登录 IP。这里有个容易被忽略的点:规范原文写的是"数据库属性",但登录审计实际是实例级配置,在 SQL Server 2000 里对应"服务器属性 -> 安全性",2014 以后的路径是"服务器属性 -> 安全性 -> 登录审核",改错层级会出现"明明改了审计级别,日志里还是只有失败登录"的情况。2008+ 的版本可以用 server audit 把登录审计独立落盘,不污染错误日志:
USE master; GO CREATE SERVER AUDIT audit_login TO FILE (FILEPATH = 'D:\sqlaudit\'); GO CREATE SERVER AUDIT SPECIFICATION audit_login_spec FOR SERVER AUDIT audit_login ADD (SUCCESSFUL_LOGIN_GROUP, FAILED_LOGIN_GROUP) WITH (STATE = ON);FILEPATH 指定的目录要提前建好,且 SQL Server 服务账号要有写入权限,否则审计启动时报错。SUCCESSFUL_LOGIN_GROUP 和 FAILED_LOGIN_GROUP 分别对应成功和失败登录事件,审计落盘文件默认是 .sqlaudit 格式,后续用 sys.fn_get_audit_file 读取。
3.2 日志保留与磁盘空间的账本
开启全量审计后最先暴露的问题不是安全性,而是磁盘。假设每秒有 20 次登录尝试,一条审计记录几十到一百多字节,一小时就是数 MB;暴力破解扫上几天,C 盘或审计盘很快告警。SQL Server 错误日志采用循环覆盖机制,2000 时代需要手动执行 DBCC ERRORLOG 轮换,现代版本可以配置最多保留文件数。Windows 事件日志侧的容量策略也要同步检查,否则事件日志满了之后审计记录会直接丢失。常见做法是加一条每日轮换任务:
EXEC sp_cycle_errorlog;这条命令主动把当前错误日志切换成历史文件并新建一个,建议放进维护计划的每日任务里。配套一个磁盘空间监控脚本,低于阈值就告警,防止日志把盘写满导致数据库自动关闭或审计失效。
3.3 登录审计的补位:LOGON 触发器记录客户端 IP
审计级别"全部"能记录登录时间和是否成功,但错误日志里查 IP 要翻半天,2000 时代的日志字段还不全。2005+ 可以用 LOGON 触发器把登录事件实时写进独立审计表:
USE msdb; GO CREATE TABLE dbo.login_audit ( login_name nvarchar(128), login_time datetime, client_ip varchar(32) ); GO CREATE TRIGGER trg_logon_audit ON ALL SERVER FOR LOGON AS BEGIN INSERT INTO msdb.dbo.login_audit(login_name, login_time, client_ip) SELECT ORIGINAL_LOGIN(), GETDATE(), CONNECTIONPROPERTY('client_net_address'); END;触发器要建在 msdb 这类独立数据库,不要放业务库,否则业务库恢复时登录审计跟着失效。最关键的坑是:LOGON 触发器如果在执行时报错,登录会被直接拒绝,相当于给自己挖了一个拒绝服务的坑。生产环境上这种触发器必须用 BEGIN TRY / BEGIN CATCH 包住写库逻辑,并保证 msdb 的写入权限始终正常。
4. 通信协议加固:裁剪协议、注册表三键值与强制加密
规范 SHG-Mssql-03 系列包含三条:网络协议只保留 TCP/IP,加固 TCP/IP 协议栈的注册表参数,以及强制协议加密。这三条从减少暴露面到内核加固再到传输加密,层层递进。拆完这一章的结论是:通信协议加固是整套规范里技术含量最高、实施顺序最容易搞反的部分。
4.1 服务网络实用工具:只保留 TCP/IP,其余协议全部禁用
规范原文的路径是"在 Microsoft SQL Server 程序组,运行服务网络实用工具",建议只使用 TCP/IP,禁用其他协议。SQL Server 2000 时代默认监听协议包括 TCP/IP、Named Pipes(命名管道)和 VIA,命名管道走 139/445 端口,与 SMB 服务混在一起,容易被跨协议传播的工具横向移动。2008+ 的操作位置在"SQL Server 配置管理器 -> SQL Server 网络配置 -> MSSQLSERVER 的协议",禁用 Named Pipes 和 VIA,保留 TCP/IP;Shared Memory 协议看情况,远程应用为主的实例可以直接禁用,但本机用 SSMS 连接的 DBA 会发现连不上或变慢,体验上像"卡了一下"。操作完确认监听端口,用系统命令核对:
netstat -ano | findstr ":1433"输出里会显示监听进程 PID,到服务列表里核对这个 PID 对应的是 sqlservr.exe 而不是其他程序。如果实例监听非默认端口 1433,业务侧连接串和防火墙入站规则要同步调整,这一点是协议裁剪中最常见的翻车点。
4.2 TCP/IP 协议栈加固:三个注册表键值的真实含义
规范 SHG-Mssql-03-01-02 给的是操作系统层 TCP/IP 栈加固,和 SQL Server 版本没有直接关系,键值位置都在 HKLM\System\CurrentControlSet\Services\Tcpip\Parameters 下。建议直接核对键值再决定是否修改:
reg query "HKLM\System\CurrentControlSet\Services\Tcpip\Parameters" /v DisableIPSourceRouting reg query "HKLM\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters" /v EnableICMPRedirect reg query "HKLM\System\CurrentControlSet\Services\Tcpip\Parameters" /v SynAttackProtect三个键值的含义和调整目标分别是:
| 键值 | 建议值 | 作用 |
|---|---|---|
| DisableIPSourceRouting | 2 | 完全禁止 IP 源路由,防御源路由欺骗攻击 |
| EnableICMPRedirect | 0 | 禁用 ICMP 重定向,防止伪造报文篡改路由表 |
| SynAttackProtect | 2 | 开启 SYN 攻击保护,配合半开连接阈值参数生效 |
补充说明:SynAttackProtect 在现代 Windows Server 版本中已经由系统内置的动态 SYN 防御机制部分替代,写进去不报错,但不代表它在每代系统上都有同等的防御效果,查这个键更多是为了满足基线合规核查点。改完注册表后需要重启系统或至少重启网卡才会完全生效,这也是"改完没效果"的最常见原因——不是键值写错了,是没触发重读。
4.3 强制协议加密:证书、TLS 与客户端连接串
规范 SHG-Mssql-03-01-04 要求把服务器网络配置工具的"常规"设置为"强制协议加密"。2000 时代这个开关在服务端勾选后,所有客户端连接必须走加密通道。现代版本对应的是配置管理器 -> SQL Server 网络配置 -> MSSQLSERVER 协议 -> 标志 -> ForceEncryption,设为"是"。这里最核心的坑是:SQL Server 默认使用自签名证书,客户端不信任这台服务器的证书,加密链路根本建立不起来。正确顺序是先给服务器申请一张证书(CN 与机器名一致),再开启强制加密,最后用客户端验证:
SELECT session_id, encrypt_option, client_net_address FROM sys.dm_exec_connections;encrypt_option 为 TRUE 表示该连接已加密。如果强制加密开了之后出现"证书链验证失败"或"SSL Provider 接收数据时出错",基本可以断定是客户端驱动版本太老或服务器证书不在客户端信任列表里。测试环境可以先让客户端连接串加 TrustServerCertificate=true 验证链路,生产环境必须换正式证书或统一升级驱动。
5. 加固实施避坑实录:五条让数据库直接"翻车"的操作
设备其他安全要求这一块,规范给了两条:停用不必要的存储过程(SHG-Mssql-04-01-01)和安装补丁(SHG-Mssql-04-01-02)。补丁管理那条的原始操作是 select @@version,并附带了一份 SQL Server 2000 的版本对照表:
| 版本号 | 补丁版本 |
|---|---|
| 8.00.194 | SQL Server 2000 RTM |
| 8.00.384 | SQL Server 2000 SP1 |
| 8.00.534 | SQL Server 2000 SP2 |
| 8.00.760 | SQL Server 2000 SP3 |
| 8.00.2039 | SQL Server 2000 SP4 |
提醒一句:现代 SQL Server 的补丁核对不能只看大版本号,还要对照官方月度累计更新说明。下面重点讲危险存储过程停用过程中最容易出问题的五个操作,全部按"现象 -> 原因 -> 解决"来拆。
5.1 删了 xp_cmdshell,作业和调度脚本批量报警
现象:按照规范删掉 xp_cmdshell 等扩展存储过程后,第二天凌晨 SQL Agent 作业和 DTS 包批量失败,报"未能找到存储过程"。
原因:存量系统里经常有调度脚本通过 xp_cmdshell 调用外部程序或写文件,删除扩展存储过程后这些依赖全部断裂。规范列了一长串建议删除的存储过程,但没提先查依赖这一步。
解决:删除前先全库查依赖:
SELECT DISTINCT o.name FROM syscomments c JOIN sysobjects o ON c.id = o.id WHERE c.text LIKE '%xp_cmdshell%';2005+ 的环境改用 sys.sql_modules 查。确认没有依赖后再执行删除。SQL Server 2005 以后更推荐的做法不是删除而是禁用,回退成本完全不同:
EXEC sp_configure 'show advanced options', 1; RECONFIGURE; EXEC sp_configure 'xp_cmdshell', 0; RECONFIGURE;sp_configure 方式可以随时改回来,而 sp_dropextendedproc 删除后需要手工重建,代价大了不止一个量级。
5.2 注册表键值改完,安全扫描报告原封不动
现象:三个 TCP/IP 注册表键值都改成了规范要求的值,扫描报告显示这些检查项仍然不通过。
原因:注册表键值改完后没有重启系统,或者系统版本较新,SynAttackProtect 键值在这个版本上已不再承担原有职能。
解决:重启系统后再跑扫描;扫描前用 reg query 逐项核对键值状态,以重启后行为为准。不要拿刚改完未刷新的数值当整改依据,这类问题在攻防中都属于"看着改了,实际没生效"的黑匣子。
5.3 删除"无效账号",SQL Server 服务起不来
现象:按 SHG-Mssql-01-01-02 清理无效账号后,实例服务启动失败,事件日志提示找不到服务账号。
原因:被删的账号恰恰是 SQL Server 服务登录账户,而不是业务账号。
解决:动手前在服务管理器里确认服务的"登录身份",并配合 sys.dm_server_services 交叉核对。如果账号已经删了,最快的临时恢复是把服务登录身份改成 LocalSystem 或 NetworkService,但长期方案还是要重建专用服务账号并恢复服务属性。
5.4 开启强制协议加密,一批客户端连接全部失败
现象:ForceEncryption 开启后,多台客户端的连接抛"SSL Provider, error: 0"或证书信任错误,应用连不上库。
原因:客户端驱动太老,只支持老版本 TLS,而服务器系统已默认关闭这些协议;或服务器端自签名证书不在客户端信任列表。
解决:分批切换而不是集群一把梭。先用最新驱动在测试环境验证加密链路,再让核心应用先切,外围应用逐步切,全部稳定后保持强制加密。回退动作就是临时关闭 ForceEncryption,但由此带来的安全窗口要在下一个维护窗口内补上。
5.5 sa 改完强口令,业务系统连环报登录失败
现象:把 sa 密码改成强口令后,多个业务系统在凌晨连接池刷新时集中报警登录失败。
原因:应用连接串里写死 sa 和旧口令,密码变更后连接池里的旧连接全部失效,应用没有自动重连机制。
解决:把 sa 当成应急通道,而不是应用通道。改密码前先看谁在用 sa 连接:
SELECT s.login_name, c.client_net_address, s.program_name FROM sys.dm_exec_sessions s JOIN sys.dm_exec_connections c ON s.session_id = c.session_id WHERE s.login_name = 'sa';确认没有业务依赖后再改。如果应用无法联动修改,宁可不改 sa,先通过防火墙放行来源和账号权限收窄来降低风险,等应用改造完成后再轮换密码。
6. 加固验收与回退:一张自检表,一份后悔药
整套规范拆完,最值得拿走的其实是一个可执行的验收路径,以及每一条都配套的回退动作。这里整理一份能直接打印的自检表,把 SHG 编号变成生产环境可核对的硬性指标。
6.1 逐项自检:把 SHG 编号变成可核对的运行指标
| 检查项 | 验证命令 / 路径 | 期望结果 |
|---|---|---|
| 账号唯一性 | SELECT name FROM sys.server_principals WHERE type = 'S' | 每个管理员独立登录名,无共享账号 |
| 空密码 | SELECT name FROM sys.sql_logins WHERE password_hash IS NULL | 无记录 |
| sa 强口令 | ALTER LOGIN sa WITH PASSWORD = '...', CHECK_POLICY = ON | 已生效,sa 保持禁用 |
| 审计级别 | 服务器属性 -> 安全性 -> 登录审核 | 成功与失败登录均记录 |
| 协议裁剪 | 配置管理器 -> 协议 | 仅 TCP/IP 启用 |
| TCP/IP 栈加固 | reg query 三个键值 | 分别为 2 / 0 / 2 |
| 强制加密 | SELECT encrypt_option FROM sys.dm_exec_connections | TRUE |
| 危险存储过程 | SELECT name FROM sysobjects WHERE name LIKE 'xp[_]cmdshell' | 不存在或已禁用 |
| 补丁版本 | SELECT @@VERSION | 高于已知漏洞修复版本 |
6.2 回退方案才是这份规范最值钱的部分
这套规范每个编号都带"回退方案"字段,例如账号删除对应"增加删除的帐户",注册表修改对应"还原更改键值"。拆过的加固文档里,能把回退写进正文的是少数。我的执行习惯是为每个检查项保留三样东西:变更前基线导出文件、变更脚本原文、一行能完成的回退命令。操作顺序固定为:先备份 master 和 msdb,再逐条实施,每条完成后跑一次业务连通性测试,记录耗时和影响范围。
6.3 一次失败的加固让我养成的习惯
几年前做某库存系统的 SQL Server 加固,我先改了 sa 密码,结果跑批脚本半夜连接失败,业务中断了两个小时。原因就是连接串里写死了旧口令,我改密码时没有先查 sys.dm_exec_sessions,也没有做回退演练。从那以后,我每次做数据库加固都强制走一遍:先记录当前状态,再逐条实施,每条做完验证业务,把回退命令单独存成一个文件,任何意外都能在两分钟内还原。这份规范的价值不只是罗列了多少检查项,而是它把每条操作的风险等级和回退路径都标了出来,哪怕命令还停留在 SQL Server 2000 时代,思路放到 2016、2019、2022 上依然成立。希望帮到你。
本文还有配套的精品资源,点击获取