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 模式下,安全策略的设置会被忽略。

我画了一张图,帮你理清它们的关系:

OPC UA 安全模式与安全策略决策流程 选择安全模式 None 无保护,不加密不签名 Sign 只签名,不加密 SignAndEncrypt 签名 + 加密 选择安全策略 Basic128Rsa15 Basic256 Basic256Sha256 None 模式下,安全策略不生效。Sign 和 SignAndEncrypt 模式下,必须指定安全策略。

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 模式。你永远不知道谁在监听你的网络。