mirror of
https://github.com/OPCFoundation/UA-.NETStandard.git
synced 2026-10-22 01:26:20 +08:00
5ca95abd0d
Security-review subagent finding (HIGH, confidence 9/10).
When consumers used the new DI flow services.AddOpcUa().AddClient(...),
the channel took the IHttpClientFactory branch and got back a named
HttpClient configured purely with AddStandardResilienceHandler() — and
the underlying HttpClientHandler was NOT exposed for HttpsTransportChannel
to attach:
- ServerCertificateCustomValidationCallback wired against the OPC UA
CertificateValidator (so the OPC UA trust list was dropped — falling
back to the OS trust chain only)
- The OPC UA application instance client certificate (so OPC UA mTLS
was silently disabled)
- AllowAutoRedirect = false (HTTPS redirects were now followed)
- MaxConnectionsPerServer / MaxRequestContentBufferSize quotas (no
longer enforced at the HTTP layer)
A server presenting a publicly-trusted CA-issued cert (CA misissuance,
domain takeover, compromised CA) would be accepted while the OPC UA
trust list — the proper authority for OPC UA — was ignored.
Fix:
- CanUseHttpClientFactory() now refuses the factory path whenever the
channel quotas carry a CertificateValidator (i.e. whenever OPC UA
server-cert validation is required), unconditionally routing to
CreateDirectHttpClient() which wires the OPC UA server-cert callback
and the OPC UA mTLS client cert.
- CreateHttpClient() emits a one-time LogWarning when a non-Shared
factory was supplied but bypassed for security reasons, so operators
see that the named HttpClient pipeline (e.g. Polly resilience handler)
is NOT applied to this OPC UA HTTPS channel.
- DefaultOpcUaHttpClientFactory.Shared continues to take the direct
path as before (no behavior change for non-DI consumers).
Verified locally:
- Stack/Opc.Ua.Core builds clean on net48 and net10.0 (0 W, 0 E)
- Libraries/Opc.Ua.Client builds clean on net10.0 (0 W, 0 E)
- OpcUaHttpClientFactoryTests on net8.0: 4/4 pass
- Https | Transport | ClientChannelManager filter on net8.0: 112/112 pass