4. OPC UA 安全策略:安全模式与安全策略详解
好,咱们进入正题。这一章聊的是 OPC UA 安全里最核心的配置——安全策略和安全模式。说白了,就是决定你的数据在传输过程中,到底要不要加密、要不要签名,以及用什么算法来干这些活。
我在项目里见过不少工程师,一上来就把安全模式设成 None,图省事。结果呢?生产数据在网络上裸奔,被人抓包分析了都不知道。嗯,咱们今天就把这事彻底讲清楚。
4.1 安全模式:三种选择,三种风险等级
OPC UA 定义了三种安全模式。你可以把它们想象成三道门:不锁门、只锁门不关窗、锁死所有门窗。
| 安全模式 | 签名 | 加密 | 典型场景 |
|---|---|---|---|
| None | 无 | 无 | 测试环境、内部调试网络 |
| Sign | 有 | 无 | 数据完整性要求高,但性能敏感 |
| SignAndEncrypt | 有 | 有 | 生产环境、跨网段、互联网传输 |
⚠️ 重要提醒:None 模式不提供任何保护。数据包可以被任意篡改、窃听。我曾经在一个客户现场发现,他们用了三年 None 模式,结果被竞争对手抓包分析了工艺参数。从那以后,我建议所有生产环境至少用 Sign 模式。
4.2 安全策略:算法组合的“套餐”
安全策略,就是一组加密算法的组合。OPC UA 标准定义了三种策略,每种都指定了签名算法、加密算法和密钥长度。
我个人习惯把安全策略比作“套餐”:Basic128Rsa15 是经济套餐,Basic256 是标准套餐,Basic256Sha256 是豪华套餐。你选哪个,取决于你的安全等级要求和设备算力。
4.2.1 Basic128Rsa15
- 签名算法:HMAC-SHA1,RSA-PKCS15-SHA1
- 加密算法:AES-128-CBC
- 密钥长度:128 位
- 适用场景:老旧设备、资源受限的嵌入式系统
这个策略用的是 SHA-1 算法。说实话,SHA-1 已经被证明存在碰撞攻击风险。但很多 10 年前的 PLC 和 RTU 只支持这个。如果你必须兼容老设备,那就用这个,但尽量配合 SignAndEncrypt 模式。
4.2.2 Basic256
- 签名算法:HMAC-SHA1,RSA-OAEP-SHA1
- 加密算法:AES-256-CBC
- 密钥长度:256 位
- 适用场景:中等安全需求,新老设备混合环境
注意,Basic256 的签名部分仍然用了 SHA-1,但加密升级到了 AES-256。这就好比门锁换成了最坚固的,但门上的猫眼还是老式的。我个人不太推荐这个策略,除非你确实需要兼容某些不支持 SHA-256 的老设备。
4.2.3 Basic256Sha256
- 签名算法:HMAC-SHA256,RSA-OAEP-SHA256
- 加密算法:AES-256-CBC
- 密钥长度:256 位
- 适用场景:新项目、高安全要求、互联网连接
这是目前最推荐的安全策略。签名和加密都用了 SHA-256 和 AES-256,安全性足够应对绝大多数工业场景。我所有的新项目,只要设备支持,一律用 Basic256Sha256 + SignAndEncrypt。
✅ 最佳实践:新部署的系统,优先选择 Basic256Sha256。如果客户端或服务器不支持,再降级到 Basic256。尽量避免使用 Basic128Rsa15,除非万不得已。
4.3 安全模式与安全策略的搭配关系
你可能会问:安全模式和安全策略怎么搭配?其实很简单:安全策略只有在 Sign 或 SignAndEncrypt 模式下才生效。None 模式下,安全策略的设置会被忽略。
我画了一张图,帮你理清它们的关系:
4.4 实际配置示例
光说不练假把式。咱们看看实际代码里怎么配。下面是一个 OPC UA 客户端连接时指定安全策略和安全模式的示例:
// C# 示例:使用 OPC UA .NET Standard 栈
var selectedEndpoint = description.Endpoints
.Where(e => e.SecurityMode == MessageSecurityMode.SignAndEncrypt
&& e.SecurityPolicyUri == SecurityPolicies.Basic256Sha256)
.OrderByDescending(e => e.SecurityLevel)
.FirstOrDefault();
if (selectedEndpoint == null)
{
Console.WriteLine("未找到支持 Basic256Sha256 + SignAndEncrypt 的端点");
return;
}
var endpointConfiguration = EndpointConfiguration.Create(appConfig);
var endpoint = new ConfiguredEndpoint(null, selectedEndpoint, endpointConfiguration);
var session = await Session.Create(
appConfig,
endpoint,
true, // 更新证书
"MySession",
60000, // 超时时间
null,
null
);
💡 小技巧:实际项目中,我通常会先枚举服务器支持的所有端点,然后按安全等级从高到低尝试连接。这样既能保证安全,又能兼容不同配置的服务器。
4.5 避坑指南
最后,分享几个我在项目中踩过的坑:
- 证书不匹配:安全策略和证书的密钥长度必须匹配。Basic256Sha256 需要至少 2048 位的 RSA 密钥。我曾经用了一个 1024 位的证书,结果连接一直失败,查了半天才发现是证书问题。
- 性能影响:SignAndEncrypt 模式会带来 10%-30% 的性能开销。如果你的 PLC 或 RTU 算力很弱,可以考虑只在关键数据上使用加密,或者用 Sign 模式保证完整性即可。
- 互操作性:不同厂商的实现可能有细微差异。我建议在集成测试时,用 UA Expert 或 UaClient 先验证一下双方的策略协商是否正常。
⚠️ 重要:永远不要在互联网上使用 None 模式。即使在内网,也建议至少用 Sign 模式。你永远不知道谁在监听你的网络。