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。我曾经见过一个案例,某工厂把 OPC UA 服务器暴露在办公网,用的 None 模式,结果被内部员工用 Wireshark 抓包篡改了写入值,导致产线停机两小时。

性能表现:

None 模式几乎不消耗额外 CPU。它只是在消息头里加一个 SecurityMode 字段标记为 None,没有签名计算,没有加密运算。我实测过,在树莓派级别的设备上,None 模式的消息吞吐量可以达到 SignAndEncrypt 的 3-5 倍。

3.3 Sign 模式:只签名不加密,够用吗?

Sign 模式是我个人最常用的模式。它保证消息是来自可信的客户端/服务器,并且没有被篡改过。但数据内容是明文传输的。

适用场景:

  • 监控类数据采集:读取温度、压力、振动等过程值。这些数据本身不敏感,但必须确保来源可靠。
  • 历史数据归档:数据需要保证完整性,不能被人为篡改,但归档后数据本身不保密。
  • 中等性能要求的系统:CPU 资源有限,但又不能完全裸奔。
💡 技巧: 如果你不确定选 Sign 还是 SignAndEncrypt,先选 Sign。因为从 Sign 升级到 SignAndEncrypt 只需要改配置,不需要改代码。反过来,从 None 升级到 Sign 可能需要重新设计证书体系。

性能开销分析:

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 去解密。先加密后签名,接收端可以先验证签名,签名不对直接丢弃,省了解密的开销。

性能开销分析:

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 三种模式的决策流程

我画了一张决策流程图,帮你快速选择:

安全模式决策流程图 安全模式选择决策流程 开始选择安全模式 是否跨安全边界? 是 否 SignAndEncrypt 数据是否敏感? 是 否 Sign 性能是否受限? 是 否 None Sign 说明: • 跨安全边界:指数据经过路由器、防火墙、互联网等不可控网络。 • 数据敏感:指数据内容如果泄露会造成损失(如配方、密码、密钥)。 • 性能受限:指设备 CPU 占用率已超过 70%,或通信延迟要求小于 10ms。

3.6 避坑指南:我踩过的三个坑

坑一:混用安全模式

我曾经在一个项目中,服务器配置了 SignAndEncrypt,但客户端配置了 Sign。结果连接建立失败,报错 SecurityMode mismatch。调试了半天才发现是配置不一致。记住:客户端和服务器的安全模式必须完全匹配,包括 SecurityPolicy 也要一致。

坑二:忽略证书验证

选了 Sign 或 SignAndEncrypt,但证书验证没开。这就相当于你穿了防弹衣,但没扣扣子。攻击者可以伪造证书,照样能通信。我建议在生产环境中一定要启用证书验证,并且定期轮换证书。

坑三:性能测试不充分

很多人在实验室用高端 PC 测试,SignAndEncrypt 跑得飞快。一到现场,换成低端 ARM 处理器,直接卡死。我的习惯是:用目标硬件做性能测试,并且留出 30% 的 CPU 余量给安全层。

3.7 小结

选安全模式没有银弹。None 适合隔离网络和性能敏感场景,Sign 适合大多数工业现场,SignAndEncrypt 适合跨边界和敏感数据。你想想看,你的系统最需要保护的是什么?是数据机密性,还是数据完整性,还是实时性?想清楚这个,选择就简单了。