资讯动态

SQL Server数据库加固规范落地:账号权限、协议审计与回退验收

发布时间:2026/10/27 3:03:38 来源:尧图企业网站定制
简介《Sql Server数据库系统加固规范》面向数据库管理员、安全运维与等保测评人员围绕SQL Server账号管理、认证授权、日志配置、通信协议及设备安全给出可落地的加固检查与配置参考。压缩包内为1个doc文档约1.73MB按SHG-Mssql编号组织条目逐项列出实施目的、问题影响、系统当前状态、实施步骤、回退方案、判断依据、实施风险与重要等级便于对照排查和整改。内容涉及最小权限、密码长度与有效期、登录失败锁定、双因素认证、操作日志审计、SSL/TLS传输加密、访问限制以及防毒与定期更新等要点适合作为安全基线核查和加固实施时的案头资料。已有245人学习可作为SQL Server安全配置与合规检查的实用参考。1. 一份规范放在手里最怕的是照着目录从头改到尾接手某公司一台跑了六年的业务库时前任留下的交接文档里最厚的一份叫《Sql Server 数据库系统加固规范》账号管理、认证授权、日志配置、通信协议、设备其他安全要求五块编号从 SHG-Mssql-01-01-01 一路排到 04-01-02每一条都写了实施目的、问题影响、回退方案和重要等级。我第一次照着改三天改完第四天早上报表作业全线失败备份任务卡在写文件那一步应用侧报登录失败——规范本身没写错错在把它当说明书从头抄到尾。Sql Server 数据库系统加固规范 这类文档写的是「应该长成什么样」没写「你这台机器上该改哪一行、改完怎么退回去」。原文里的syslogins、企业管理器、sp_addlogin是 SQL Server 2000 时代的语法现在实例上是sys.server_principals、SSMS、CREATE LOGIN同名条目背后的命令完全不一样。同一句「禁用不必要的协议」在一台还挂着老客户端的库上执行就是一次断连事故。这份笔记写给要在一台真实实例上把这套规范落完的人先盘环境、再逐条实施、最后能验收中途坏了有得救。2. 落地前盘环境版本基线、账号清单与回退包加固本身不难难的是「改完之后业务还活着」。所以真正动手之前要做的事比改配置本身更花时间。我一般会留出半天只做盘点和备份不碰任何配置项盘点结果直接落成几张表后面每条加固动作都对着表改。2.1 先确认版本与补丁别拿 2000 的命令打新版本规范原文给了一张补丁对照表8.00.194 对应 SQL Server 2000 RTM8.00.384 是 SP18.00.534 是 SP28.00.760 是 SP38.00.2039 是 SP4。这套对照只在 8.00 这条线里成立2005 之后的 build 号规则完全不同所以第一步永远是看实例自己报什么而不是猜。-- 一次性取出版本、补丁级别、版本类型和实例名落到盘点表里 SELECT VERSION AS ver_text, -- 完整版本字符串含操作系统信息 SERVERPROPERTY(ProductVersion) AS build_no, -- 形如 8.00.2039 / 10.50.6000.34 SERVERPROPERTY(ProductLevel) AS patch_level, -- RTM / SP1 / SP2 / SP3 / SP4 SERVERPROPERTY(Edition) AS edition, -- 标准版 / 企业版 / Express SERVERPROPERTY(InstanceName) AS inst_name, -- 命名实例在这里默认实例返回 NULL SERVERPROPERTY(IsIntegratedSecurityOnly) AS win_auth_only; -- 1 表示只允许 Windows 身份验证build_no是判断补丁基线的唯一可靠依据ver_text只是给人看的。IsIntegratedSecurityOnly这一列很关键如果它返回 1说明实例当前只接受 Windows 认证这时候去改「身份验证模式」等于动认证体系必须排进维护窗口不能顺手改。命名实例要额外记下来因为后面协议配置、注册表路径、服务名都跟实例名绑定默认实例和命名实例的注册表键不是同一个位置。2.2 把登录名、角色、权限导成一张表规范第一条要求「为不同的管理员分配不同的账号」前置动作是先知道现在有哪些账号。原文给的语句是use master加Select name,password from syslogins order by name这条在新版本上还能跑但password列返回的是星号读不出任何信息。换成系统视图更实在-- 登录名盘点账号类型、是否启用、默认库、最近一次登录时间 SELECT sp.name AS login_name, sp.type_desc AS login_type, -- SQL_LOGIN / WINDOWS_LOGIN / WINDOWS_GROUP sp.is_disabled AS disabled, -- 1 表示已禁用 sp.default_database_name AS default_db, sp.create_date, sp.modify_date, ISNULL(CONVERT(varchar(19), sp.last_login_time, 120), 从未登录) AS last_login FROM sys.server_principals AS sp WHERE sp.type IN (S, U, G) -- SSQL 登录UWindows 登录GWindows 组 ORDER BY sp.name; -- 服务器角色成员谁挂在了 sysadmin / securityadmin 这类高权限角色上 SELECT r.name AS role_name, m.name AS member_name FROM sys.server_role_members AS rm JOIN sys.server_principals AS r ON r.principal_id rm.role_principal_id JOIN sys.server_principals AS m ON m.principal_id rm.member_principal_id ORDER BY r.name, m.name;第一段查的是「有哪些门」第二段查的是「谁拿着万能钥匙」。sysadmin成员清单要单独抄一份出来加固过程中任何账号被误禁用、误降权都能靠这份清单定位。last_login这一列是判断「无效账号」的直接证据超过半年没登录、又不是服务账号的基本可以列进待处理名单。2.3 回退包动手之前必须留的四样东西规范里每条都写了「回退方案」但回退方案能不能用取决于你有没有提前留下原值。我一般会固定留四样序号留存内容取得方式用途1master、msdb、model 三个系统库的完整备份完整备份落地到独立磁盘账号、作业、登录审计配置被改坏时整体回退2业务库完整备份 最近一次日志备份完整 日志权限误删导致应用报错时快速比对3登录名、角色、权限清单2.2 的两段查询结果导出成文本逐个账号还原4注册表与协议原值3 个 TCP/IP 键值、每个协议的启用状态、服务账号名TCP/IP 加固和协议收敛的回退依据系统库备份用一条语句就能落-- 三个系统库依次备份路径按实际磁盘改不要和数据文件放同一块盘 BACKUP DATABASE master TO DISK D:\backup\pre_hardening_master.bak WITH INIT, COMPRESSION; BACKUP DATABASE msdb TO DISK D:\backup\pre_hardening_msdb.bak WITH INIT, COMPRESSION; BACKUP DATABASE model TO DISK D:\backup\pre_hardening_model.bak WITH INIT, COMPRESSION;WITH INIT会覆盖同名备份文件所以文件名里必须带日期或「pre_hardening」这类前缀别直接覆盖上一次的备份。COMPRESSION在标准版及以上可用能省一半空间Express 版会报错去掉这个参数就行。master 库很小但它是账号信息的载体一旦sysadmin角色被改空只能靠它恢复。2.4 摸清谁在调用危险存储过程规范最后一章要求停用xp_cmdshell、sp_OACreate、xp_regwrite这一批扩展存储过程。原文给的做法是exec sp_dropextendedproc xp_cmdshell一行行删。问题是只要有一个老接口或一个作业在调它删完第二天就会有人来找你。动手前先查有没有对象引用-- 在业务库里找引用了危险过程的模块包括存储过程、函数、触发器 SELECT OBJECT_NAME(m.object_id) AS module_name, m.definition FROM sys.sql_modules AS m WHERE m.definition LIKE %xp_cmdshell% OR m.definition LIKE %sp_OACreate% OR m.definition LIKE %xp_regwrite% OR m.definition LIKE %xp_dirtree%;sys.sql_modules只覆盖 T-SQL 模块查不到应用层拼出来的动态 SQL也查不到作业步骤里的命令行。作业那部分要去 msdb 里翻sysjobsteps看command列有没有cmdshell字样。这两处都干净才说明可以安全删除只要有一处命中就先跟业务方确认替代方案把「删除」改成「先禁用」。3. 账号管理与认证授权六条规范逐条落到命令这一章是规范里条目最多的部分六条编号 01-01-01 到 01-01-06重要等级从三星到一星不等。按我的经验顺序不能反着来先建新账号、再禁旧账号、然后调权限、最后改口令中途任何一步走错都能靠前一步留下的东西还原。3.1 一人一账号从 sp_addlogin 到 CREATE LOGIN规范 01-01-01 要求「按照用户分配账号避免不同用户间共享账号」原文示例是sp_addlogin user_name_1,password1。这条语法在旧版本上还能用但密码以明文出现在脚本和日志里本身就是一个新隐患。-- 新版本写法单独建登录名强制密码策略指定默认库 CREATE LOGIN [app_report] WITH PASSWORD 换成实际强口令, -- 至少 10 位含大小写、数字、符号 DEFAULT_DATABASE [BizDB], -- 登录后默认落到业务库减少误操作 CHECK_POLICY ON, -- 继承 Windows 密码复杂度与锁定策略 CHECK_EXPIRATION ON; -- 启用口令有效期 -- 建库内用户并只给只读权限报表类账号通常只需要这些 USE [BizDB]; CREATE USER [app_report] FOR LOGIN [app_report]; ALTER ROLE [db_datareader] ADD MEMBER [app_report];CHECK_POLICY ON是这条命令里最值得保留的参数它把密码复杂度、锁定阈值交给操作系统策略管省得自己写规则。代价是如果这台机器的本地安全策略要求 90 天改密应用连接串里的密码到期就会失效所以业务账号一般设CHECK_EXPIRATION OFF运维账号设ON这两类账号必须分开建不要图省事共用一个。旧语法sp_addlogin不是不能用是在新版本上已经不推荐而且它绕过了密码策略。建角色、把角色赋给用户是规范里「把角色赋给不同的用户」这句话的具体落法-- 建一个只读角色把对象权限挂在角色上人员变动时只改成员关系 USE [BizDB]; CREATE ROLE [role_report_read]; GRANT SELECT ON SCHEMA::[dbo] TO [role_report_read]; GRANT EXECUTE ON SCHEMA::[dbo] TO [role_report_read]; ALTER ROLE [role_report_read] ADD MEMBER [app_report];权限挂在角色上而不是人身上这是后面「权限最小化」能落地的前提。人走了只删成员关系不用逐条回收对象权限也不会出现「这个人权限收干净了那个人还留着」的情况。3.2 无效账号与默认账号的处置顺序规范 01-01-02 要求「删除或锁定无效账号」原文的操作路径是企业管理器里右键删除。删除是不可逆的所以我的顺序永远是「先禁用、观察一个周期、确认没人用、再删」。-- 第一步禁用不删除保留回退可能 ALTER LOGIN [old_temp_user] DISABLE; -- 第二步观察期内确认没有连接再来返回 0 行才可以走第三步 SELECT session_id, login_name, status, program_name, host_name FROM sys.dm_exec_sessions WHERE login_name old_temp_user; -- 第三步确认无用后删除用户先从库里移除再删登录名 USE [BizDB]; DROP USER IF EXISTS [old_temp_user]; USE [master]; DROP LOGIN [old_temp_user];删登录名的顺序必须是「先库内用户、后服务器登录名」反过来会留下没有对应登录名的孤儿用户sys.database_principals里能看到但谁也登不上排查时很费时间。关于默认账号sa不要直接删规范也没要求删——它要求的是「减少系统安全隐患」。合理做法是先确认实例是否启用了 SQL 认证如果业务全部走 Windows 认证就把sa禁用-- 先看 sa 当前状态is_disabled 返回 1 说明已经禁用 SELECT name, is_disabled, last_login_time FROM sys.sql_logins WHERE name sa; -- 业务不依赖 SQL 认证时禁用而不是删除 ALTER LOGIN [sa] DISABLE;禁用sa之后如果还有应用用它连库会立刻报「登录失败」所以这一步必须和业务方确认过或者先把应用改成独立账号再禁。3.3 启动账号降权最容易把服务搞起不来的地方规范 01-01-03 要求「限制启动账号权限」原文写的是新建 SQL Server 服务账号后从 Users 组中删除不要把账号提升为 Administrators 组成员。这条是所有条目里风险最高的因为它直接决定服务能不能起来。正确的做法是分步走每一步都验证服务状态# 用 PowerShell 查看当前各服务的登录身份确认改之前是什么账号 Get-CimInstance Win32_Service | Where-Object { $_.Name -like MSSQL* -or $_.Name -like SQLAgent* } | Select-Object Name, StartName, State # 改服务账号示例服务名 MSSQLSERVER命名实例是 MSSQL$实例名 $svc Get-CimInstance Win32_Service -Filter NameMSSQLSERVER $svc.Change($null, $null, $null, $null, $null, $null, DOMAIN\svc_sqlserver, 口令, $null, $null, $null)StartName就是服务启动身份改之前必须记下来。Change方法的第七、第八个参数分别对应账号和密码账号格式是「域\用户」或「.\本地用户」写错格式服务会直接起不来。改完账号之后有三件事必须马上做否则服务大概率启动失败给新账号授予「作为服务登录」权限给新账号授予数据文件目录、日志目录、备份目录的读写权限如果开了 SQL Server 代理代理服务账号也要单独配。规范里提到的 SQLRunAs 账户本质就是「一个只跑数据库、不进管理员组、不登录系统」的专用账号它不需要交互式登录权限给了反而是多余攻击面。回退路径很直接把服务账号改回原值重启服务即可所以这一步的原值记录不能省。3.4 权限最小化与角色化管理规范 01-01-04 和 01-01-05 其实是同一件事的两面前者要求「取消业务账号不需要的服务器角色和数据库角色」后者要求「用角色来管理对象权限」。操作上就是三步——列出多余角色、移除、改由自定义角色承载。-- 查某个登录名当前挂了哪些服务器角色重点看 securityadmin / sysadmin / bulkadmin SELECT r.name AS role_name FROM sys.server_role_members AS rm JOIN sys.server_principals AS r ON r.principal_id rm.role_principal_id JOIN sys.server_principals AS m ON m.principal_id rm.member_principal_id WHERE m.name app_report; -- 移除不需要的服务器角色 ALTER SERVER ROLE [securityadmin] DROP MEMBER [app_report]; -- 库内同理先看库角色成员再移除多余的写权限 USE [BizDB]; SELECT r.name AS role_name FROM sys.database_role_members AS rm JOIN sys.database_principals AS r ON r.principal_id rm.role_principal_id JOIN sys.database_principals AS m ON m.principal_id rm.member_principal_id WHERE m.name app_report; ALTER ROLE [db_datawriter] DROP MEMBER [app_report];判断「多余」的标准是业务测试是否正常而不是「看起来不需要」。规范原文里判断依据写的就是「业务测试正常」四个字这四字背后意味着收紧权限只做减法、一次只收一档、每收一次跑一遍业务回归。最忌讳一次性把db_datareader、db_datawriter、db_executor全撤掉再慢慢加出了问题根本不知道是哪一档导致的。3.5 空密码与强口令整改规范 01-01-06 要求检查空密码特别是sa需要至少 10 位强口令。原文给的查询是Select name,Password from syslogins where password is null在旧版本上确实能查到。新版本password列不可读要用PWDCOMPARE来判断-- 找出所有空密码的 SQL 登录名PWDCOMPARE 第一个参数为空串返回 1 即为空密码 SELECT name, is_disabled, is_policy_checked, is_expiration_checked FROM sys.sql_logins WHERE PWDCOMPARE(, password_hash) 1; -- 改口令同时打开密码策略 ALTER LOGIN [app_report] WITH PASSWORD 新的强口令 , CHECK_POLICY ON;sys.sql_logins只包含 SQL 认证登录名Windows 认证账号不需要这条检查因为口令由域控管。is_policy_checked和is_expiration_checked两列能直接看出哪些账号还在裸奔——没开策略的账号口令可以设成一位字符这条检查是必须补上的。改sa口令时注意如果有作业或链接服务器用sa连本机改完会一起失效这类依赖要在 2.4 那一步一并查出来。4. 日志配置与通信协议审计开关、协议收敛和加密账号那章做完实例的「谁能进来」就定了这一章解决的是「进来之后有没有记录」和「从哪条路进来」。规范里这部分的条目少但可操作面很窄配置项大多在图形界面或注册表里没有 SQL 语句那么直观也更容易配错。4.1 登录审计审计级别到底改的是哪个开关规范 02-01-01 要求启用日志记录记录账号、登录是否成功、登录时间和来源 IP。原文的操作方式是「打开数据库属性选择安全性把审计级别调整为全部身份验证调整为 SQL Server 和 Windows」。在 SSMS 里对应的是实例属性 → 安全性 → 登录审核四个选项分别对应「无」「仅失败」「仅成功」「成功和失败」。图形界面之外也可以走注册表写入的方式适合批量脚本-- 开启高级选项后才能改注册表扩展过程 EXEC sp_configure show advanced options, 1; RECONFIGURE; -- LoginAuditLevel0无1仅成功2仅失败3成功和失败 EXEC master.dbo.xp_instance_regwrite NHKEY_LOCAL_MACHINE, NSOFTWARE\Microsoft\MSSQLServer\MSSQLServer, NLoginAuditLevel, REG_DWORD, 3; -- 改完复查当前值 EXEC master.dbo.xp_instance_regread NHKEY_LOCAL_MACHINE, NSOFTWARE\Microsoft\MSSQLServer\MSSQLServer, NLoginAuditLevel;xp_instance_regwrite的第三个参数是注册表值名第四个REG_DWORD是数据类型第五个才是要写进去的值。命名实例的注册表路径不是MSSQLServer这一层而是Microsoft SQL Server\实例名路径写错会静默失败所以最后那次xp_instance_regread不能省它是唯一能确认写入成功的动作。审计级别设成 3 之后登录成功和失败都会写进错误日志代价是日志增长变快高并发短连接场景下 ERRORLOG 会涨得很快这一点在 4.2 里单独处理。4.2 日志落盘与保留别让审计记录自己滚没了登录审计记录在错误日志里而错误日志默认只保留 7 个文件6 个归档 1 个当前滚动一次最老的就没了。规范要求「记录内容包括用户登录使用的账号、登录是否成功、登录时间以及远程登录时用户使用的 IP 地址」这些字段确实都在但前提是日志还在。-- 查询最近的登录失败记录参数依次是日志序号、日志类型(1错误日志)、检索串 EXEC sp_readerrorlog 0, 1, N登录失败; EXEC sp_readerrorlog 0, 1, NLogin failed; -- 查看当前错误日志文件数量默认 6可按合规要求调大 EXEC xp_instance_regread NHKEY_LOCAL_MACHINE, NSOFTWARE\Microsoft\MSSQLServer\MSSQLServer, NNumErrorLogs;sp_readerrorlog的第一个参数是日志序号0 表示当前日志1 表示上一个归档。巡检脚本一般会从 0 扫到 6把失败记录汇总出来。NumErrorLogs默认值是 6按日切的话只覆盖一周如果合规要求保留 90 天要么把它调到 90要么在错误日志之外单独做归档——后者的常见做法是用 SQL Server 代理作业定时把 ERRORLOG 复制到归档目录再按日期命名。另外规范提到的「数据库操作记录」和「登录记录」不是一回事。登录审计只覆盖认证环节增删改这类操作要靠业务库自身的审计功能或触发器这部分原文没有展开实施时按各自的合规要求单独设计别以为开了登录审计就万事大吉。4.3 网络协议收敛只留 TCP/IP 之前先查客户端规范 03-01-01 要求「除去不必要的服务建议只使用 TCP/IP 协议禁用其他协议」。SQL Server 的网络协议包括 Shared Memory、Named Pipes、TCP/IP 和 VIA其中 Shared Memory 只在本机有效禁用它会让本机 SSMS 的连接行为发生变化所以我的做法是本机保留 Shared Memory跨机只留 TCP/IPNamed Pipes 和 VIA 一律禁用。操作在 SQL Server 配置管理器里SQL Server 网络配置 → 实例名的协议 → 右键每个协议选启用或禁用。禁用后必须重启 SQL Server 服务才生效重启就是一次业务中断所以这一步必须排进窗口。动手前先确认没有客户端依赖命名管道-- 看当前连接用的是哪个协议net_transport 列直接告诉你 SELECT session_id, net_transport, protocol_type, client_net_address, program_name FROM sys.dm_exec_connections WHERE net_transport IS NOT NULL;net_transport返回TCP、Named Pipes、Shared memory三种常见值。如果查出有远程客户端正在走Named Pipes说明某个连接串或别名里写死了管道名禁之前必须把那些客户端改到 TCP否则重启那一刻它们全部掉线且连不回来。这是我在真实环境里踩过的最典型的坑排在 5.1 条里详细说。4.4 TCP/IP 栈加固三个注册表键的原值与回退规范 03-01-02 列了三个注册表键都是 Windows 层面的网络栈加固不是 SQL Server 自己的配置注册表键均在HKLM\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters下建议值作用DisableIPSourceRouting2禁用源路由防源路由欺骗EnableICMPRedirect0关闭 ICMP 重定向防路由表被改写SynAttackProtect2加强 SYN FLOOD 攻击防护# 改之前先把原值导出回退时逐条写回 $path HKLM:\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters Get-ItemProperty -Path $path | Select-Object DisableIPSourceRouting, EnableICMPRedirect, SynAttackProtect # 写入加固值类型统一为 DWord Set-ItemProperty -Path $path -Name DisableIPSourceRouting -Value 2 -Type DWord Set-ItemProperty -Path $path -Name EnableICMPRedirect -Value 0 -Type DWord Set-ItemProperty -Path $path -Name SynAttackProtect -Value 2 -Type DWord第一条命令输出的是原值必须抄到 2.3 的回退包里。Set-ItemProperty的-Type DWord不能省写成字符串类型某些系统上不生效。这三个键属于系统级网络参数改完不需要重启 SQL Server但部分系统要重启网络适配器或整机才彻底生效所以要和维护窗口一起安排。注意一点在较新的 Windows 版本上这三个键的默认值和生效方式已有变化有的键即使写进去也不再产生旧版本那样的效果。规范给的是一套通用基线落到具体机器上以「改完能验证、出问题能回退」为准别把它当成必须逐字命中的硬指标。4.5 强制协议加密证书不对就是全线连不上规范 03-01-04 要求「使用通讯协议加密」原文的操作是启动服务器网络配置工具把常规设置改成「强制协议加密」。这个开关打开之后客户端和服务器之间的所有流量都走 TLS但前提是实例上装了一张能被客户端信任的证书。操作路径是SQL Server 配置管理器 → SQL Server 网络配置 → 实例的协议 → 右键 TCP/IP 属性 → 标志页 → 强制加密设为「是」然后重启服务。证书本身要提前导入到「本地计算机 → 个人」证书存储并且主题名称CN必须和客户端连接时使用的主机名一致。-- 查看实例当前使用的加密证书信息encrypt_option 为 TRUE 表示连接已加密 SELECT session_id, encrypt_option, net_transport, client_net_address FROM sys.dm_exec_connections; -- 确认加密用的是哪张证书 SELECT name, issuer_name, expiry_date, thumbprint FROM sys.certificates WHERE name 所选证书的名称;encrypt_option返回TRUE才说明连接真正加密了只开开关不装证书SQL Server 会自己生成一张自签证书客户端不信任它就报证书链错误。这条在所有加固条目里回退成本最高一旦客户端全量报错只能把「强制加密」改回「否」并重启服务等于又一次中断。所以我的做法是先在一台测试实例上把证书链跑通再推到生产。5. 常见问题与排查加固后连不上、作业失败怎么救加固过程中出事绝大多数不是命令写错而是「改的东西影响了没在清单上的依赖」。下面五条是我在不同环境里真实遇到过的按「现象 → 原因 → 解决」记下来碰到类似症状可以直接对号。5.1 现象应用突然连不上报登录失败或超时原因协议收敛时禁用了 Named Pipes而某个客户端连接串或 SQL Server 别名里写死了np:前缀走的是命名管道。服务重启后这条路径直接消失客户端表现是连接超时日志里未必有明确报错。解决先查客户端侧配置把别名和连接串统一改成tcp:主机名,端口。如果改不了第三方老系统临时把 Named Pipes 重新启用并重启服务恢复到可用状态后再推改造。事后补一条前置检查用sys.dm_exec_connections按net_transport分组统计一遍确认没有远程的命名管道连接再动协议开关。5.2 现象备份作业和代理作业在服务账号降权后集体失败原因服务账号从 Administrators 或 Users 组移除后对数据目录、备份目录、日志目录的 NTFS 权限一并丢失。SQL Server 服务本身能起来它对实例目录有权限但备份作业要往另一个盘写文件那里没有新账号的写权限作业报「拒绝访问」。解决给新服务账号单独授予三个目录的修改权限不要整组加回 Users 组那就白降权了。目录清单是数据文件目录、日志文件目录、备份目录加上sp_readerrorlog用到的错误日志目录。授权后用一条BACKUP DATABASE ... TO DISK手工验证一次比看作业历史快。5.3 现象删掉 xp_cmdshell 之后第二天某个老接口挂了原因应用侧依赖xp_cmdshell做文件搬运或调外部程序调用点不在数据库模块里sys.sql_modules查不到2.4 那一步漏掉了。解决先恢复可用再谈替代。xp_cmdshell属于内置扩展过程新版不能再靠sp_addextendedproc加回来而是用配置项控制-- 恢复 xp_cmdshell先开高级选项再打开开关 EXEC sp_configure show advanced options, 1; RECONFIGURE; EXEC sp_configure xp_cmdshell, 1; RECONFIGURE;恢复之后按规范原意处理能改造成作业或外部程序调度的改造成本一次付清确实改不了的至少限制调用账号只有sysadmin并把开关默认关掉、只在执行窗口打开。sp_OACreate这一组同理sp_configure Ole Automation Procedures才是总开关单删扩展过程在新版本上不一定有效。5.4 现象打开强制加密后客户端报证书链错误或直接超时原因三种可能——实例上没有导入证书用的是自签证书导入的证书 CN 和客户端连接的主机名不一致客户端机器不信任签发该证书的根 CA。解决按顺序排查。先在服务端查sys.dm_exec_connections的encrypt_option确认加密是否真的生效再核对证书 CN 和连接串里的主机名是否逐字相同用 IP 连而证书是域名签发的一样会失败最后在客户端用工具验证证书链把根 CA 导入到「受信任的根证书颁发机构」。实在来不及先关掉强制加密保业务证书改造单独立项。5.5 现象审计级别设成「全部」ERRORLOG 里却查不到登录记录原因三种情况——改的是注册表但没重启服务值没生效sp_readerrorlog查的是当前日志记录已经滚动到归档文件里查询用的检索串和实际日志语言不匹配中文环境下写Login failed是搜不到的。解决先用xp_instance_regread复查LoginAuditLevel的实际值确认是 3再用sp_readerrorlog从 0 扫到 6把归档日志一起搜检索串中英文各试一次。这三步走完还查不到就手工制造一次失败登录用错误口令连一个测试账号立刻查当前日志能查到说明审计是好的之前只是日志滚掉了。6. 验收把加固结果逐条对回规范编号改完不等于生效生效不等于业务正常。我习惯在收尾时跑一遍固定脚本把规范编号和查询结果一一对上输出一张带结论的表谁来看都能判断这次加固到底做没做。规范编号验收动作期望结果01-01-01查sys.server_principals与业务账号对应关系每个使用者有独立登录名无共享账号01-01-02查is_disabled与last_login_time无效账号已禁用观察期后已删除01-01-03PowerShell 查服务StartName服务账号不在 Administrators 组非系统内置账号01-01-04查服务器角色与库角色成员业务账号只保留必需角色01-01-05查自定义角色与成员对象权限挂在角色上成员关系可追溯01-01-06PWDCOMPARE(, password_hash)返回 0 行sa口令 10 位以上02-01-01制造一次失败登录后查错误日志账号、时间、来源 IP 均被记录03-01-01查sys.dm_exec_connections的net_transport远程连接全部为 TCP03-01-02读三个 TCP/IP 注册表键值为 2 / 0 / 2原值已归档03-01-04查encrypt_option返回 TRUE证书 CN 与主机名一致04-01-01查sys.extended_procedures与sys.configurations危险过程已删除或对应开关已关闭04-01-02SELECT VERSION比对补丁级别补丁为当前可用的最新级别验收脚本可以写成一段可直接执行的 T-SQL输出 PASS/FAIL 两列-- 验收空密码账号数量期望 0 SELECT 01-01-06 空密码检查 AS item, CASE WHEN COUNT(*) 0 THEN PASS ELSE FAIL END AS result, COUNT(*) AS detail FROM sys.sql_logins WHERE PWDCOMPARE(, password_hash) 1; -- 验收远程命名管道连接数期望 0 SELECT 03-01-01 协议收敛 AS item, CASE WHEN COUNT(*) 0 THEN PASS ELSE FAIL END AS result, COUNT(*) AS detail FROM sys.dm_exec_connections WHERE net_transport Named Pipes AND client_net_address local machine; -- 验收高危扩展过程是否存在期望存在的数量为 0 SELECT 04-01-01 危险过程 AS item, CASE WHEN COUNT(*) 0 THEN PASS ELSE FAIL END AS result, COUNT(*) AS detail FROM sys.extended_procedures WHERE name IN (xp_cmdshell, sp_OACreate, xp_regwrite, xp_dirtree);三段查询分别对应账号、协议、存储过程三条线detail列给出具体数量result列直接给结论。这套脚本我一般会存成一个 .sql 文件放在运维仓库里每次加固前后各跑一次前后对比就是一份完整的变更记录。登录审计的验收要单独做因为它是唯一需要「主动制造一次失败」的项目用一个不存在的账号连一次库然后立刻执行EXEC sp_readerrorlog 0, 1, N登录失败能查到刚发生的那条记录才算通过。这一步别嫌麻烦审计开关是最容易出现「以为开了其实没开」的配置。最后说个习惯那次报表作业全线失败之后我每次做加固都会先把 2.3 的四样东西备齐再按 2.4 查一遍依赖然后才动第一条配置。规范里的编号和回退方案是给人看的真正能救命的是你手上那份原值清单和系统库备份。这份资源的价值不在条目多全而在于每条都写了实施风险和回退路径——照着做的时候把回退那一栏当成必读项而不是可选项能少走很多弯路。希望帮到你。本文还有配套的精品资源点击获取

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑