Skip to content

How-to guide

Secure clients

Secure the client: choose an endpoint, validate server certificates, protect your own certificate, authenticate users, and use a checklist for production.

This content was machine translated and may contain errors. Read in German

How-to guide

Secure clients ​

This page collects all settings a client uses to secure its connections to a server. The default values of the OPC UA .NET SDK are designed for an easy start and are not suitable for production. The section Harden for production summarizes which settings you should change for production. The pages Understand certificates and Users and roles describe the basics.

Default values at a glance ​

Types usedOpcClientOpcClientSecurityOpcCertificateStoresOpcCertificateSettingsOpcTransport

SettingDefault valueRecommendation for production
Security.EndpointPolicynull: the client chooses the endpoint with the lowest level, usually an endpoint with the mode NoneSet a policy with SignAndEncrypt and Basic256Sha256, Aes128_Sha256_RsaOaep, or Aes256_Sha256_RsaPss
Security.UseOnlySecureEndpointsfalsetrue if no EndpointPolicy is set
Security.AutoUpgradeEndpointPolicyfalsetrue together with an EndpointPolicy
Security.AutoAcceptUntrustedCertificatestrue: the client accepts unknown server certificatesfalse; add server certificates to the TrustedPeerStore in advance
Security.VerifyServersCertificateDomainsfalsetrue
Security.CertificateValidationRulesDefault: the client accepts certificates signed with SHA-1, and backward-compatible validation is activeRejectSHA1Signed and DisableBackwardsCompatibleValidation
CertificateStores.AutoCreateCertificatetrue: if there is no certificate, the client creates a new one (up to version 2.58 also if the existing one is invalid)false, and use a managed certificate
Automatically created certificateself-signed, key length 2048 bits, valid for 600 monthscertificate from your own certificate authority with a lifetime according to your policy
Security.UserIdentitynull: anonymous authenticationuser name and password pair or certificate
TransportMaxMessageSize 10 MB, MaxByteStringLength 5 MB, MaxStringLength and MaxArrayLength 65535 eachincrease only as far as the application needs

Insecure default values

With the default values, the client usually connects without encryption and accepts the certificate of any server it does not know. An attacker in the network can then pose as the server (man in the middle), read and modify the transferred data, and obtain the credentials sent to it. Change these settings before you go to production.

Choose a secure endpoint ​

Types usedOpcClientOpcClientSecurityOpcSecurityPolicyOpcSecurityModeOpcSecurityAlgorithmOpcDiscoveryClientOpcEndpointDescription

By default, the client chooses the endpoint with the simplest security configuration from the server endpoints offered, that is, the endpoint with the lowest level. According to the OPC Foundation, the level of the policy of an endpoint is a relative measure of the security mechanisms the endpoint uses. By definition, an endpoint with a higher level is therefore more secure than an endpoint with a lower level. This way, the client usually chooses an endpoint with the mode None. If the server does not offer one, the client chooses an endpoint with Sign or SignAndEncrypt.

Consider only encrypted endpoints: If the client should consider only encrypted endpoints, set the property UseOnlySecureEndpoints to true. The client then chooses only endpoints with the mode SignAndEncrypt (enumeration OpcSecurityMode):

csharp
client.Security.UseOnlySecureEndpoints = true;
vbnet
client.Security.UseOnlySecureEndpoints = True

Choose the endpoint with the highest level: If the client should choose the endpoint that defines the highest policy level, set the property UseHighLevelEndpoint to true:

csharp
client.Security.UseHighLevelEndpoint = true;
vbnet
client.Security.UseHighLevelEndpoint = True

Set a specific security configuration: If the client should choose an endpoint with a specific security configuration, set the property EndpointPolicy as in the following example. The client then uses only an endpoint with exactly this OpcSecurityMode and OpcSecurityAlgorithm. Choose a current algorithm: Basic128Rsa15 and Basic256 are considered deprecated, and Basic256Sha256, Aes128_Sha256_RsaOaep, or Aes256_Sha256_RsaPss, for example, are preferable. If you do not specify an algorithm (OpcSecurityAlgorithm.Auto), the client uses Basic256Sha256 for Sign and SignAndEncrypt. It then does not connect to a server that offers only Basic256 or Basic128Rsa15. In this case, the client ignores the properties UseOnlySecureEndpoints and UseHighLevelEndpoint:

csharp
client.Security.EndpointPolicy = new OpcSecurityPolicy(
        OpcSecurityMode.SignAndEncrypt,
        OpcSecurityAlgorithm.Basic256Sha256);
vbnet
client.Security.EndpointPolicy = New OpcSecurityPolicy( _
        OpcSecurityMode.SignAndEncrypt, _
        OpcSecurityAlgorithm.Basic256Sha256)

Fall back to a more secure endpoint: If the client should fall back to a more secure endpoint when the server does not offer the specified policy, also set the property AutoUpgradeEndpointPolicy to true. The property UsedEndpoint returns the endpoint the client actually uses after the connection is established:

csharp
client.Security.EndpointPolicy = new OpcSecurityPolicy(
        OpcSecurityMode.SignAndEncrypt,
        OpcSecurityAlgorithm.Basic256Sha256);
 
// Use the next better endpoint in case the server does not offer the policy.
client.Security.AutoUpgradeEndpointPolicy = true;
 
client.Connect();
Console.WriteLine("Used endpoint: {0}", client.UsedEndpoint);
vbnet
client.Security.EndpointPolicy = New OpcSecurityPolicy( _
        OpcSecurityMode.SignAndEncrypt, _
        OpcSecurityAlgorithm.Basic256Sha256)

'Use the next better endpoint in case the server does not offer the policy.
client.Security.AutoUpgradeEndpointPolicy = True

client.Connect()
Console.WriteLine("Used endpoint: {0}", client.UsedEndpoint)

To examine the endpoints of a server, use the class OpcDiscoveryClient. The property SupportedTokenTypes of the endpoint description returns the kinds of user identities an endpoint supports:

csharp
using (var client = new OpcDiscoveryClient("opc.tcp://localhost:4840/")) {
    var endpoints = client.DiscoverEndpoints();
 
    foreach (var endpoint in endpoints) {
        // Your code to operate on each endpoint.
    }
}
vbnet
Using client As New OpcDiscoveryClient("opc.tcp://localhost:4840/")
    Dim endpoints = client.DiscoverEndpoints()
 
    For Each endpoint in endpoints
        'Your code to operate on each endpoint.
    Next
End Using

Check after connecting: Check whether the client actually uses an encrypted endpoint. This is useful above all if no fixed EndpointPolicy is set:

csharp
client.Connect();
 
if (client.UsedEndpoint.Policy.Mode != OpcSecurityMode.SignAndEncrypt) {
    client.Disconnect();
    throw new InvalidOperationException("The server offers no encrypted endpoint.");
}
vbnet
client.Connect()

If client.UsedEndpoint.Policy.Mode <> OpcSecurityMode.SignAndEncrypt Then
    client.Disconnect()
    Throw New InvalidOperationException("The server offers no encrypted endpoint.")
End If

Validate and trust server certificates ​

Types usedOpcClientOpcClientSecurityOpcCertificateValidationFailedEventArgsOpcCertificateValidationRulesOpcCertificateJudgementEventArgsOpcCertificateImpeachmentOpcCertificateStoresOpcCertificateStoreInfo

When the connection is established, a server sends its certificate to the client for authentication. Based on the server certificate, the client decides whether it really connects to this server and thus trusts it.

Check the domains in the certificate: If you enable the property VerifyServersCertificateDomains, the client also checks the domains stored in the server certificate. By default, this property is disabled:

csharp
client.Security.VerifyServersCertificateDomains = true;
vbnet
client.Security.VerifyServersCertificateDomains = True

Accept only trusted certificates: If the client should accept only trusted certificates, disable the default acceptance of unknown certificates. Even with acceptance enabled, the client does not automatically accept expired, revoked, or otherwise invalid certificates:

csharp
client.Security.AutoAcceptUntrustedCertificates = false;
vbnet
client.Security.AutoAcceptUntrustedCertificates = False

Validate certificates yourself: Once you have disabled the default acceptance of unknown certificates, you should provide a custom validation of the certificates:

csharp
client.CertificateValidationFailed += HandleCertificateValidationFailed;
...
private void HandleCertificateValidationFailed(
        object sender,
        OpcCertificateValidationFailedEventArgs e)
{
    if (e.Certificate.Thumbprint == "...")
        e.Accept = true;
}
vbnet
AddHandler client.CertificateValidationFailed, AddressOf HandleCertificateValidationFailed
...
Private Sub HandleCertificateValidationFailed( _
        ByVal sender As Object, _
        ByVal e As OpcCertificateValidationFailedEventArgs)
    If e.Certificate.Thumbprint = "..." Then
        e.Accept = True
    End If
End Sub

Trust a certificate manually: If the client has classified a server certificate as untrusted, you can declare it as trusted manually. To do this, store it in the TrustedPeerStore:

csharp
// In context of the event handler the sender is an OpcClient.
var client = (OpcClient)sender;
 
if (!client.CertificateStores.TrustedPeerStore.Contains(e.Certificate))
    client.CertificateStores.TrustedPeerStore.Add(e.Certificate);
vbnet
'In context of the event handler the sender is an OpcClient.
Dim client = CType(sender, OpcClient)
 
If Not client.CertificateStores.TrustedPeerStore.Contains(e.Certificate) Then
    client.CertificateStores.TrustedPeerStore.Add(e.Certificate)
End If

Stricter rules for validating certificates: The property CertificateValidationRules sets them. With RejectSHA1Signed, the client rejects certificates that were signed with SHA-1. With DisableBackwardsCompatibleValidation, it validates according to the currently recommended rules. By default, both rules are disabled:

csharp
client.Security.CertificateValidationRules
        = OpcCertificateValidationRules.RejectSHA1Signed
        | OpcCertificateValidationRules.DisableBackwardsCompatibleValidation;
vbnet
client.Security.CertificateValidationRules _
        = OpcCertificateValidationRules.RejectSHA1Signed _
        Or OpcCertificateValidationRules.DisableBackwardsCompatibleValidation

Handle a certificate change: If the server uses a different certificate during an existing connection than when the connection was established, the client raises the event CertificateJudgement. If you do not handle it, this situation leads to an exception. With the property Dismiss of the event arguments, you can dismiss the objection:

csharp
client.CertificateJudgement += HandleCertificateJudgement;
...
private static void HandleCertificateJudgement(
        object sender,
        OpcCertificateJudgementEventArgs e)
{
    // The server uses a different certificate than when the connection was established.
    if (e.Impeachment == OpcCertificateImpeachment.Changed
            && e.ImpeachedCertificate.Thumbprint == "...")
        e.Dismiss = true;
}
vbnet
AddHandler client.CertificateJudgement, AddressOf HandleCertificateJudgement
...
Private Shared Sub HandleCertificateJudgement( _
        ByVal sender As Object, _
        ByVal e As OpcCertificateJudgementEventArgs)
    'The server uses a different certificate than when the connection was established.
    If e.Impeachment = OpcCertificateImpeachment.Changed _
            AndAlso e.ImpeachedCertificate.Thumbprint = "..." Then
        e.Dismiss = True
    End If
End Sub

Allow only a specific server: If the client should not accept unknown certificates across the board, but you also do not want to store every certificate in the TrustedPeerStore in advance, the client can accept the certificate of the expected server in the event CertificateValidationFailed. It recognizes the certificate by its thumbprint. The property Result states the reason for the objection. Accept only certificates with the result Untrusted. Results such as Revoked, TimeInvalid, InvalidDomain, or ChainIncomplete indicate a certificate that is revoked, expired, issued for another computer, or cannot be fully validated:

csharp
client.CertificateValidationFailed += HandleCertificateValidationFailed;
...
private void HandleCertificateValidationFailed(
        object sender,
        OpcCertificateValidationFailedEventArgs e)
{
    // Accept only the expected server, and only if its certificate is merely unknown.
    e.Accept = e.Result == OpcCertificateValidationResult.Untrusted
            && string.Equals(
                    e.Certificate.Thumbprint,
                    expectedThumbprint,
                    StringComparison.OrdinalIgnoreCase);
}
vbnet
AddHandler client.CertificateValidationFailed, AddressOf HandleCertificateValidationFailed
...
Private Sub HandleCertificateValidationFailed( _
        ByVal sender As Object, _
        ByVal e As OpcCertificateValidationFailedEventArgs)
    'Accept only the expected server, and only if its certificate is merely unknown.
    e.Accept = e.Result = OpcCertificateValidationResult.Untrusted _
            AndAlso String.Equals( _
                    e.Certificate.Thumbprint, _
                    expectedThumbprint, _
                    StringComparison.OrdinalIgnoreCase)
End Sub

Protect your own certificate ​

Types usedOpcClientOpcCertificateManagerOpcCertificateSettingsOpcCertificateStoresOpcCertificateRequestedEventArgs

The section Application certificate describes how a certificate is loaded, created, and stored. For security, the following points matter.

Set the properties of the certificate: A certificate created by the SDK is self-signed, uses a 2048-bit key, and is valid for 600 months. You set the key length (KeySize) and the validity in months (Lifetime) through the class OpcCertificateSettings. For production, use a certificate issued by the certificate authority of your company:

csharp
// The key size is specified in bits, the lifetime in months.
var settings = new OpcCertificateSettings(client.ApplicationName) {
    KeySize = 4096,
    Lifetime = 24
};
 
client.Certificate = OpcCertificateManager.CreateCertificate(settings);
vbnet
'The key size is specified in bits, the lifetime in months.
Dim settings = New OpcCertificateSettings(client.ApplicationName) With { _
    .KeySize = 4096, _
    .Lifetime = 24 _
}

client.Certificate = OpcCertificateManager.CreateCertificate(settings)

Do not replace a certificate silently: Up to version 2.58, the following applies: If the property AutoCreateCertificate is active and the client finds no valid certificate when it connects, it deletes the previous certificate from the ApplicationStore and creates a new, self-signed certificate. This happens, for example, when the certificate has expired. Servers that trusted the previous certificate then reject the client.

As of version 2.59, the client never replaces an existing but invalid certificate automatically. Instead, it raises the event CertificateRequested. The property Reason of the event data states the reason: Invalid, UseNotAllowed, Revoked, TimeInvalid, IssuerUseNotAllowed, IssuerRevoked, or IssuerTimeInvalid. For an expired certificate, for example, it is TimeInvalid. The property AutoCreateCertificate of the event data is false in this case. Unless the handler provides another certificate, the client keeps using the existing certificate. As of version 2.59, the client uses a certificate that the handler provides through the property AlternativeCertificate when it connects, also on later connects. The certificate must contain its private key.

Provide a certificate yourself through the event CertificateRequested and disable automatic creation:

csharp
client.CertificateStores.AutoCreateCertificate = false;
client.CertificateRequested += HandleCertificateRequested;
...
private void HandleCertificateRequested(
        object sender,
        OpcCertificateRequestedEventArgs e)
{
    e.AlternativeCertificate = OpcCertificateManager.LoadCertificate(
            certificatePath,
            certificatePassword);
}
vbnet
client.CertificateStores.AutoCreateCertificate = False
AddHandler client.CertificateRequested, AddressOf HandleCertificateRequested
...
Private Sub HandleCertificateRequested( _
        ByVal sender As Object, _
        ByVal e As OpcCertificateRequestedEventArgs)
    e.AlternativeCertificate = OpcCertificateManager.LoadCertificate( _
            certificatePath, _
            certificatePassword)
End Sub

Protect the private key: The ApplicationStore contains the certificate together with its private key. The SDK does not set access permissions for the files of the certificate stores. Therefore, put the certificate stores in a directory that only the user account of the application can access. The section Configure the application and session describes how to configure the certificate stores. Load an existing certificate from a password-protected .pfx file.

Authenticate users ​

Types usedOpcClientOpcUserIdentityOpcClientIdentityOpcCertificateIdentityOpcClientSecurityOpcCertificateStoresOpcCertificateStoreInfo

If a server expects information about the identity of the user in addition to the client certificate, set the identity through the property UserIdentity. You can choose identities with user name and password or with a certificate. If the server supports an anonymous user identity, you do not have to set a specific identity.

Set a user identity with user name and password:

csharp
client.Security.UserIdentity = new OpcClientIdentity("userName", "password");
vbnet
client.Security.UserIdentity = New OpcClientIdentity("userName", "password")

Set a user identity with a certificate (with private key):

csharp
client.Security.UserIdentity = new OpcCertificateIdentity(new X509Certificate2("Doe.pfx"));
vbnet
client.Security.UserIdentity = New OpcCertificateIdentity(New X509Certificate2("Doe.pfx"))

Set an anonymous user identity (already the default configuration):

csharp
client.Security.UserIdentity = null;
vbnet
client.Security.UserIdentity = Nothing

Change the user identity at runtime: The ChangeUserIdentity method logs on another user in the existing session without closing the connection. With null, the client continues as an anonymous user. If the server rejects the identity, the method throws an OpcException with the status of the server, for example BadUserAccessDenied. The session and the previous identity then remain. Only after a successful change does the UserIdentity property return the new identity. If the client is not connected, the method throws an OpcException with the status BadServerNotConnected:

csharp
client.ChangeUserIdentity(new OpcClientIdentity("userName", "password"));
vbnet
client.ChangeUserIdentity(New OpcClientIdentity("userName", "password"))

Transfer of the password: The client encrypts the password of a user name and password identity with the certificate of the server, provided that the server specifies a security policy for its user tokens. A server developed with this SDK does so even on endpoints with the mode None. With servers from other vendors, the password can be transferred unencrypted on such endpoints. In addition, this protection is only as good as the validation of the server certificate: if the client accepts unknown certificates automatically, an attacker posing as the server can decrypt the password. Therefore, authenticate users only through endpoints with the mode SignAndEncrypt, and disable the property AutoAcceptUntrustedCertificates for them. Do not store passwords in the source code. Read them at runtime from protected storage instead.

Data transfer limits ​

The limits for the size of messages, strings, and arrays also protect the client from oversized responses of a server. Increase them only as far as the application requires (see Data transfer limits).

OPC Classic and DCOM ​

For connections to OPC Classic servers, the security settings of DCOM apply. The section Remote servers and DCOM security of the page OPC Classic describes how to set the logon and the authentication level.

Harden for production ​

Check the following points before you go to production:

  1. Enforce an encrypted endpoint: Set EndpointPolicy with SignAndEncrypt and a current algorithm, or enable UseOnlySecureEndpoints and check the endpoint used (see Choose a secure endpoint).
  2. Reject unknown server certificates: Disable AutoAcceptUntrustedCertificates, and add server certificates to the TrustedPeerStore or accept them selectively in the event CertificateValidationFailed (see Validate and trust server certificates).
  3. Validate certificates strictly: Set CertificateValidationRules to RejectSHA1Signed and DisableBackwardsCompatibleValidation, and enable VerifyServersCertificateDomains.
  4. Manage your own certificate: Use a certificate with an appropriate key length and lifetime, disable AutoCreateCertificate, and put the certificate stores in a protected directory (see Protect your own certificate).
  5. Authenticate users: Use a user identity and do not store passwords in the source code (see Authenticate users).
  6. Do not accept certificate changes unchecked: Handle the event CertificateJudgement, and set Dismiss only after your own check.
  7. Do not increase limits unnecessarily: Adjust the limits under Transport only as far as the application requires.
  8. Protect the license key: Do not store the key in plain text in publicly accessible files or repositories (see Negligent disclosure).

In summary, a client configured this way looks like this:

csharp
var client = new OpcClient("opc.tcp://192.168.0.10:4840/");
 
// Only an encrypted endpoint with a current algorithm.
client.Security.EndpointPolicy = new OpcSecurityPolicy(
        OpcSecurityMode.SignAndEncrypt,
        OpcSecurityAlgorithm.Basic256Sha256);
client.Security.AutoUpgradeEndpointPolicy = true;
 
// Trust only known server certificates and check them strictly.
client.Security.AutoAcceptUntrustedCertificates = false;
client.Security.VerifyServersCertificateDomains = true;
client.Security.CertificateValidationRules
        = OpcCertificateValidationRules.RejectSHA1Signed
        | OpcCertificateValidationRules.DisableBackwardsCompatibleValidation;
 
// Use a managed certificate instead of a generated one.
client.CertificateStores.AutoCreateCertificate = false;
client.Certificate = OpcCertificateManager.LoadCertificate(certificatePath, certificatePassword);
 
// Log on as a user instead of anonymously.
client.Security.UserIdentity = new OpcClientIdentity(userName, password);
vbnet
Dim client = New OpcClient("opc.tcp://192.168.0.10:4840/")

'Only an encrypted endpoint with a current algorithm.
client.Security.EndpointPolicy = New OpcSecurityPolicy( _
        OpcSecurityMode.SignAndEncrypt, _
        OpcSecurityAlgorithm.Basic256Sha256)
client.Security.AutoUpgradeEndpointPolicy = True

'Trust only known server certificates and check them strictly.
client.Security.AutoAcceptUntrustedCertificates = False
client.Security.VerifyServersCertificateDomains = True
client.Security.CertificateValidationRules _
        = OpcCertificateValidationRules.RejectSHA1Signed _
        Or OpcCertificateValidationRules.DisableBackwardsCompatibleValidation

'Use a managed certificate instead of a generated one.
client.CertificateStores.AutoCreateCertificate = False
client.Certificate = OpcCertificateManager.LoadCertificate(certificatePath, certificatePassword)

'Log on as a user instead of anonymously.
client.Security.UserIdentity = New OpcClientIdentity(userName, password)