Zum Inhalt springen

Anleitung

Server absichern

Den Server absichern: Endpunkte, Zertifikate, Benutzer, Rollen und Zugriffskontrolllisten, Audit-Ereignisse und eine Checkliste für den Betrieb.

Anleitung

Server absichern ​

Diese Seite bündelt alle Mechanismen, mit denen ein Server sich und seine Daten schützt. Die Standardwerte des OPC UA .NET SDK sind auf einen einfachen Einstieg ausgelegt und für den Produktivbetrieb nicht geeignet. Welche Einstellungen Sie dafür ändern sollten, fasst der Abschnitt Härtung für den Produktivbetrieb zusammen. Die Grundlagen beschreiben die Seiten Zertifikate verstehen und Benutzer und Rollen.

Standardwerte im Überblick ​

Beteiligte TypenOpcServerOpcServerSecurityOpcServerBindingOpcCertificateStoresOpcAuthenticationLimitsOpcOperationLimits

EinstellungStandardwertEmpfehlung für den Produktivbetrieb
Security.EndpointPoliciesleer: Der Server bietet nur Endpunkte mit dem Modus None anausschließlich Policies mit SignAndEncrypt und Basic256Sha256, Aes128_Sha256_RsaOaep oder Aes256_Sha256_RsaPss
Binding.Addressesleer: Der Server bindet an alle IPv4- und IPv6-Adressen des Rechners, auch wenn seine Adresse localhost lautetauf die Netzwerkschnittstellen beschränken, über die Clients zugreifen
Security.AutoAcceptUntrustedCertificatestrue: Der Server nimmt unbekannte Clientzertifikate anfalse; Clientzertifikate vorab in den TrustedPeerStore aufnehmen
Security.CertificateValidationRulesDefault: Der Server nimmt mit SHA-1 signierte Zertifikate an, die rückwärtskompatible Prüfung ist aktivRejectSHA1Signed und DisableBackwardsCompatibleValidation
Security.AnonymousAclaktiv, solange keine andere Zugriffskontrollliste aktiv istdeaktivieren; nur bekannte Benutzer zulassen
Security.IsAuditingEnabledfalse: Der Server meldet keine Audit-Ereignissenach Bedarf true (siehe Audit-Ereignisse)
CertificateStores.AutoCreateCertificatetrue: Fehlt ein Zertifikat, erzeugt der Server ein neues (bis Version 2.58 auch, wenn das vorhandene ungültig ist)false und ein verwaltetes Zertifikat verwenden
Automatisch erzeugtes Zertifikatselbstsigniert, Schlüssellänge 2048 Bit, gültig für 600 MonateZertifikat einer eigenen Zertifizierungsstelle mit einer Laufzeit nach Ihrer Richtlinie
AuthenticationLimitsaktiv: nach 5 Fehlversuchen innerhalb von 5 Sekunden wachsende Verzögerung ab 1 Sekunde, höchstens 30 Sekundenan die Zahl der Benutzer anpassen
OperationLimits.AutoDetermineLimitsfalse: Der Server meldet seinen Clients keine Grenzen je Anfragetrue
TransportMaxMessageSize 10 MB, MaxByteStringLength 5 MB, MaxStringLength und MaxArrayLength je 65535nur so weit erhöhen, wie die Anwendung es braucht

Unsichere Standardwerte

Mit den Standardwerten ist ein Server über alle Netzwerkschnittstellen des Rechners erreichbar, kommuniziert unverschlüsselt, lässt anonyme Benutzer zu und nimmt das Zertifikat jedes ihm unbekannten Clients an. Wer den Rechner über das Netzwerk erreicht, kann damit Daten lesen, schreiben und Methoden aufrufen. Ändern Sie diese Einstellungen vor dem Produktivbetrieb.

Endpunkte und Netzwerk absichern ​

Beteiligte TypenOpcServerOpcServerSecurityOpcSecurityPolicyOpcServerBinding

Nur verschlüsselte Endpunkte anbieten: Solange die Eigenschaft EndpointPolicies leer ist, bietet der Server ausschließlich Endpunkte mit dem Modus None an. Über diese Endpunkte überträgt er Daten weder signiert noch verschlüsselt. Sobald eine Policy eingetragen ist, entfällt der Endpunkt mit dem Modus None. Tragen Sie deshalb nur Policies mit dem Modus SignAndEncrypt ein und geben Sie den Algorithmus ausdrücklich an. Ohne Angabe (OpcSecurityAlgorithm.Auto) wählt das SDK Basic256Sha256. Wie der Server Adressen und Policies zu Endpunkten kombiniert, beschreibt der Abschnitt Endpunkte.

TLS-Versionen bei HTTPS beachten: Ab Version 2.59 überlässt der Server bei Endpunkten mit dem Schema https die Wahl der TLS-Versionen dem Betriebssystem. Bis Version 2.58 waren TLS 1.0, 1.1 und 1.2 fest eingestellt. Clients, die nur TLS 1.0 oder 1.1 unterstützen, können sich deshalb über HTTPS möglicherweise nicht mehr verbinden.

Nur an die benötigten Netzwerkschnittstellen binden: Die Adresse des Servers (zum Beispiel opc.tcp://localhost:4840/) bestimmt die Endpunkte, die der Server seinen Clients meldet. Sie bestimmt nicht die Netzwerkschnittstellen, an die er seine Ports bindet. Ohne weitere Angabe bindet der Server an alle IPv4- und IPv6-Adressen des Rechners. Damit ist er auch dann aus dem Netzwerk erreichbar, wenn seine Adresse localhost lautet. Beschränken Sie die Bindung über die Eigenschaft Binding auf die benötigten Adressen (siehe An Netzwerkschnittstellen binden). Die standardmäßig aktive exklusive Bindung (UseExclusiveAddress) verhindert zudem, dass ein anderer Prozess denselben Port belegt.

Clientzertifikate prüfen und vertrauen ​

Beteiligte TypenOpcServerOpcServerSecurityOpcCertificateValidationFailedEventArgsOpcCertificateValidationRulesOpcCertificateStoresOpcCertificateStoreInfo

Ein Client sendet beim Verbindungsaufbau sein Zertifikat zur Authentifizierung an den Server. Anhand des Clientzertifikats entscheidet der Server, ob er die Verbindung mit dem Client zulässt und ihm damit vertraut.

Nur vertrauenswürdige Zertifikate akzeptieren: Wenn der Server nur vertrauenswürdige Zertifikate akzeptieren soll, deaktivieren Sie die standardmäßige Akzeptanz aller unbekannten Zertifikate. Abgelaufene, gesperrte oder anderweitig ungültige Zertifikate nimmt der Server auch ohne diese Einstellung nicht automatisch an:

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

Zertifikate selbst prüfen: Sobald Sie die standardmäßige Akzeptanz aller Zertifikate deaktiviert haben, sollten Sie eine benutzerdefinierte Prüfung der Zertifikate vorsehen:

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

Zertifikat manuell vertrauen: Wenn der Server ein Clientzertifikat als nicht vertrauenswürdig eingestuft hat, können Sie es manuell als vertrauenswürdig deklarieren. Speichern Sie es dazu im TrustedPeerStore:

csharp
// In context of the event handler the sender is an OpcServer.
var server = (OpcServer)sender;

if (!server.CertificateStores.TrustedPeerStore.Contains(e.Certificate))
    server.CertificateStores.TrustedPeerStore.Add(e.Certificate);
vbnet
' In context of the event handler the sender is an OpcServer.
Dim server As OpcServer = CType(sender, OpcServer)

If Not server.CertificateStores.TrustedPeerStore.Contains(e.Certificate) Then
    server.CertificateStores.TrustedPeerStore.Add(e.Certificate)
End If

Strengere Regeln für die Prüfung von Zertifikaten legt die Eigenschaft CertificateValidationRules fest. Standardmäßig akzeptiert der Server auch Zertifikate, die mit SHA-1 signiert sind:

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

Eigenes Zertifikat schützen ​

Beteiligte TypenOpcServerOpcCertificateManagerOpcCertificateSettingsOpcCertificateStoresOpcCertificateRequestedEventArgs

Wie ein Zertifikat geladen, erzeugt und gespeichert wird, beschreibt der Abschnitt Anwendungszertifikat. Für die Sicherheit sind dabei die folgenden Punkte wichtig:

  • Eigenschaften des Zertifikats: Ein vom SDK erzeugtes Zertifikat ist selbstsigniert, verwendet einen Schlüssel mit 2048 Bit und ist 600 Monate gültig. Schlüssellänge (KeySize), Gültigkeit in Monaten (Lifetime) und die Domänen, unter denen der Server erreichbar ist (DomainNames), legen Sie über die Klasse OpcCertificateSettings fest. Beim Server ergänzt das SDK die Domänen um den vollqualifizierten Namen des Rechners (FQDN), sofern er sich per DNS auflösen lässt. So nehmen Clients, die sich über diesen Namen verbinden, das Zertifikat an. Als Organisation (O) im Antragsteller (engl. subject) trägt das SDK den Hersteller aus OpcServerInfo.CompanyName ein (Eigenschaft Organization). Ein bereits vorhandenes Zertifikat ändert es nicht. Für den Produktivbetrieb empfiehlt sich ein Zertifikat, das die Zertifizierungsstelle (engl. certificate authority) Ihres Unternehmens ausgestellt hat. Clients müssen dann nur der Zertifizierungsstelle vertrauen.
  • Kein Zertifikat stillschweigend ersetzen: Wenn der Server beim Start kein gültiges Zertifikat findet, zum Beispiel weil es abgelaufen ist, löst er das Ereignis CertificateRequested aus. Bis Version 2.58 gilt: Wenn kein Handler ein Zertifikat liefert und die Eigenschaft AutoCreateCertificate aktiv ist, löscht er das bisherige Zertifikat aus dem ApplicationStore und erzeugt ein neues, selbstsigniertes Zertifikat. Clients, die dem bisherigen Zertifikat vertraut haben, lehnen den Server danach ab. Ab Version 2.59 ersetzt der Server ein vorhandenes, aber ungültiges Zertifikat nie automatisch. Die Eigenschaft Reason der Ereignisdaten nennt dann den Grund: Invalid, UseNotAllowed, Revoked, TimeInvalid, IssuerUseNotAllowed, IssuerRevoked oder IssuerTimeInvalid. Für ein abgelaufenes Zertifikat lautet er zum Beispiel TimeInvalid. Die Eigenschaft AutoCreateCertificate der Ereignisdaten ist dabei false. Wenn der Handler kein anderes Zertifikat bereitstellt, verwendet der Server weiter das vorhandene Zertifikat. Ein Zertifikat, das der Handler über die Eigenschaft AlternativeCertificate bereitstellt, verwendet der Server ab Version 2.59 beim Start. Es muss seinen privaten Schlüssel enthalten. Stellen Sie über das Ereignis CertificateRequested selbst ein Zertifikat bereit und deaktivieren Sie die automatische Erzeugung.
  • Den privaten Schlüssel schützen: Der ApplicationStore enthält das Zertifikat samt privatem Schlüssel. Das SDK legt für die Dateien der Zertifikatspeicher keine Zugriffsrechte fest. Legen Sie die Zertifikatspeicher in einem Verzeichnis ab, auf das nur das Benutzerkonto des Servers zugreifen darf. Laden Sie ein vorhandenes Zertifikat aus einer durch ein Passwort geschützten .pfx-Datei.

Benutzer anmelden ​

Beteiligte TypenOpcServerOpcUserIdentityOpcServerIdentityOpcCertificateIdentityOpcServerSecurityOpcAccessControlListOpcAnonymousAclOpcUserNameAclOpcCertificateAclOpcAccessControlEntryOpcOperationTypeOpcRequestTypeOpcAccessControlMode

Ein Server erlaubt standardmäßig auch Zugriffe ohne Angabe einer konkreten Benutzeridentität. Diese Art der Benutzerauthentifizierung heißt anonyme Authentifizierung. Wenn ein Client dagegen eine Benutzeridentität angibt, muss der Server diese Identität kennen. Nur dann lässt er den Zugriff mit dieser Identität zu. Wenn sich Benutzer zum Beispiel mit einem Benutzername-Passwort-Paar oder einem Zertifikat ausweisen sollen, konfigurieren und aktivieren Sie die passenden Zugriffskontrolllisten (engl. Access Control List, ACL). Zur Konfiguration der Zugriffskontrolllisten gehört die Konfiguration der Zugriffskontrolleinträge (engl. Access Control Entries, ACE). Jeder Eintrag steht für ein Prinzipal mit einer bestimmten Identität, also Benutzername und Passwort oder ein Zertifikat. Die Einträge tragen Sie in die Listen ein.

Die Zugriffskontrollliste für anonyme Benutzer ist nur so lange aktiv, wie keine andere Zugriffskontrollliste aktiv ist. Wenn Sie also zum Beispiel die Zugriffskontrollliste für Benutzername-Passwort-Paare aktivieren, ist der anonyme Zugriff automatisch abgeschaltet. Wenn er dennoch möglich sein soll, setzen Sie die Eigenschaft IsEnabled der AnonymousAcl ausdrücklich auf true. Umgekehrt schaltet das folgende Beispiel den anonymen Zugriff ausdrücklich ab:

Anonyme Zugriffskontrollliste deaktivieren:

csharp
server.Security.AnonymousAcl.IsEnabled = false;
vbnet
server.Security.AnonymousAcl.IsEnabled = False

Zugriffskontrollliste für Benutzername-Passwort-Paare konfigurieren:

csharp
var acl = server.Security.UserNameAcl;

acl.AddEntry("username1", "password1");
acl.AddEntry("username2", "password2");
acl.AddEntry("username3", "password3");
...
acl.IsEnabled = true;
vbnet
Dim acl = server.Security.UserNameAcl

acl.AddEntry("username1", "password1")
acl.AddEntry("username2", "password2")
acl.AddEntry("username3", "password3")
'...
acl.IsEnabled = True

Zugriffskontrollliste für Zertifikate konfigurieren:

csharp
var acl = server.Security.CertificateAcl;
  
acl.AddEntry(new X509Certificate2(@".\user1.der"));
acl.AddEntry(new X509Certificate2(@".\user2.der"));
acl.AddEntry(new X509Certificate2(@".\user3.der"));
...
acl.IsEnabled = true;
vbnet
Dim acl = server.Security.CertificateAcl

acl.AddEntry(New X509Certificate2(".\user1.der"))
acl.AddEntry(New X509Certificate2(".\user2.der"))
acl.AddEntry(New X509Certificate2(".\user3.der"))
'...
acl.IsEnabled = True

Wenn über die Eigenschaft CertificateValidator der CertificateAcl ein eigener X509CertificateValidator festgelegt ist, prüft der Server das Zertifikat einer Benutzeridentität zusätzlich, bevor er den Fingerabdruck (engl. thumbprint) vergleicht.

Alle Zugriffskontrolllisten, die das SDK bereitstellt, verwenden den Zugriffskontrollmodus (engl. Access Control Mode) Whitelist. In diesem Modus hat jeder Eintrag allein dadurch, dass er definiert ist, Zugriff auf alle Arten (engl. Types) von Anfragen (engl. Requests). Das gilt auch, wenn ihm der Zugriff dafür nicht ausdrücklich erteilt (engl. allow) wurde. Entziehen (engl. deny) Sie den Einträgen deshalb alle nicht erlaubten Operationen. Die erlaubten und verbotenen Operationen legen Sie direkt auf dem Eintrag fest, den die Zugriffskontrollliste nach dem Eintragen bereitstellt. Andere Modi, Rollen und eigene Zugriffskontrolllisten beschreiben die Abschnitte Zugriffskontrollmodi, Rollen und Eigene Zugriffskontrolllisten.

1. Einen Zugriffskontrolleintrag merken:

csharp
var user1 = acl.AddEntry("username1", "password1");
vbnet
Dim user1 = acl.AddEntry("username1", "password1")

2. Dem Zugriffskontrolleintrag zwei Rechte entziehen:

csharp
user1.Deny(OpcRequestType.Write);
user1.Deny(OpcRequestType.HistoryUpdate);
vbnet
user1.Deny(OpcRequestType.Write)
user1.Deny(OpcRequestType.HistoryUpdate)

3. Ein zuvor entzogenes Recht wieder erteilen:

csharp
user1.Allow(OpcRequestType.HistoryUpdate);
vbnet
user1.Allow(OpcRequestType.HistoryUpdate)

Passwörter geschützt ablegen ​

Beteiligte TypenOpcServerIdentityOpcUserNameAcl

Wenn Sie einen Benutzer mit einem Passwort als Zeichenkette eintragen (AddEntry(userName, password)), hält der Server das Passwort im Klartext im Speicher. Wenn die Passwörter Ihrer Benutzer bereits als Hashwerte vorliegen, leiten Sie von der Klasse OpcServerIdentity ab. Der Konstruktor übernimmt den gespeicherten Hashwert als Byte-Array. Die überschriebene Methode TransformPassword berechnet beim Anmelden aus dem übermittelten Passwort den Hashwert nach demselben Verfahren. Der Server vergleicht die beiden Werte in konstanter Zeit. Das folgende Beispiel verwendet PBKDF2 mit einem Salt je Benutzer:

csharp
public sealed class HashedServerIdentity : OpcServerIdentity
{
    private const int Iterations = 100000;
    private readonly byte[] salt;
 
    public HashedServerIdentity(string userName, byte[] passwordHash, byte[] salt)
        : base(userName, password: passwordHash)
    {
        this.salt = salt;
    }
 
    public static byte[] Hash(string password, byte[] salt)
    {
        using (var pbkdf2 = new Rfc2898DeriveBytes(
                password,
                salt,
                Iterations,
                HashAlgorithmName.SHA256)) {
            return pbkdf2.GetBytes(32);
        }
    }
 
    protected override byte[] TransformPassword(string password)
    {
        return Hash(password, this.salt);
    }
}
vbnet
Public NotInheritable Class HashedServerIdentity
    Inherits OpcServerIdentity

    Private Const Iterations As Integer = 100000
    Private ReadOnly salt As Byte()

    Public Sub New(ByVal userName As String, ByVal passwordHash As Byte(), ByVal salt As Byte())
        MyBase.New(userName, password:=passwordHash)
        Me.salt = salt
    End Sub

    Public Shared Function Hash(ByVal password As String, ByVal salt As Byte()) As Byte()
        Using pbkdf2 = New Rfc2898DeriveBytes( _
                password, _
                salt, _
                Iterations, _
                HashAlgorithmName.SHA256)
            Return pbkdf2.GetBytes(32)
        End Using
    End Function

    Protected Overrides Function TransformPassword(ByVal password As String) As Byte()
        Return Hash(password, Me.salt)
    End Function
End Class

So tragen Sie die Identität ein:

csharp
// Hash and salt come from the user store of the application.
var identity = new HashedServerIdentity("operator", storedHash, storedSalt);
 
server.Security.UserNameAcl.AddEntry(identity);
server.Security.UserNameAcl.IsEnabled = true;
vbnet
'Hash and salt come from the user store of the application.
Dim identity = New HashedServerIdentity("operator", storedHash, storedSalt)

server.Security.UserNameAcl.AddEntry(identity)
server.Security.UserNameAcl.IsEnabled = True

Benutzerzertifikate prüfen ​

Beteiligte TypenOpcCertificateAcl

Wenn sich ein Benutzer mit einem Zertifikat anmeldet, vergleicht der Server dessen Fingerabdruck mit den Einträgen der CertificateAcl. Wenn der Server das Zertifikat vorher prüfen soll, zum Beispiel gegen die Zertifizierungsstelle Ihres Unternehmens und auf eine Sperrung, legen Sie über die Eigenschaft CertificateValidator einen eigenen X509CertificateValidator fest (Namespace System.IdentityModel.Selectors). Wenn der Validator das Zertifikat mit einer Ausnahme ablehnt, verweigert der Server die Anmeldung:

csharp
public sealed class UserCertificateValidator : X509CertificateValidator
{
    public override void Validate(X509Certificate2 certificate)
    {
        using (var chain = new X509Chain()) {
            chain.ChainPolicy.RevocationMode = X509RevocationMode.Online;
 
            if (!chain.Build(certificate))
                throw new SecurityException("The user certificate is not trusted.");
        }
    }
}
vbnet
Public NotInheritable Class UserCertificateValidator
    Inherits X509CertificateValidator

    Public Overrides Sub Validate(ByVal certificate As X509Certificate2)
        Using chain = New X509Chain()
            chain.ChainPolicy.RevocationMode = X509RevocationMode.Online

            If Not chain.Build(certificate) Then
                Throw New SecurityException("The user certificate is not trusted.")
            End If
        End Using
    End Sub
End Class
csharp
server.Security.CertificateAcl.CertificateValidator = new UserCertificateValidator();
server.Security.CertificateAcl.AddEntry(userCertificate);
server.Security.CertificateAcl.IsEnabled = true;
vbnet
server.Security.CertificateAcl.CertificateValidator = New UserCertificateValidator()
server.Security.CertificateAcl.AddEntry(userCertificate)
server.Security.CertificateAcl.IsEnabled = True

Benutzer auf Endpunkte beschränken ​

Beteiligte TypenOpcAccessControlEntryOpcEndpointIdentityOpcAccessControlMode

Neben den Operationen kann ein Zugriffskontrolleintrag auch die Endpunkte festlegen, über die sich ein Benutzer anmelden darf. Wie der Server erteilte (Enable) und entzogene (Disable) Endpunkte auswertet, bestimmt der Zugriffskontrollmodus für Endpunkte. Sie geben ihn beim Hinzufügen eines Eintrags als zweiten Modus an. Im Modus Blacklist darf sich der Benutzer nur über ausdrücklich erteilte Endpunkte anmelden. Über alle anderen Endpunkte verweigert der Server die Anmeldung mit dem Status BadUserAccessDenied. So lässt sich zum Beispiel ein Dienstkonto auf einen Endpunkt mit dem Modus SignAndEncrypt beschränken. Adresse und Policy der OpcEndpointIdentity müssen dabei dem Endpunkt entsprechen, über den sich der Client verbindet:

csharp
var endpoint = new OpcEndpointIdentity(
        "opc.tcp://192.168.0.10:4840/",
        new OpcSecurityPolicy(OpcSecurityMode.SignAndEncrypt, OpcSecurityAlgorithm.Basic256Sha256));
 
// Endpoint access mode Blacklist: only explicitly enabled endpoints are permitted.
var service = server.Security.UserNameAcl.AddEntry(
        "service",
        servicePassword,
        operationAccessMode: OpcAccessControlMode.Whitelist,
        endpointAccessMode: OpcAccessControlMode.Blacklist);
 
service.Enable(endpoint);
vbnet
Dim endpoint = New OpcEndpointIdentity( _
        "opc.tcp://192.168.0.10:4840/", _
        New OpcSecurityPolicy(OpcSecurityMode.SignAndEncrypt, OpcSecurityAlgorithm.Basic256Sha256))

'Endpoint access mode Blacklist: only explicitly enabled endpoints are permitted.
Dim service = server.Security.UserNameAcl.AddEntry( _
        "service", _
        servicePassword, _
        operationAccessMode:=OpcAccessControlMode.Whitelist, _
        endpointAccessMode:=OpcAccessControlMode.Blacklist)

service.Enable(endpoint)

Anmeldung mit Token ​

Für Benutzeridentitäten mit ausgestellten Token (engl. issued token) prüft die IssuedTokenAcl ausschließlich Kerberos-Tickets, und das nur, wenn der Server unter .NET Framework läuft. Unter .NET Standard und .NET (Core) weist der Server solche Anmeldungen ab.

Rollen ​

Beteiligte TypenOpcServerSecurityOpcServerSecurityRolesOpcAccessControlRoleOpcAccessControlEntryOpcPrincipal

OPC UA definiert eine Reihe von Standardrollen, denen die Benutzer eines Servers angehören können. Die Eigenschaft Roles der Klasse OpcServerSecurity stellt diese Rollen als Instanzen der Klasse OpcAccessControlRole bereit:

RolleBedeutung
AnonymousDarf nicht sicherheitsrelevante Nodes im Server-Objekt und alle Typ-Nodes browsen und lesen.
AuthenticatedUserDarf nicht sicherheitsrelevante Nodes browsen und lesen.
ObserverDarf browsen, aktuelle und historische Daten und Ereignisse lesen und Daten und Ereignisse abonnieren.
OperatorWie Observer, darf zusätzlich einige aktuelle Daten schreiben und einige Methoden aufrufen.
EngineerDarf browsen, Konfigurationsdaten lesen und schreiben, historische Daten und Ereignisse lesen, Methoden aufrufen und abonnieren.
SupervisorDarf browsen, aktuelle und historische Daten und Ereignisse lesen, Methoden aufrufen und abonnieren.
ConfigureAdminDarf nicht sicherheitsrelevante Einstellungen der Konfiguration ändern.
SecurityAdminDarf sicherheitsrelevante Einstellungen ändern, zum Beispiel das Zertifikat des Servers (siehe Zertifikate per GDS verwalten).

Anonyme Benutzer ordnet der Server automatisch der Rolle Anonymous zu, alle über eine Zugriffskontrollliste angemeldeten Benutzer der Rolle AuthenticatedUser. Weitere Rollen ordnen Sie einem Zugriffskontrolleintrag über die Methode Assign zu:

csharp
var acl = server.Security.UserNameAcl;
 
var operator1 = acl.AddEntry("operator1", password: "password1");
operator1.Assign(server.Security.Roles.Operator);
 
var admin = acl.AddEntry("admin", password: "password2");
admin.Assign(server.Security.Roles.ConfigureAdmin, server.Security.Roles.SecurityAdmin);
 
acl.IsEnabled = true;
vbnet
Dim acl = server.Security.UserNameAcl

Dim operator1 = acl.AddEntry("operator1", password:="password1")
operator1.Assign(server.Security.Roles.Operator)

Dim admin = acl.AddEntry("admin", password:="password2")
admin.Assign(server.Security.Roles.ConfigureAdmin, server.Security.Roles.SecurityAdmin)

acl.IsEnabled = True

Über die Methode Revoke heben Sie die Zuordnung wieder auf:

csharp
admin.Revoke(server.Security.Roles.ConfigureAdmin);
vbnet
admin.Revoke(server.Security.Roles.ConfigureAdmin)

Ob ein Prinzipal einer Rolle angehört, ermittelt die Methode IsInRole der Klasse OpcPrincipal beziehungsweise die Methode Contains der jeweiligen Rolle. Die Rollen, die der Server verwendet, liefert die Eigenschaft AccessControlRoles der Klasse OpcServerSecurity.

Zugriffskontrollmodi ​

Beteiligte TypenOpcAccessControlListOpcAccessControlEntryOpcAccessControlModeOpcRequestType

Wie der Server die einem Zugriffskontrolleintrag erteilten (Allow) und entzogenen (Deny) Operationen auswertet, legt der Zugriffskontrollmodus des Eintrags fest (Enumeration OpcAccessControlMode):

  • Whitelist (Standard der Zugriffskontrolllisten des SDK): Alle Operationen sind erlaubt, solange sie dem Eintrag nicht ausdrücklich entzogen wurden.
  • Blacklist: Alle Operationen sind verweigert, solange sie dem Eintrag nicht ausdrücklich erteilt wurden.
  • Explicit: Es zählt nur, was dem Eintrag ausdrücklich erteilt oder entzogen wurde. Der Server verweigert dabei ausschließlich ausdrücklich entzogene Operationen.

Den Modus legen Sie beim Hinzufügen eines Eintrags fest:

csharp
var guest = acl.AddEntry(
        "guest",
        password: "password3",
        operationAccessMode: OpcAccessControlMode.Blacklist);
 
// In blacklist mode only explicitly allowed operations are permitted.
guest.Allow(OpcRequestType.Browse, OpcRequestType.Read);
vbnet
Dim guest = acl.AddEntry( _
        "guest", _
        password:="password3", _
        operationAccessMode:=OpcAccessControlMode.Blacklist)

'In blacklist mode only explicitly allowed operations are permitted.
guest.Allow(OpcRequestType.Browse, OpcRequestType.Read)

Eigene Zugriffskontrolllisten ​

Beteiligte TypenOpcServerSecurityOpcAccessControlListOpcAccessControlTokenTypeOpcIdentityTokenOpcUserNameIdentityTokenOpcPrincipalOpcServerIdentity

Wenn Sie die Benutzer eines Servers nicht im Code des Servers pflegen möchten, sondern zum Beispiel in einer bestehenden Benutzerverwaltung, implementieren Sie eine eigene Zugriffskontrollliste. Leiten Sie dazu von der Klasse OpcAccessControlList ab, legen Sie über die Eigenschaft TokenType die Art der unterstützten Identitäten fest und implementieren Sie die Methode Authenticate. Wenn die Methode ein Prinzipal liefert, gilt der Benutzer als angemeldet. Wenn sie null liefert, prüft der Server die nächste aktive Zugriffskontrollliste. Ordnen Sie angemeldete Benutzer wie bei den Zugriffskontrolllisten des SDK der Rolle AuthenticatedUser zu:

csharp
public class MyUserNameAcl : OpcAccessControlList
{
    private readonly Dictionary<string, OpcPrincipal> principals
            = new Dictionary<string, OpcPrincipal>();
 
    public MyUserNameAcl(OpcServerBase owner)
        : base(
                owner,
                operationAccessMode: OpcAccessControlMode.Whitelist,
                endpointAccessMode: OpcAccessControlMode.Whitelist)
    {
    }
 
    protected override OpcAccessControlTokenType TokenType
    {
        get { return OpcAccessControlTokenType.UserName; }
    }
 
    public override OpcPrincipal Authenticate(OpcIdentityToken identityToken)
    {
        var token = identityToken as OpcUserNameIdentityToken;
 
        // Verify the user name and password, e.g. using an existing user management.
        if (token == null || !UserStore.Verify(token.UserName, token.DecryptedPassword))
            return null;
 
        lock (this.principals) {
            OpcPrincipal principal;
 
            if (!this.principals.TryGetValue(token.UserName, out principal)) {
                principal = new OpcPrincipal(new OpcServerIdentity(token.UserName));
                this.AddEntry(principal);
 
                // Authenticated users are expected to be a member of the AuthenticatedUser role.
                this.Owner.Security.Roles.AuthenticatedUser.Assign(principal);
                this.principals.Add(token.UserName, principal);
            }
 
            return principal;
        }
    }
}
vbnet
Public Class MyUserNameAcl
    Inherits OpcAccessControlList

    Private ReadOnly principals As New Dictionary(Of String, OpcPrincipal)()

    Public Sub New(ByVal owner As OpcServerBase)
        MyBase.New( _
                owner, _
                operationAccessMode:=OpcAccessControlMode.Whitelist, _
                endpointAccessMode:=OpcAccessControlMode.Whitelist)
    End Sub

    Protected Overrides ReadOnly Property TokenType As OpcAccessControlTokenType
        Get
            Return OpcAccessControlTokenType.UserName
        End Get
    End Property

    Public Overrides Function Authenticate(ByVal identityToken As OpcIdentityToken) As OpcPrincipal
        Dim token = TryCast(identityToken, OpcUserNameIdentityToken)

        'Verify the user name and password, e.g. using an existing user management.
        If token Is Nothing OrElse Not UserStore.Verify(token.UserName, token.DecryptedPassword) Then
            Return Nothing
        End If

        SyncLock Me.principals
            Dim principal As OpcPrincipal = Nothing

            If Not Me.principals.TryGetValue(token.UserName, principal) Then
                principal = New OpcPrincipal(New OpcServerIdentity(token.UserName))
                Me.AddEntry(principal)

                'Authenticated users are expected to be a member of the AuthenticatedUser role.
                Me.Owner.Security.Roles.AuthenticatedUser.Assign(principal)
                Me.principals.Add(token.UserName, principal)
            End If

            Return principal
        End SyncLock
    End Function
End Class

Über die Methode AddAccessControlList machen Sie die eigene Zugriffskontrollliste dem Server bekannt und aktivieren sie. Über die Methode RemoveAccessControlList entfernen Sie sie wieder:

csharp
var customAcl = new MyUserNameAcl(server);
server.Security.AddAccessControlList(customAcl);
 
customAcl.IsEnabled = true;
vbnet
Dim customAcl = New MyUserNameAcl(server)
server.Security.AddAccessControlList(customAcl)

customAcl.IsEnabled = True

Wie bei den Zugriffskontrolllisten des SDK schaltet die Aktivierung einer eigenen Zugriffskontrollliste den anonymen Zugriff automatisch ab (siehe Benutzer anmelden).

Anmeldeversuche begrenzen ​

Beteiligte TypenOpcServerOpcAuthenticationLimits

Zum Schutz vor dem Durchprobieren von Passwörtern (engl. brute force) begrenzt der Server die Anmeldeversuche über die Eigenschaft AuthenticationLimits. Er zählt die Versuche je Benutzer und IP-Adresse des Clients. Wenn innerhalb des Zeitfensters DelayWindow (standardmäßig 5 Sekunden) mehr als MaxFailedAttempts (standardmäßig 5) Anmeldeversuche fehlschlagen, verzögert der Server jeden weiteren Versuch. Er verzögert zunächst um Delay (standardmäßig 1 Sekunde) und bei weiteren Fehlversuchen jeweils doppelt so lange, höchstens jedoch um MaxDelay (standardmäßig 30 Sekunden). Eine erfolgreiche Anmeldung setzt den Zähler zurück:

csharp
server.AuthenticationLimits.MaxFailedAttempts = 3;                  // Default: 5
server.AuthenticationLimits.DelayWindow = TimeSpan.FromSeconds(10); // Default: 5 seconds
server.AuthenticationLimits.Delay = TimeSpan.FromSeconds(2);        // Default: 1 second
server.AuthenticationLimits.MaxDelay = TimeSpan.FromMinutes(1);     // Default: 30 seconds
vbnet
server.AuthenticationLimits.MaxFailedAttempts = 3                  'Default: 5
server.AuthenticationLimits.DelayWindow = TimeSpan.FromSeconds(10) 'Default: 5 seconds
server.AuthenticationLimits.Delay = TimeSpan.FromSeconds(2)        'Default: 1 second
server.AuthenticationLimits.MaxDelay = TimeSpan.FromMinutes(1)     'Default: 30 seconds

Zudem begrenzt der Server die Zahl gleichzeitiger Anmeldeversuche je Identität (MaxConcurrentAttemptsPerIdentity, standardmäßig 3) und insgesamt (MaxConcurrentAttempts, standardmäßig 32). Darüber hinausgehende Versuche lehnt er mit dem Status BadUserAccessDenied ab. Wenn der Server diese Grenzen anhand der Prozessorkerne und des verfügbaren Speichers ermitteln soll, aktivieren Sie die Eigenschaft AutoDetermineLimits:

csharp
// Default: false
server.AuthenticationLimits.AutoDetermineLimits = true;
vbnet
'Default: False
server.AuthenticationLimits.AutoDetermineLimits = True

Für Verbindungen über das Schema https stehen dem Server keine Informationen zur Gegenstelle zur Verfügung. Die Begrenzung gilt dort deshalb nicht.

Abgelehnte Anmeldungen meldet das Ereignis SessionActivationFailed (siehe Audit-Ereignisse).

Schutz vor Überlastung ​

Beteiligte TypenOpcServerOpcOperationLimitsOpcTransportOpcRequestValidatingEventArgs

Clients können einen Server mit sehr großen oder sehr vielen Anfragen belasten. Drei Mechanismen begrenzen das:

  • Grenzen je Anfrage: Standardmäßig meldet der Server seinen Clients keine Grenzen dafür, wie viele Nodes sie je Anfrage lesen, schreiben, browsen oder abonnieren dürfen. Mit OperationLimits.AutoDetermineLimits ermittelt der Server anhand der verfügbaren Systemressourcen geeignete Grenzen und meldet sie seinen Clients (siehe Grenzen der Datenübertragung).
  • Grenzen der Nachrichten: Die Grenzen unter Transport begrenzen die Größe von Nachrichten, Zeichenketten und Arrays. Erhöhen Sie sie nur so weit, wie es die Anwendung erfordert.
  • Anfragen ablehnen: Über das Ereignis RequestValidating kann der Server Anfragen vor der Verarbeitung ablehnen, zum Beispiel alle Anfragen, die die Struktur des Adressraums verändern (siehe Anfragen validieren):
csharp
server.RequestValidating += HandleRequestValidating;
...
private static void HandleRequestValidating(
        object sender,
        OpcRequestValidatingEventArgs e)
{
    // Clients must not change the structure of the address space.
    if (e.RequestType == OpcRequestType.AddNodes
            || e.RequestType == OpcRequestType.DeleteNodes
            || e.RequestType == OpcRequestType.AddReferences
            || e.RequestType == OpcRequestType.DeleteReferences) {
        e.Cancel = true;
    }
}
vbnet
AddHandler server.RequestValidating, AddressOf HandleRequestValidating
...
Private Shared Sub HandleRequestValidating( _
        ByVal sender As Object, _
        ByVal e As OpcRequestValidatingEventArgs)
    'Clients must not change the structure of the address space.
    If e.RequestType = OpcRequestType.AddNodes _
            OrElse e.RequestType = OpcRequestType.DeleteNodes _
            OrElse e.RequestType = OpcRequestType.AddReferences _
            OrElse e.RequestType = OpcRequestType.DeleteReferences Then
        e.Cancel = True
    End If
End Sub

Zertifikate per GDS verwalten ​

Ein Global Discovery Server (GDS) kann das Anwendungszertifikat und die vertrauenswürdigen Zertifikate des Servers aus der Ferne verwalten (GDS Push Management). Voraussetzungen, Ablauf und Einschränkungen beschreibt die Seite Zertifikate per GDS verwalten.

Audit-Ereignisse ​

Beteiligte TypenOpcServerOpcServerSecurityOpcSessionOpcRequestValidatingEventArgsOpcSessionActivationFailedEventArgs

Audit-Ereignisse (gemäß OPC UA Teil 4) protokollieren sicherheitsrelevante Aktionen. Der Server meldet sie nur, wenn die Eigenschaft Security.IsAuditingEnabled den Wert true hat (standardmäßig false). Die Eigenschaft lässt sich auch im laufenden Betrieb umschalten und wirkt dann sofort:

csharp
server.Security.IsAuditingEnabled = true;
vbnet
server.Security.IsAuditingEnabled = True

Der Server meldet die folgenden Audit-Ereignisse über das Server-Objekt:

EreignistypAusgelöst
AuditOpenSecureChannelEventTypewenn ein Client einen sicheren Kanal öffnet; außerdem, wenn der Server das Öffnen oder Erneuern eines sicheren Kanals ablehnt
AuditChannelEventTypewenn ein Client einen sicheren Kanal mit einer CloseSecureChannel-Anfrage schließt
AuditCreateSessionEventTypewenn ein Client eine Sitzung erstellt
AuditActivateSessionEventTypewenn ein Client eine Sitzung aktiviert, also sich anmeldet

Die Ereignisse zu sicheren Kanälen meldet der Server nur für Verbindungen über opc.tcp. Wie in OPC UA festgelegt, erhält ein Client die Audit-Ereignisse nur, wenn er über einen Endpunkt mit dem Modus SignAndEncrypt oder über HTTPS verbunden ist und sein Benutzer der Rolle SecurityAdmin angehört (siehe Rollen).

Weitere Audit-Ereignisse, etwa für Schreibzugriffe, Methodenaufrufe oder Zertifikatsänderungen, meldet der Server nicht. Eigene Audit-Ereignisse kann eine Anwendung nicht melden. Wie ein Client die Ereignisse empfängt, beschreibt der Abschnitt Audit-Ereignisse empfangen.

Wenn Ihre Anwendung ein Protokoll sicherheitsrelevanter Aktionen benötigt, führen Sie es selbst über die Ereignisse des Servers, zum Beispiel SessionActivated für Anmeldungen, SessionActivationFailed für abgelehnte Anmeldungen und RequestValidating für Schreibzugriffe und Methodenaufrufe (siehe Anfragen überwachen):

csharp
server.SessionActivated += HandleSessionActivated;
server.RequestValidating += HandleCriticalRequest;
...
private static void HandleSessionActivated(object sender, OpcSessionEventArgs e)
{
    Console.WriteLine(
            "{0:u} session {1}: {2}",
            DateTime.UtcNow,
            e.Session.Name,
            e.Session.UsedIdentity);
}
 
private static void HandleCriticalRequest(object sender, OpcRequestValidatingEventArgs e)
{
    if (e.RequestType == OpcRequestType.Write || e.RequestType == OpcRequestType.Call) {
        Console.WriteLine(
                "{0:u} {1} in session {2}",
                DateTime.UtcNow,
                e.RequestType,
                e.Context.SessionId);
    }
}
vbnet
AddHandler server.SessionActivated, AddressOf HandleSessionActivated
AddHandler server.RequestValidating, AddressOf HandleCriticalRequest
...
Private Shared Sub HandleSessionActivated(ByVal sender As Object, ByVal e As OpcSessionEventArgs)
    Console.WriteLine( _
            "{0:u} session {1}: {2}", _
            DateTime.UtcNow, _
            e.Session.Name, _
            e.Session.UsedIdentity)
End Sub

Private Shared Sub HandleCriticalRequest( _
        ByVal sender As Object, _
        ByVal e As OpcRequestValidatingEventArgs)
    If e.RequestType = OpcRequestType.Write OrElse e.RequestType = OpcRequestType.Call Then
        Console.WriteLine( _
                "{0:u} {1} in session {2}", _
                DateTime.UtcNow, _
                e.RequestType, _
                e.Context.SessionId)
    End If
End Sub

SessionActivationFailed tritt bei jeder abgelehnten Anmeldung ein. Die Eigenschaft Status nennt den Grund, die Eigenschaft Identity die Identität, mit der sich der Client anmelden wollte, ohne Passwort oder Token-Daten. Bei einem Benutzernamen ist sie eine OpcUserNameIdentityTokenInfo mit dem Namen des Benutzers (UserName), bei einem Benutzerzertifikat eine OpcCertificateIdentityTokenInfo mit dem Zertifikat (Certificate):

csharp
server.SessionActivationFailed += HandleSessionActivationFailed;
...
private static void HandleSessionActivationFailed(
        object sender,
        OpcSessionActivationFailedEventArgs e)
{
    var userName = e.Identity as OpcUserNameIdentityTokenInfo;
 
    Console.WriteLine(
            "{0:u} logon rejected ({1}): {2}",
            DateTime.UtcNow,
            e.Status.Code,
            userName != null ? userName.UserName : "no user name");
}
vbnet
AddHandler server.SessionActivationFailed, AddressOf HandleSessionActivationFailed
...
Private Shared Sub HandleSessionActivationFailed( _
        ByVal sender As Object, _
        ByVal e As OpcSessionActivationFailedEventArgs)
    Dim userName = TryCast(e.Identity, OpcUserNameIdentityTokenInfo)

    Console.WriteLine( _
            "{0:u} logon rejected ({1}): {2}", _
            DateTime.UtcNow, _
            e.Status.Code, _
            If(userName IsNot Nothing, userName.UserName, "no user name"))
End Sub

Härtung für den Produktivbetrieb ​

Prüfen Sie vor dem Produktivbetrieb die folgenden Punkte:

  1. Nur verschlüsselte Endpunkte anbieten: ausschließlich Policies mit SignAndEncrypt und einem aktuellen Algorithmus eintragen (siehe Endpunkte und Netzwerk absichern).
  2. Netzwerkschnittstellen beschränken: die Eigenschaft Binding auf die benötigten Adressen begrenzen.
  3. Unbekannte Clientzertifikate ablehnen: AutoAcceptUntrustedCertificates deaktivieren und Clientzertifikate in den TrustedPeerStore aufnehmen (siehe Clientzertifikate prüfen und vertrauen).
  4. Zertifikate streng prüfen: CertificateValidationRules auf RejectSHA1Signed und DisableBackwardsCompatibleValidation stellen.
  5. Eigenes Zertifikat verwalten: ein Zertifikat mit angemessener Schlüssellänge und Laufzeit verwenden, AutoCreateCertificate deaktivieren und die Zertifikatspeicher in einem geschützten Verzeichnis ablegen (siehe Eigenes Zertifikat schützen).
  6. Anonymen Zugriff abschalten und Benutzer verwalten: nur bekannte Benutzer zulassen, Passwörter als Hashwerte ablegen und Benutzerzertifikate prüfen (siehe Benutzer anmelden).
  7. Rechte minimal halten: jedem Benutzer nur die Operationen erteilen, die er braucht, und Rollen gezielt zuordnen (siehe Rollen und Zugriffskontrollmodi).
  8. Anmeldeversuche begrenzen: die AuthenticationLimits an die Zahl der Benutzer anpassen (siehe Anmeldeversuche begrenzen).
  9. Überlastung verhindern: OperationLimits.AutoDetermineLimits aktivieren, die Grenzen unter Transport nicht unnötig erhöhen und unerwünschte Anfragen ablehnen (siehe Schutz vor Überlastung).
  10. GDS Push gezielt freischalten: die Rolle SecurityAdmin nur einer Identität mit Zertifikat zuordnen (siehe Zertifikate per GDS verwalten).
  11. Sicherheitsrelevante Aktionen protokollieren: bei Bedarf IsAuditingEnabled einschalten, Anmeldungen, abgelehnte Anmeldungen und kritische Anfragen selbst protokollieren (siehe Audit-Ereignisse) und die Kennzahlen des Servers überwachen (siehe Diagnose).
  12. Lizenzschlüssel schützen: den Schlüssel nicht im Klartext in öffentlich zugänglichen Dateien oder Repositories ablegen (siehe Fahrlässige Veröffentlichung).

Zusammengefasst sieht ein so konfigurierter Server wie folgt aus:

csharp
var server = new OpcServer("opc.tcp://192.168.0.10:4840/");
 
// Only encrypted endpoints with current algorithms (removes the implicit None endpoint).
server.Security.EndpointPolicies.Add(new OpcSecurityPolicy(
        OpcSecurityMode.SignAndEncrypt,
        OpcSecurityAlgorithm.Basic256Sha256));
server.Security.EndpointPolicies.Add(new OpcSecurityPolicy(
        OpcSecurityMode.SignAndEncrypt,
        OpcSecurityAlgorithm.Aes256_Sha256_RsaPss));
 
// Listen only on the network interface that clients use.
server.Binding.Addresses.Add(IPAddress.Parse("192.168.0.10"));
 
// Trust only known client certificates and check them strictly.
server.Security.AutoAcceptUntrustedCertificates = false;
server.Security.CertificateValidationRules
        = OpcCertificateValidationRules.RejectSHA1Signed
        | OpcCertificateValidationRules.DisableBackwardsCompatibleValidation;
 
// No anonymous access, only known users.
server.Security.UserNameAcl.AddEntry("operator", operatorPassword);
server.Security.UserNameAcl.IsEnabled = true;
server.Security.AnonymousAcl.IsEnabled = false;
 
// Report operation limits to the clients.
server.OperationLimits.AutoDetermineLimits = true;
 
// Use a managed certificate instead of a generated one.
server.CertificateStores.AutoCreateCertificate = false;
server.Certificate = OpcCertificateManager.LoadCertificate(certificatePath, certificatePassword);
 
server.Start();
vbnet
Dim server = New OpcServer("opc.tcp://192.168.0.10:4840/")

'Only encrypted endpoints with current algorithms (removes the implicit None endpoint).
server.Security.EndpointPolicies.Add(New OpcSecurityPolicy( _
        OpcSecurityMode.SignAndEncrypt, _
        OpcSecurityAlgorithm.Basic256Sha256))
server.Security.EndpointPolicies.Add(New OpcSecurityPolicy( _
        OpcSecurityMode.SignAndEncrypt, _
        OpcSecurityAlgorithm.Aes256_Sha256_RsaPss))

'Listen only on the network interface that clients use.
server.Binding.Addresses.Add(IPAddress.Parse("192.168.0.10"))

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

'No anonymous access, only known users.
server.Security.UserNameAcl.AddEntry("operator", operatorPassword)
server.Security.UserNameAcl.IsEnabled = True
server.Security.AnonymousAcl.IsEnabled = False

'Report operation limits to the clients.
server.OperationLimits.AutoDetermineLimits = True

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

server.Start()