- 1. 写在前面的话
- 2. Modbus 到底缺了什么
- 3. 九个真实风险场景
- 4. 场景 1:Modbus TCP 直连公网——502 端口暴露在 Shodan 上
- 5. 场景 2:水厂/变电站 Modbus RTU 通过 4G DTU 透明传输上云
- 6. 场景 3:Modbus 转 MQTT 网关——MQTT 侧裸奔
- 7. 场景 4:工厂内网 Wi-Fi 上的 Modbus TCP 被嗅探
- 8. 场景 5:楼宇自控 BACnet-Modbus 网关配置页未设密码
- 9. 场景 6:风电场 SCADA 的 Modbus 控制指令被重放
- 10. 场景 7:OEM 设备默认配置被利用
- 11. 场景 8:寄存器写入攻击——修改设备参数
- 12. 场景 9:RS-485 总线物理接入——车间门没锁
- 13. 分层防御:从物理层到监控层的完整方案
- 14. 网络层:把 Modbus 关进笼子
- 15. 传输层:Modbus 加 TLS 的方案
- 16. 应用层:Modbus 安全代理/网关
- 17. 物理层:RS-485 总线的物理安全
- 18. 监控层:Modbus 流量异常检测
- 19. 合规性参考
- 20. 最低成本防护清单
- 21. 和 OPC UA 的安全模型对比
- 22. 写在后面
写在前面的话
Modbus 不安全。这不是什么新发现——1979 年 Modicon 设计这个协议的时候,连互联网都没普及,更不会想到有一天 PLC 会通过 4G 模块直接暴露在公网上。那时候的威胁模型是「电缆会不会被老鼠咬断」,不是「有没有人在 502 端口上做中间人攻击」。
但这不代表 Modbus 不能用。一个协议的问题和工程现场的问题是两回事。在机柜里、在被隔离的控制网上、在一对一物理连接的 RS-485 总线上,Modbus 明文的缺点几乎不构成威胁。问题出在什么时候?出在你把那根 RS-485 线接上一个 4G DTU,然后 DTU 配了个公网 IP,然后默认密码还没改。
这篇文章不讲安全理论,讲九个你我都可能遇到的情况——不是「如果」而是「已经发生过」。然后我们讨论在不换设备、不推翻现有架构的前提下,怎么把风险降到一个可接受的水平。
Modbus 到底缺了什么
先搞清楚 Modbus 缺失的到底是什么。不是「不安全」三个字就能概括的。
**没有认证机制。** Modbus TCP 的 MBAP 头里有个 Unit ID 字段,1 字节。这玩意儿是设备地址,不是身份凭证。任何能建立 TCP 连接到 502 端口的人,都可以发送功能码 0x03 读保持寄存器、功能码 0x06 写单个寄存器。试试看:telnet 过去发 `x00x01x00x00x00x06x01x03x00x00x00x01` ——只要设备在线,它就会返回寄存器数据。不需要密码,不需要 token,不需要任何形式的身份验证。
拿功能码 0x05 写单个线圈来说。这一帧只有 12 字节:
| TX ID | Proto | Len | UID | FC | Coil Addr | Value |
|---------|-------|------|-----|-----|-----------|----------|
| 00 01 | 00 00 | 00 06| 01 | 05 | 00 01 | FF 00 |
这个帧的意思是:把设备 01 的线圈地址 0001 置为 ON。如果你是一个合法的 SCADA 客户端,这没问题。如果你是一个连上 502 端口的陌生人,这也是有效的。设备不会区别对待。
**没有加密。** TCP 载荷里的每一个字节都是明文。Wireshark 用 `modbus` 过滤器可以直接看到事务 ID、功能码、寄存器地址、数据值。抓一包 Modbus TCP 流量等于拿到整套寄存器映射表。一个有心人看你工厂的 Modbus 流量五分钟,能画出所有设备的寄存器图。
**CRC 验不了篡改。** Modbus RTU 的 CRC-16 和 Modbus TCP 依赖的 TCP 校验和,设计目的都是检测物理传输层的比特错误——线缆噪声、电磁干扰导致的数据翻转。它们不是密码学哈希,不能防刻意篡改。攻击者截获一帧,改寄存器值,重新计算 CRC,转发出去,从站无法区分这一帧是不是被改过。
看一下攻击流:
原始帧 (主站→从站): 01 06 00 01 17 70 D8 0B (写保持寄存器地址0001=6000, 对应50Hz)
截获→篡改后帧: 01 06 00 01 02 58 C9 C3 (改成600, 对应5Hz)
CRC 变了,但攻击者也算得出来。从站收到后照样执行。变频器上限频率从 50Hz 变成了 5Hz——电机没烧,但泵不出水了。
**没有防重放。** Modbus 没有时间戳、没有序列号保护(MBAP 里的事务 ID 只是用来匹配请求与响应,不是安全序号)。同一帧可以无限重放。上个月你给风机发了停机指令,攻击者录下来,下个月再发一次——解码完全一样,设备照样停。
九个真实风险场景
不是说理论上的漏洞,是下面这些事情已经在不同现场发生过。有些是我自己碰到的,有些是同行聊起的,有些是公开报告里的。
场景 1:Modbus TCP 直连公网——502 端口暴露在 Shodan 上
Shodan 上搜 `port:502`,结果数一直在涨。两三年前公开数据大概六七千台,现在早就过万了。这些设备里有 PLC、RTU、网关、智能电表,有的跑在数据中心,有的挂在水厂 SCADA 的主干网上。Shodan 还会抓取设备返回的 Modbus 响应,直接显示设备型号、固件版本。
什么都不用破解。你把设备 IP 配成公网地址,502 端口没做任何 ACL——这就跟把车间大门开着、设备操作面板对着马路一样。
nmap 扫一下更直观:
nmap -p 502 --script modbus-discover <target_ip>
这个 NSE 脚本会尝试读取设备信息。如果设备响应了 0x11(报告从站 ID)或 0x2B(设备识别),它直接告诉你制造商、产品代码、固件版本。零门槛。
场景 2:水厂/变电站 Modbus RTU 通过 4G DTU 透明传输上云
现场用的是 RS-485 跑 Modbus RTU,几十台仪表挂在总线上。为了远程监控,加了个 4G DTU,配置成透明传输模式——DTU 把串口数据打包成 TCP 包发到云端服务器。公网 IP,端口 8899(不是 502,但差别不大)。
问题来了:DTU 和云服务器之间的链路是明文 TCP。任何能在这段链路做 MITM(中间人)的人——不一定是国家级攻击者,可能是运营商内部人员、4G 信号劫持设备、或者同基站下的其他设备利用 LTE 网络漏洞——都可以:
1. 监听所有 Modbus RTU 流量,拿到完整的寄存器映射和实时数据 2. 注入伪造的写指令(功能码 0x06 或 0x10),修改设备参数 3. 甚至向从站发送广播指令(地址 0x00),同时控制总线上所有设备
去年有个水厂的案例:攻击者通过公开的云平台 IP 连上了 DTU 的后台管理端口(默认密码 admin/admin),直接看到整个泵站的控制界面。万幸只是看了,没操作。
场景 3:Modbus 转 MQTT 网关——MQTT 侧裸奔
这种架构现在很常见:Modbus RTU 设备 → 网关做协议转换 → MQTT Broker(云端或本地)→ 上层应用消费。
网关把寄存器数据映射成 MQTT Topic,比如 `/plant1/pump1/pressure` → 保持寄存器 40001 的值。这个设计本身没问题——MQTT 的发布/订阅模型确实比 Modbus 轮询更适合云端场景。
问题出在 MQTT 侧:很多部署没开 TLS,Broker 不需要客户端证书认证,Topic 没有 ACL。攻击者只要知道 Broker 地址和端口(通常 1883,明文 MQTT 默认端口),用 `mosquitto_sub` 就能订阅所有 Topic:
mosquitto_sub -h <broker_ip> -p 1883 -t "#" -v
`#` 是 MQTT 的多级通配符,订阅所有 Topic。几秒钟后,整个工厂的温度、压力、电表读数、设备状态全部到手。如果 Broker 还允许发布(很多网关的双向控制功能依赖这个),攻击者可以直接向控制 Topic 发送指令:
mosquitto_pub -h <broker_ip> -p 1883 -t "/plant1/pump1/control" -m "STOP"
场景 4:工厂内网 Wi-Fi 上的 Modbus TCP 被嗅探
不少工厂为了布线方便,把 Modbus TCP 设备和 SCADA 服务器挂在同一个 Wi-Fi 网络上。Wi-Fi 密码写在设备标签上,贴在机柜外面——防君子不防小人。
内部员工(或者访客、维保人员、离职员工留下的设备)连上这个 Wi-Fi 后,Modbus TCP 流量全是广播域内的明文。Wireshark 抓包:
过滤器: modbus && tcp.port == 502
抓个十分钟就能把所有设备的寄存器映射画出来。如果攻击者还想更进一步,ARP 欺骗把 SCADA 服务器的流量引到自己机器上,然后作为中间人转发——设备端的 Modbus 通信不会中断,SCADA 界面一切正常,后台的数据已经在被实时窃取。
场景 5:楼宇自控 BACnet-Modbus 网关配置页未设密码
楼宇自控系统里,BACnet 和 Modbus 经常会混在一个网关上。比如 Delta Controls、Siemens Desigo 的一些网关产品,既有 Modbus RTU 接口接仪表,又有 BACnet/IP 接口上 BMS。
这些网关通常会提供一个 Web 配置页面。默认情况下,很多集成商上线时只改 IP 地址、配置好寄存器映射,密码还是出厂默认——或者压根没设密码。Web 页面暴露了完整的寄存器映射表、设备地址、功能码配置、甚至在线调试功能——可以直接在里面发 Modbus 读写指令。
Shodan 上搜 `BACnet gateway` 或特定网关型号的产品页面,能找到不少这样的入口。进去了不只是看数据——能直接在 Web 界面上改暖通阀门开度、设空调温度设定值、启停冷水机组。
场景 6:风电场 SCADA 的 Modbus 控制指令被重放
风电场 SCADA 系统通常用 Modbus TCP 和风机 PLC 通信。控制指令包括启停、桨距角调整、偏航控制、功率限制等。
2015 年乌克兰电网攻击事件之后,大家对 OT 安全总算开始重视。但风场的情况比较特殊——很多风场建在偏远地区,远程运维依赖 VPN 或专线,运维人员流动性大,VPN 账号管理经常跟不上。
如果一条「紧急停机」Modbus 指令(功能码 0x05,写某一个线圈)在传输过程中被坏人截获——无论通过什么手段,可能是 VPN 客户端被控、可能是运维笔记本被植入木马、可能是内网横向移动——这个帧可以被保存下来。攻击者不需要理解 Modbus 协议细节,不需要知道寄存器映射,只需要几个月后在夜间重放这个帧。风机收到后就会执行停机。
重放不挑时间、不挑目标。录一次,发一百次。而 Modbus 协议原生没有任何机制能阻止这件事。
场景 7:OEM 设备默认配置被利用
OEM 设备厂商为了提高出货效率,所有的 PLC/RTU 用统一的从站地址(比如地址 01)、统一的功能码支持列表、甚至统一的寄存器映射。更糟糕的是,有些厂商在固件里写死了通信参数——没法改。
这在设备调试阶段很方便。但在实际部署以后,变成安全噩梦。
假设一个分布式光伏项目用了同一批逆变器,所有设备的从站地址都是 01,寄存器映射完全一样(40001=功率,40003=电压,40005=运行状态,40101=开关机控制)。攻击者攻破其中一台设备或者中间的网络节点,他等于拿到了所有设备的控制蓝图。别的设备不用重新侦察——寄存器映射完全是同一份。
场景 8:寄存器写入攻击——修改设备参数
这个场景最危险。Modbus 的保持寄存器不光存测量数据,还存设备参数。变频器上限频率、PID 参数、报警阈值、校准系数——都在寄存器里。能写寄存器的人就能改变设备的物理行为。
具体例子:
| 设备 | 寄存器地址 | 参数 | 正常值 | 恶意值 | 后果 |
|---|---|---|---|---|---|
| 变频器 | 40018 | 上限频率 | 5000 (=50Hz) | 500 (=5Hz) | 泵出水不足,产线停产 |
| 温控器 | 40005 | 目标温度 | 250 (=25.0℃) | 800 (=80.0℃) | 过温保护跳闸,或者反过来改低导致冻结 |
| 电表 | 40045 | 电流变比 | 100 | 1 | 电量数据偏差百倍,能耗核算崩盘 |
| PLC | 40001 | 运行模式 | 1 (运行) | 0 (停止) | 直接让 PLC 停止执行逻辑 |
不需要做什么复杂攻击。nmap 的 modbus-discover 脚本扫一遍拿到寄存器映射,然后 modbus-cli 或 pymodbus 直接往里写:
from pymodbus.client import ModbusTcpClient
client = ModbusTcpClient('192.168.1.100')
client.write_register(18, 500) # 把变频器上限频率改成5Hz
四行代码。不需要任何权限。变频器收到了就执行。
场景 9:RS-485 总线物理接入——车间门没锁
RS-485 总线的物理安全性几乎是零。总线上的所有设备共享一对差分信号线(A+/B-),任何人在总线的任何位置接上一个 USB-RS485 转换器,就能:
1. **被动监听**:把所有 RS-485 流量记录下来,离线分析 2. **主动注入**:伪装成主站或者从站发送指令 3. **总线干扰**:持续发送数据造成总线冲突,DDoS 整个网络
一个 USB-RS485 转换器淘宝十几块钱。一个机智的攻击者在夜班巡检时,趁人不注意把转换器藏在线槽里,加一个微型 4G 模块做远程接入。谁能发现?没有人会定期检查 RS-485 总线的电气特性。
关键是 RS-485 总线的设计本身就是多站共享介质,不需要交换机、不需要端口接入许可。物理上挂上去就是网络的一员。Modbus RTU 的从站地址只有 1-247,攻击者可以枚举所有地址,逐个探测设备类型。
分层防御:从物理层到监控层的完整方案
讲完九个场景之后,一个自然而然的结论是:不能靠单一手段解决 Modbus 安全问题。它的问题分布在协议栈的每一层,防护也得跟着分。
下面这些方案不是在讲理论——每一条都有对应的产品、开源工具或者配置方法。按自己的现场条件挑着用。
网络层:把 Modbus 关进笼子
**第一条铁律:Modbus 502 端口绝对不要直接暴露在公网上。** 这句话怎么强调都不过分。如果你的设备供应商跟你说「直接把 IP 配成公网的,我们远程维护方便」——换供应商。
具体操作:
**防火墙 ACL 白名单。** 不是黑名单,是白名单。502 端口只允许指定 IP(SCADA 服务器、数据采集网关)访问。Linux iptables 两行搞定:
iptables -A INPUT -p tcp --dport 502 -s 192.168.10.0/24 -j ACCEPT
iptables -A INPUT -p tcp --dport 502 -j DROP
如果你的设备 CPU 跑不动 iptables,用硬件防火墙(几百块的小型工业防火墙就行),或者至少在路由器/三层交换机上做 ACL。
**VLAN 隔离。** 把 Modbus 设备放在独立的 VLAN 里,和办公网络、Wi-Fi 网络、访客网络完全隔离。VLAN 间路由只放行 SCADA 服务器到 502 端口的流量,其他一概不路由。交换机端口上做 MAC 绑定,防止有人把设备拔了换自己的笔记本。
**VPN/IPsec 隧道。** 需要远程访问的场景,走 VPN 而不是把端口开到公网上。IPsec 或 WireGuard 都可以。OpenVPN 的配置不复杂:
# 服务端只允许 502 端口流量通过隧道
push "route 192.168.10.0 255.255.255.0"
这保证了 Modbus 流量始终在加密隧道里传输。即使攻击者拦截了 VPN 链路,TLS/AES 加密也会让他拿不到明文。
传输层:Modbus 加 TLS 的方案
提到 Modbus 加 TLS,得先说现状:**Modbus Organization 在 2018 年 10 月发布了 Modbus/TCP Security 规范**。核心变化:默认端口从 502 改为 802,TLS 1.2 强制,X.509v3 证书做身份认证,同时引入基于角色的访问控制(Role-Based Access Control,RBAC)。
规范定义了四个角色:
| 角色 ID | 角色名 | 权限 |
|---|---|---|
| 0 | Administrator | 全功能码、全寄存器、设备管理 |
| 1 | Operator | 读写所有寄存器,不能改配置 |
| 2 | Engineer | 调试诊断权限 |
| 3 | Observer | 只读数据,不能写 |
这彻底解决了 Modbus 无认证的问题——客户端必须持有有效证书才能建立 TLS 连接,证书中的角色字段决定了能执行哪些功能码。
但现实是,支持 802 端口的设备少得可怜。绝大多数存量设备只支持 502 明文。不换设备怎么加 TLS?
**stunnel 方案。** stunnel 是一个轻量的 TLS 代理,能把任意 TCP 连接封装到 TLS 隧道里。部署架构:
SCADA 客户端 → stunnel(本地127.0.0.1:1502) → TLS → stunnel(远程) → 设备(502)
stunnel 配置很短:
# 客户端 stunnel.conf
[modbus-client]
client = yes
accept = 127.0.0.1:1502
connect = 192.168.10.1:802
verifyChain = yes
CAfile = /etc/stunnel/ca.pem
cert = /etc/stunnel/client.pem
key = /etc/stunnel/client.key
# 服务端 stunnel.conf
[modbus-server]
client = no
accept = 802
connect = 127.0.0.1:502
cert = /etc/stunnel/server.pem
key = /etc/stunnel/server.key
CAfile = /etc/stunnel/ca.pem
verifyChain = yes
客户端软件连 `127.0.0.1:1502` 而不是直连设备的 502。中间的 TLS 加密对上层完全透明。stunnel 本身只有几百 KB,可以跑在嵌入式 Linux 网关、树莓派、甚至 OpenWrt 路由器上。
**注意:** stunnel 解决的是传输加密问题,不解决应用层认证问题。它保证了传输链路不被窃听和篡改,但一旦 TLS 隧道建好,Modbus 帧本身依然是明文——只是这个明文只在加密隧道和保护的内网之间传输。如果攻击者能进入内网并直接连设备的 502,stunnel 保护不了。
应用层:Modbus 安全代理/网关
如果你不能在每个设备端部署 stunnel,或者需要更细粒度的控制,在 Modbus 总线和上层应用之间加一个安全代理/网关是性价比最高的方案。
Moxa MGate 系列、Hilscher netTAP、Advantech ADAM-4570 这些工业网关都支持访问控制列表。你可以在网关上配置:
– 哪个 IP 可以访问哪些从站地址 – 允许哪些功能码通过 – 寄存器级读写控制——比如地址 40001-40050 只读,40051-40100 可读写 – 连接速率限制(防暴力轮询/DoS)
选型时看清楚:不是所有 Modbus 网关都支持安全策略。很多廉价网关只是做透传,ACL 功能在选型表里要找 `Access Control` 或 `Security Policy` 字段。
开源方案也不是没有。用 pymodbus 写一个代理也就几百行代码:
# 简化版 Modbus 安全代理逻辑
ALLOWED_FUNCTION_CODES = {0x03, 0x04, 0x06, 0x10} # 只允许这些功能码
READ_ONLY_REGISTERS = range(40001, 40051) # 这个地址段只读
def proxy_handler(request):
if request.function_code not in ALLOWED_FUNCTION_CODES:
return exception_response(request.function_code, 0x01) # 非法功能码
if request.function_code in {0x06, 0x10}:
for addr in request.addresses:
if addr in READ_ONLY_REGISTERS:
return exception_response(request.function_code, 0x02) # 非法数据地址
# 转发到实际设备
return forward_to_device(request)
这几行挡掉了场景 8 里大部分寄存器写入攻击。
物理层:RS-485 总线的物理安全
物理安全听起来「低级」,但九个场景里至少三个和物理接入有关。
最低成本也能做的几件事:
1. **机柜上锁。** 不只是一个简单的钥匙锁——用电子门禁,记录谁什么时候开了哪个机柜。异常时间(凌晨两三点)的机柜开门=物理安全事件。 2. **RS-485 总线用带屏蔽的双绞线走线槽。** 线槽加封条,拆开有痕迹。不是防不住,是让攻击者留下证据。 3. **USB 端口禁用。** 工厂里的工控机/HMI 不需要插 U 盘。BIOS 禁用 USB、Windows 组策略禁用可移动存储。有人插 USB-RS485 转换器,系统不识别。 4. **总线终端电阻加防拆传感器。** RS-485 总线两端各有一个 120Ω 终端电阻。如果一个电阻被移除(有人在线中间接了一个监听设备导致阻抗变化),总线的电气特性会变化——可以用总线分析仪检测。
花不了多少钱,但挡住 90% 的物理接入攻击足够了。
监控层:Modbus 流量异常检测
前面的所有措施都是「不让他进来」。但对「已经进来了」或者「合法用户做了不合法的事」的情况,你还需要检测能力。
Modbus 流量的异常特征很明确——正是因为协议简单,异常更容易识别:
**轮询周期突变。** SCADA 系统通常以固定周期轮询设备(比如每秒一次)。如果某个从站的请求频率突然从 1 次/秒变成 100 次/秒,大概率不是 SCADA 的行为。可能是有人在暴力扫描寄存器。
**非标准功能码出现。** 一个只用了 0x03(读保持寄存器)和 0x06(写单个寄存器)的系统,突然出现 0x08(诊断)或 0x2B(设备识别)请求——这是侦察行为的典型特征。
**非工作时间流量。** 工厂停产时段(比如晚上 11 点到早上 6 点),Modbus 总线上不应该有大量读写指令。如果有,报警。
**异常功能码组合。** 短时间内出现 0x05(写单个线圈)、0x06(写单个寄存器)、0x10(写多个寄存器)的密集组合,且目标地址跨越多个不相邻的区域——几乎可以确定是恶意操作。
开源工具方面:
# Zeek (原Bro) 有 Modbus 协议解析器
# 写一个检测脚本放在 Zeek 的策略目录
Wireshark + Modbus 插件可以用来做离线流量审计。把一天的总线流量抓下来,用 Wireshark 的 `Statistics` → `Protocol Hierarchy` → `Modbus` 看功能码分布。功能码 0x08 和 0x2B 的出现是红旗。
nmap 的 `modbus-discover` NSE 脚本应该周期性地从你自己的 SCADA 服务器运行,检查有没有新的 Modbus 设备出现在网络上:
nmap -p 502 --script modbus-discover 192.168.10.0/24
发现了不属于你的设备,事情就严重了。
合规性参考
不展开讲法规条文,只说对 Modbus 部署直接有影响的几条。
**IEC 62443-3-3** 定义了工业自动化和控制系统的七个基础要求(FR1-FR7)。其中 FR2(使用控制)要求对工业通信实施认证和授权,FR3(系统完整性)要求对通信数据进行完整性校验。明文 Modbus 直接不符合 FR2 和 FR3。加 stunnel/VPN 后可以满足密码学层面的要求。
**NERC CIP(北美电力可靠性标准)** 的 CIP-005 要求对电力系统电子安全边界(ESP)实施访问控制。这意味着如果你在美国电力行业用 Modbus 传输控制指令,502 端口必须在 ESP 内部或者通过 ESP 的加密隧道,不能裸奔。CIP-007 还要求系统打补丁和最小化端口,和 Modbus 设备的固件管理直接相关。
**中国等保 2.0(GB/T 22239-2019)** 对工控系统有专门的扩展要求。主要包括:控制网络和非控制网络之间实施边界防护和技术隔离;使用广域网进行控制指令传输时采用加密认证;工业控制系统内部根据业务划分安全域并实施隔离。用 Modbus 的设备如果在等保三级及以上的系统里,基本的网络隔离、通信加密、访问控制是硬性要求,没有可选余地。
这些合规要求不是摆设——审计的时候会查网络架构图、防火墙规则、抓包验证。拿 Modbus TCP 明文走公网通不过任何一项合规审计。
最低成本防护清单
如果你在一个中小工厂、预算有限、设备老旧不能换、也没有专职安全工程师,下面 5 条是你现在就能做的。**这 5 条挡住 90% 的攻击,不需要额外采购设备:**
1. **检查所有 502 端口是否可以从公网访问。** 到 https://www.shodan.io 搜你的公网 IP 段,或者在外部网络用 `nmap -p 502 <公网IP>` 扫一遍。发现暴露的,立刻关掉端口映射或者加 AC。 2. **Modbus 网关/DTU 改默认密码。** 不只是网关的 Web 管理页面——确认 DTU 的 AT 指令配置密码(如果支持)、MQTT Broker 的认证、VPN 的预共享密钥,全部改掉。 3. **把 Modbus 设备放在独立 VLAN,配置白名单 ACL。** 如果交换机不支持 VLAN,至少划一个独立的 IP 子网,路由器上做 ACL,只允许 SCADA 服务器 IP 访问 502。 4. **在 SCADA 服务器上跑一次 Wireshark 抓包审计。** 记录一小时的总线流量,检查有没有异常功能码(0x08, 0x2B)、有没有出现在不该在的设备地址。 5. **定期用 nmap 扫描 Modbus 网络。** 写个 cron 每周跑一次 `nmap -p 502 –script modbus-discover <子网>`,把输出 diff 一下。出现新设备=有人接了什么东西进去。
把上面 5 条落实了,再谈要不要上专用的 OT 安全平台、要不要做 SIEM 集成。大多数小工厂连第一条都没做。
和 OPC UA 的安全模型对比
聊 Modbus 安全绕不开 OPC UA。不是说谁替代谁,是搞清楚两者的安全模型差距,避免选型时做出离谱决策。
| 维度 | Modbus TCP (原生) | OPC UA |
|---|---|---|
| 认证 | 无 | X.509 证书、用户名/密码、Kerberos |
| 传输加密 | 无 | TLS 1.2/1.3 (UA-TCP) 或 HTTPS (UA-HTTPS) |
| 数据签名 | 无 | 每条消息可单独签名 (UA-SecureConversation) |
| 访问控制 | 无 | 会话级+节点级 ACL |
| 审计日志 | 依赖应用层 | 内置审计事件类型 |
| 协议复杂度 | 极简,12 字节帧 | 二进制编码,完整 OO 对象模型 |
OPC UA 把安全做进了协议栈,从传输层到应用层都有对应的安全机制。Modbus 把一切扔给了实现者。这不是 OPC UA 比 Modbus 「更好」——这是两种完全不同的设计哲学。OPC UA 的安全复杂度也是代价:TLS 握手、证书管理、信任链、CRL/OCSP 吊销检查——这些在嵌入式 Modbus 设备上是天方夜谭。STM32 跑 Modbus RTU 只需要一个 UART 和两三百行 C 代码,跑 OPC UA 需要 TLS 库、XML 解析器、至少几十 KB 的 RAM。
所以结论不是「大家都用 OPC UA」。是:如果你本来就在用 Modbus,别因为它不安全就推翻整个系统换成 OPC UA——加 stunnel、防火墙 ACL、安全代理的成本远低于换协议。如果你是新建系统、选型阶段、设备资源充足、需要面向 IT/OT 融合架构——OPC UA 天然的安全能力会让你在后期的合规和运维上省很多事。
写在后面
Modbus 的安全问题不是一个技术问题,是一个工程管理问题。协议本身没有安全能力,但你可以通过部署架构把它放到一个受保护的环境里。就像你不会把一台没有防火墙的服务器直接挂在公网上一样,你也不应该让 Modbus 设备直接面对不可信网络。
说到底,最危险的从来不是协议漏洞,而是有人觉得「我们这种小厂没人攻击」。攻击者不挑大厂小厂——自动化扫描工具一视同仁,502 端口开着就进来。
有问题再聊,或者你自己开 Wireshark 抓一包看看——大概率你会被惊到的。
发表回复