简介:KB5004442 安全更新配套解读文档,面向 OPC Classic 用户、系统管理员及工业自动化运维人员。内容围绕 CVE-2021-26414 漏洞展开,系统说明微软 DCOM Server 安全功能旁路问题的由来,以及 2021 年 6 月、2022 年 6 月、2023 年 3 月三个阶段强制启用新安全机制的时间表。文档重点分析此次更新对 OPC Classic 客户端和服务器的不同影响:客户端需通过 CoInitializeSecurity 设置数据包完整性身份验证,服务器则依赖 DCOMCNFG 权限配置,并给出测试、缓解及迁移建议。资源共 1 个 PDF 文件,约 398KB,内容简洁但覆盖了关键的注册表路径、默认身份验证级别调整步骤和受影响 Windows 版本清单,适合用于制定内部升级计划或排查 DCOM/OPC 连接故障。已有 459 人学习,对于需要提前应对 Microsoft DCOM 强制安全策略的团队具有实用参考价值。
1. KB5004442 到底改了什么,为什么 OPC 客户端一夜之间全灰
半夜两点被值班电话叫醒:车间三台 SCADA 的画面全灰了,OPC DA 客户端报 0x800706BA,PLC 数据一条都上不来。查了一圈,罪魁祸首就是 KB5004442——微软为堵 CVE-2021-26414 这个 Windows DCOM Server 安全功能旁路漏洞而发布的更新。补丁本身没错,错在它默认掐掉了 DCOM 远程激活里「不安全」的那一类调用,而老一代 OPC DA(OPC DA 2.0/3.0)跨机通信恰好就建在这些不安全的调用上。这篇笔记写给维护 Windows 加 OPC 这条线的老伙计:先讲清楚补丁动了什么,再给出能直接照着做的评估、配置、验证路径,以及我踩过的坑。
2. DCOM 安全旁路为什么让 OPC 全线躺枪:CVE-2021-26414 的机制
2.1 DCOM 在 OPC DA 里干的是什么活
OPC DA 2.0 和 3.0 的跨机通信完全建立在 Microsoft 的 COM/DCOM 之上。客户端要读服务器上的数据,不是直接发一个 TCP 包就完事,而是先通过 RPC 的 Endpoint Mapper(135/TCP)找到目标机器上的 OPC Server 组件,再让远程的 RPCSS 服务按 CLSID 把 OPC Server 进程拉起来,然后拿一个叫 OXID 的引用标识符建立 DCOM 通道,最后才能调接口。
这一串动作里,最容易被打穿的就是「远程激活」这一步:客户端只需要知道目标机器的 CLSID 或 ProgID,再带上一点点参数,就能让对方的 COM 子系统启动一个进程。过去几十年,许多工业软件为了省事,把 DCOM 的默认身份验证级别设在 None,默认模拟级别设在 Anonymous。平时这么干没问题,因为内网里没人天天拿 RPC 扫描器对着工控机打,但补丁一出,这类配置就变成了最容易悲剧的一批:你连身份验证都没有,凭什么让远程机器帮你启动进程。
2.2 CVE-2021-26414 绕过的是哪一层安全
CVE-2021-26414 的官方定性是「Windows DCOM Server 安全功能旁路」。这里的旁路点不在业务接口,而在 DCOM 激活器对调用方身份的信任判断上。Windows 从 Vista 起引入完整性级别(Integrity Level):普通进程跑在 Medium,服务进程跑在 High/System,浏览器保护模式才是 Low。老版本 DCOM 在远程激活时,只检查调用方有没有权限,却没有严格校验这次激活请求的完整性级别和身份验证强度。
攻击者可以利用这一点,从一个低完整性进程发起 DCOM 远程激活,去激活本应由高权限服务承载的 COM 对象;如果这台机器上恰好有以 SYSTEM 身份运行的 OPC Server 或组态软件,攻击者相当于拿到一把没上锁的后门钥匙。微软对这个漏洞的风险评估不低,所以补丁的策略不是「提示你注意」,而是直接改变操作系统默认行为:远程 DCOM 激活请求必须满足两条硬性要求——调用方的完整性级别至少是 Medium,并且在激活时完成了足够强度的身份验证。
2.3 KB5004442 改了什么默认行为
KB5004442 的变更可以浓缩成一句话:DCOM 远程激活不再信任匿名和低完整性的调用请求。原来一套「身份验证级别 = 无、模拟级别 = 匿名」的默认配置,在补丁装上后会直接失效,调用方会在激活阶段被拒绝,客户端拿到的错误就是常见的 0x80070005(拒绝访问)或 0x800706BA(RPC 服务器不可用)。
更要命的是这个补丁不是孤立的。从 Windows 10 1809 / Windows Server 2019 开始,它伴随着 2021 年 6 月的月度累积更新默认进入系统,之后微软又通过配套更新(比如后续的 DCOM 强制更新 KB5004605)把「默认开、可关」进一步变成「强制开、不可全局关」。所以你现在去给一台攒了两年补丁的旧机器装更新,OPC 组态大概率当场翻车,而且不是简单重启能救回来的。
3. 部署前先看清家底:补丁状态、OPC 组件与最小验证环境
3.1 三步确认 KB5004442 是否已进系统
第一步不是改配置,而是先确认目标机器到底处于什么状态。在客户端和服务端各跑一遍下面的命令:
# 检查 KB5004442 是否在系统补丁列表里 Get-HotFix -Id KB5004442 | Select-Object HotFixID, InstalledOn, Description如果系统装的是后来滚进来的累积更新,KB5004442 不一定单独列出,但它的行为已经包含在系统里。更稳妥的办法是直接查 DCOM 兼容性注册表键:
# 读取 DCOM AppCompat 键,确认补丁行为是否已生效 $path = 'HKLM:\SOFTWARE\Microsoft\Ole\AppCompat' Get-ItemProperty -Path $path | Select-Object RequireIntegrityActivateAuthenticationLevel, AllowInsecureRemoteActivation这里两个键的解释要记牢:RequireIntegrityActivateAuthenticationLevel为 1 表示强制完整性级别检查,0 表示放低要求;AllowInsecureRemoteActivation为 0 表示禁止不安全的远程激活,1 表示允许。键不存在时,系统按当前补丁版本的默认行为处理,老版本补丁默认开检查,新版本补丁则可能连键都锁死。看到RequireIntegrityActivateAuthenticationLevel = 1时,基本可以断定这台机器已经把 DCOM 安全门关上了。
3.2 盘点 OPC Server 与 Client 的 DCOM 配置清单
在动手之前,把现场的 OPC 资产简单列个清单,比直接改注册表靠谱得多。我一般会按这四类信息归档:
- OPC Server 软件及版本:Kepware、Matrikon OPC Simulation、西门子 Simatic Net OPC 等,重点记版本号和位数(32 位还是 64 位)。
- OPC 组件 CLSID 或 ProgID:在注册表
HKLM\SOFTWARE\Classes\CLSID下按名称筛选,或者用 OleView .NET 打开组件列表。 - 运行账户:OPC Server 是作为 Windows 服务跑,还是作为某个用户的交互进程跑;服务登录身份是 LocalSystem、本地账户还是域账户。
- 客户端与服务器关系:同一台机器、同一域、不同域、还是工作组;客户端账户在服务器上有没有本地登录权限。
大部分现场翻车案例里,DCOM 配置早被人忘干净了。用 OleView .NET 或注册表导出把 CLSID、AppID、LaunchPermission、AccessPermission 拍个快照存下来,至少不会改乱了回不去。
3.3 一条命令验证远程 DCOM 激活是否被拦
不用等 SCADA 报警,自己就能先验证一台机器会不会被补丁卡死。在 OPC 客户端机器上执行下面的 PowerShell:
# 尝试远程激活 OPC Server 的 COM 对象 $serverHost = "192.168.10.50" $progId = "Kepware.OPC.Server" $type = [Type]::GetTypeFromProgID($progId, $serverHost) $opcObj = [Activator]::CreateInstance($type)这段代码先通过GetTypeFromProgID向远程机器发起组件查询,再用CreateInstance真正触发远程激活。如果顺利返回一个对象,说明 DCOM 激活没被拦;如果抛出 0x80070005、0x800706BA 或 0x800706BE,说明补丁已经把这台机器的远程激活堵死了。注意,这条命令的进程位数必须和测试组件匹配:32 位 OPC 组件要放在 32 位 PowerShell 里测,否则会出现「明明装了组件却找不到 ProgID」的假象。
3.4 快速判断影响面:一张表对号入座
影响面判断可以直接套下面这张表,不用逐台试:
| 现场条件 | 补丁安装后的预期表现 | 处理优先级 |
|---|---|---|
| OPC Server 和 Client 在同一台机器 | 一般不受影响,除非本机进程也走匿名激活 | 低 |
| 同一域、账户有 DCOM 权限、验证级别 Connect | 基本正常 | 低 |
| 同一域、默认验证级别 None | 大概率 0x80070005 | 高 |
| 工作组、跨网段、无信任关系 | 几乎必挂 | 最高 |
| 西门子 Simatic Net 老版本 OPC 服务 | 常见 0x800706BA | 高 |
4. 兼容与加固的落地配置:身份验证级别、注册表开关、端口与防火墙
4.1 首选方案:把 OPC 的 DCOM 身份验证级别调到 Connect
大多数老 OPC 现场不需要走极端方案,把 DCOM 的身份验证级别从「无」提到「连接」,就能同时满足补丁要求和 OPC 业务。打开组件服务管理单元:
Win + R 输入 dcomcnfg 进入 组件服务 -> 计算机 -> 我的电脑 -> 属性 切换到「默认属性」页 将「默认身份验证级别」改为「连接」 将「默认模拟级别」改为「标识」这个操作在 OPC Server 和 OPC 客户端两台机器上都要做。注意,老 OPC 客户端有时会在自己的配置文件里单独指定身份验证级别,那就要以配置文件为准;如果客户端写死了 None,光改 dcomcnfg 的默认值不生效,需要去查客户端软件的连接设置。改完后重启 OPC Server 服务,再用 3.3 的命令重新测一遍激活。
4.2 KB5004442 的官方兼容开关:两个 AppCompat 注册表键
如果调身份验证级别之后仍然被拦,说明目标机器上的 DCOM 安全门已经严格到不认老客户端的程度。这时可以用微软为这个补丁专门留的兼容开关,按机器维度放开限制:
# 关闭 DCOM 完整性级别强制检查(仅在兼容性测试阶段使用) $path = 'HKLM:\SOFTWARE\Microsoft\Ole\AppCompat' New-Item -Path $path -Force | Out-Null Set-ItemProperty -Path $path -Name 'RequireIntegrityActivateAuthenticationLevel' -Value 0 -Type DWord # 允许不安全的 DCOM 远程激活(明确知道风险时短期使用) Set-ItemProperty -Path $path -Name 'AllowInsecureRemoteActivation' -Value 1 -Type DWord这两个键的作用边界不一样:第一个管的是「激活者完整性级别不够时放不放行」,第二个管的是「匿名或低身份验证调用能不能远程激活」。修改后需要重启机器,或者重启 RpcSs 服务让 RPCSS 重新读配置。我一般只在测试环境用这两个开关,生产环境上用它等于把补丁的安全收益剪掉一大半,不建议当长期方案。
4.3 只给特定 OPC 应用开例外,别全局放开
全局放开两个键,虽然省事,但也把整台机器的 DCOM 防线全拆了。更稳的做法是只针对出问题的那个 OPC 组件开例外。在 dcomcnfg 里定位到具体组件,进入属性页,逐个核对三点:
- 「常规」页里的身份验证级别改为「连接」。
- 「安全」页的启动和激活权限、访问权限里,显式加上运行 OPC 客户端的账户。
- 「标识」页确认组件以交互用户还是指定用户运行,避免 SYSTEM 身份引起额外权限校验。
如果组件是 32 位而当前打开的是 64 位 dcomcnfg,列表里会看不到这个组件。此时要用 32 位版本的组件服务管理单元:
运行 mmc comexp.msc /32这条命令打开的界面显示的是 32 位 COM 组件注册表视图,西门子老 OPC、Kepware 老版本、以及各种国产组态软件的 DCOM 组件多半都在这里。找不到组件属性能不能改,十有八九就是位数不对。
4.4 固定 RPC 动态端口并放行防火墙
DCOM 本身除了 135 端口外,真正的数据传输走的是动态 RPC 端口。补丁装完后很多现场顺手加固了防火墙,结果把动态端口全挡了,症状就是激活能通、数据报错。建议把动态端口范围收敛到一个可控区间,再放行防火墙:
# 把 DCOM 动态端口范围限制到 40000-41000 $rpcPath = 'HKLM:\SOFTWARE\Microsoft\Rpc\Internet' Set-ItemProperty -Path $rpcPath -Name 'Ports' -Value '40000-41000' -Type String Set-ItemProperty -Path $rpcPath -Name 'PortsInternetAvailable' -Value 'Y' -Type String Restart-Service RpcSs -Force然后放行对应的入站规则:
# 放行 RPC Endpoint Mapper 和动态端口范围 New-NetFirewallRule -DisplayName 'DCOM-RPC-TCP-135' -Direction Inbound -Protocol TCP -LocalPort 135 -Action Allow New-NetFirewallRule -DisplayName 'DCOM-RPC-Dynamic' -Direction Inbound -Protocol TCP -LocalPort 40000-41000 -Action Allow注意Restart-Service RpcSs -Force会重启 RPC 服务,所有依赖 DCOM 的进程连接会被打断,OPC Server 服务需要一并重启。端口范围不要拍脑袋选太窄,50 个端口以下在并发高时容易出现端口枯竭。
5. KB5004442 落地后最常踩的 5 个坑:现象、原因、解决
5.1 所有 OPC 客户端连不上,统一报 0x80070005
现象:补丁安装后的第二天,所有客户端读取失败,系统日志里大量 DCOM 10016 事件。
原因:OPC Server 和客户端的 DCOM 默认身份验证级别为「无」,补丁直接把这种调用扔进拒绝列表。
解决:按 4.1 把两台机器的默认身份验证级别改为「连接」,默认模拟级别改为「标识」,重启 OPC Server 服务后验证。如果客户端软件写死了自己的验证级别,还要在客户端配置里同步改。这条能覆盖八成现场。
5.2 注册表开关设了 1 仍然不生效
现象:按要求把AllowInsecureRemoteActivation设成 1,重启后还是报拒绝访问。
原因:两种情况。一是注册表视图写错了,64 位系统里运行的是 32 位 OPC 组件,真实配置在HKLM\SOFTWARE\Wow6432Node\Microsoft\Ole\AppCompat下;二是系统装了后续强制更新,全局兼容开关已被锁定。
解决:先在 32 位视图下补设同名键;如果仍然无效,用mmc comexp.msc /32打开 32 位组件服务,对具体组件做应用级例外,不要和系统策略硬顶。
5.3 同域正常、工作组环境全军覆没
现象:两台机器在域内测试没问题,搬进车间改成工作组 IP 直连,OPC 死活连不上。
原因:DCOM 在工作组环境下的身份验证依赖本机账户和 NTLM 校验。客户端向服务器发起激活时,服务器要验证客户端身份,但两边没有信任关系,匿名路径又被补丁堵死,于是直接拒绝。
解决:短期办法是在服务器上创建与客户端同名的本地账户并设置相同密码,同时把该账户加入 Distributed COM Users 组;服务器端 DCOM 权限里显式放行该账户。长期建议是尽快把通信迁移到 OPC UA 或加 UA 网关,DCOM 在工作组环境下的坑远不止这一个。
5.4 OPC Client 能激活,但订阅数据回调断流
现象:远程激活成功,OPC 能读到一次状态,但数据订阅一推就断,客户端日志里出现 RPC 连接中断。
原因:DCOM 回调是服务器反向连接客户端。补丁后服务器反向激活客户端时同样要过安全校验,客户端这边如果没开防火墙动态端口,回调包进不来。
解决:在客户端机器上也放行 135 和动态 RPC 端口范围,并确认客户端进程的 DCOM 身份验证级别不低于 Connect。很多人只配服务端,忘了回调方向是反的,这条最容易漏。
5.5 dcomcnfg 里找不到老组态软件的 DCOM 组件
现象:想在组件服务里改权限,搜遍了列表看不到现场那套 OPC Server。
原因:老组态软件多半是 32 位组件,注册在 Wow6432Node 视图下,64 位 dcomcnfg 不显示。
解决:使用mmc comexp.msc /32打开;命令行里直接跑C:\Windows\SysWOW64\dcomcnfg.exe也可以。配置成功后,不要再用 64 位界面复核,否则又找不到,容易误判没生效。
6. 验证生效与就近迁移 OPC UA:安全日志、测试脚本与过渡路径
6.1 用事件日志验证补丁行为是否按预期工作
改完配置后,先看系统事件日志里的 DCOM 来源错误,确认不是靠猜:
# 拉取最近 200 条 DCOM 相关错误事件 Get-WinEvent -LogName System -MaxEvents 200 | Where-Object { $_.ProviderName -match 'DCOM' -and $_.LevelDisplayName -eq '错误' } | Select-Object TimeCreated, Id, Message | Format-List如果现场已经清零,说明激活和回调都通了。如果仍有 10016,事件消息里会写明是哪个 CLSID 和 AppID 被拒,直接拿这个 ID 去 4.3 里定位组件做例外。外加一条保险:在客户端机器上执行 3.3 的激活测试脚本,能正常返回对象,才算真正闭环。
6.2 给老 OPC DA 一个过渡方案:UA 网关与隧道
如果上面这些步骤做完,还是有个别老软件不配合,我不建议再和注册表死磕,直接给它配一个 UA 网关或 DCOM 隧道组件,让老 OPC DA 的 DCOM 流量封装进一条可控通道。这样 Windows 更新照打、安全策略照开,老组件只暴露给网关进程,对外不再走易受攻击的匿名 DCOM。迁移路径上有一个对比可以帮你判断投入方向:
| 维度 | 老 OPC DA 走 DCOM | 过渡:UA 网关/隧道 | 标准:OPC UA 直连 |
|---|---|---|---|
| 协议依赖 | 135 加动态 RPC 端口 | 封装后弱化 DCOM | 单端口 4840/TCP |
| 安全模型 | 依赖 Windows 账户与域 | 隧道内自行控制 | 证书双向认证 |
| 补丁影响 | 每次 DCOM 更新都可能翻车 | 影响面小 | 无直接影响 |
6.3 我的处理习惯与最终建议
我的习惯是:凡是涉及 Windows 补丁和 OPC 的生产环境,绝不一次全量推。先拿一台测试机装上 KB5004442,按上面的步骤跑通配置,再推到试点工位观察一周,最后才轮到全车间。每次改动前用 reg export 把Ole和Ole\AppCompat两个键备份出来,实在改坏了还能一键还原。这个补丁本身没有退路,你要做的不是绕过它,而是让老组件在新规则下体面地工作。希望帮到你。
本文还有配套的精品资源,点击获取