3. 安全模式(SecurityMode)详解:对比 None、Sign、SignAndEncrypt 三种模式的应用场景与性能开销
安全模式这东西,说白了就是决定你的 OPC UA 通信到底要穿几层防弹衣。我见过不少项目,上来就选 SignAndEncrypt,觉得越安全越好。结果呢?现场设备 CPU 跑满,通信延迟飙升,最后不得不降级。反过来,也有工厂裸奔用 None,被中间人攻击搞停产。
今天咱们就把这三种模式掰开揉碎,看看它们各自适合什么场景,代价又是什么。
3.1 三种模式的核心差异
先看一张对比表,心里有个底:
| 特性 | None | Sign | SignAndEncrypt |
|---|---|---|---|
| 身份验证 | 无 | 有(证书签名) | 有(证书签名) |
| 消息完整性 | 无 | 有(HMAC) | 有(HMAC) |
| 消息机密性 | 无 | 无 | 有(AES 加密) |
| 防重放攻击 | 无 | 有(序列号+时间戳) | 有(序列号+时间戳) |
| CPU 开销 | 极低 | 中等 | 高 |
| 网络带宽开销 | 极低 | 低(增加签名头) | 中(增加加密头+填充) |
嗯,这里要注意:Sign 和 SignAndEncrypt 都做了签名,所以都能防篡改和防重放。区别只在于数据是否加密。
3.2 None 模式:什么时候可以裸奔?
我个人习惯把 None 模式叫做「信任链模式」。它不提供任何安全保护,但也不是一无是处。
适用场景:
- 隔离网络内部通信:比如 PLC 和同一机柜内的工控机通信,物理上已经隔离了外部网络。
- 性能敏感的控制环路:伺服驱动器的实时位置反馈,延迟要求微秒级,加签名加密会破坏实时性。
- 调试阶段:开发时先用 None 排除安全层的干扰,等逻辑调通再上安全策略。
性能表现:
None 模式几乎不消耗额外 CPU。它只是在消息头里加一个 SecurityMode 字段标记为 None,没有签名计算,没有加密运算。我实测过,在树莓派级别的设备上,None 模式的消息吞吐量可以达到 SignAndEncrypt 的 3-5 倍。
3.3 Sign 模式:只签名不加密,够用吗?
Sign 模式是我个人最常用的模式。它保证消息是来自可信的客户端/服务器,并且没有被篡改过。但数据内容是明文传输的。
适用场景:
- 监控类数据采集:读取温度、压力、振动等过程值。这些数据本身不敏感,但必须确保来源可靠。
- 历史数据归档:数据需要保证完整性,不能被人为篡改,但归档后数据本身不保密。
- 中等性能要求的系统:CPU 资源有限,但又不能完全裸奔。
性能开销分析:
Sign 模式的核心开销在 HMAC 计算。以 AES-256 和 SHA-256 为例,签名一个 1KB 的消息大约需要 5-10 微秒(取决于硬件是否支持 AES-NI 指令集)。
// 伪代码:Sign 模式的消息处理流程
// 发送端
message = buildMessage(payload)
signature = HMAC_SHA256(message, sessionKey)
send(message + signature)
// 接收端
receivedMessage, receivedSignature = receive()
expectedSignature = HMAC_SHA256(receivedMessage, sessionKey)
if receivedSignature == expectedSignature:
process(receivedMessage)
else:
reject("签名验证失败")
这里有个坑:签名计算的时间是固定的,但验证时间可能因为消息长度不同而略有差异。我曾经在项目中遇到过一个问题:客户端用 Sign 模式发送大量小数据包,服务器端 CPU 被签名验证占满,导致其他任务饿死。后来加了消息合并,把多个小包合并成一个大数据包再签名,问题就解决了。
3.4 SignAndEncrypt 模式:全副武装的代价
SignAndEncrypt 是最高安全级别。它先加密再签名,既保证机密性又保证完整性。但代价也最大。
适用场景:
- 跨企业边界通信:比如两个公司之间的 OPC UA 连接,数据经过公共网络。
- 敏感数据写入:修改配方参数、设定值、报警阈值等,一旦被篡改可能造成安全事故。
- 合规要求:某些行业(如制药、核电)强制要求端到端加密。
性能开销分析:
SignAndEncrypt 的开销 = 签名开销 + 加密开销。加密比签名更耗 CPU,因为 AES 加密需要处理填充、IV 向量等。
| 消息大小 | None | Sign | SignAndEncrypt |
|---|---|---|---|
| 100 字节 | 0.2 μs | 8 μs | 15 μs |
| 1 KB | 0.5 μs | 12 μs | 28 μs |
| 10 KB | 2 μs | 35 μs | 120 μs |
| 100 KB | 15 μs | 280 μs | 1.1 ms |
你看,消息越大,加密的代价越明显。对于 100KB 的大数据包,SignAndEncrypt 比 None 慢了 70 多倍。所以,如果你要传输大量历史数据或文件,建议用单独的加密通道,而不是让 OPC UA 逐包加密。
3.5 三种模式的决策流程
我画了一张决策流程图,帮你快速选择:
3.6 避坑指南:我踩过的三个坑
坑一:混用安全模式
我曾经在一个项目中,服务器配置了 SignAndEncrypt,但客户端配置了 Sign。结果连接建立失败,报错 SecurityMode mismatch。调试了半天才发现是配置不一致。记住:客户端和服务器的安全模式必须完全匹配,包括 SecurityPolicy 也要一致。
坑二:忽略证书验证
选了 Sign 或 SignAndEncrypt,但证书验证没开。这就相当于你穿了防弹衣,但没扣扣子。攻击者可以伪造证书,照样能通信。我建议在生产环境中一定要启用证书验证,并且定期轮换证书。
坑三:性能测试不充分
很多人在实验室用高端 PC 测试,SignAndEncrypt 跑得飞快。一到现场,换成低端 ARM 处理器,直接卡死。我的习惯是:用目标硬件做性能测试,并且留出 30% 的 CPU 余量给安全层。
3.7 小结
选安全模式没有银弹。None 适合隔离网络和性能敏感场景,Sign 适合大多数工业现场,SignAndEncrypt 适合跨边界和敏感数据。你想想看,你的系统最需要保护的是什么?是数据机密性,还是数据完整性,还是实时性?想清楚这个,选择就简单了。