Freigeben über


Schannel

Das Sicherheitspaket secure Channel (Schannel), dessen Authentifizierungsdienst-ID RPC_C_AUTHN_GSS_SCHANNEL ist, unterstützt die folgenden public-key-basierten Protokolle: SSL (Secure Sockets Layer) Version 2.0 und 3.0, Transport Layer Security (TLS) 1.0 und Private Communication Technology (PCT) 1.0. TLS 1.0 ist eine standardisierte, leicht geänderte Version von SSL 3.0, die von der Internet Engineering Task Force (IETF) im Januar 1999 im Dokument RFC 2246ausgestellt wurde. Da TLS standardisiert wurde, werden Entwickler ermutigt, TLS anstelle von SSL zu verwenden. PCT ist nur aus Gründen der Abwärtskompatibilität enthalten und sollte nicht für die neue Entwicklung verwendet werden. Wenn das Schannel-Sicherheitspaket verwendet wird, verhandelt DCOM automatisch das beste Protokoll, je nach Client- und Serverfunktionen.

In den folgenden Themen wird kurz das TLS-Protokoll und die Funktionsweise mit DCOM beschrieben.

Anmerkung

Alle Informationen zum TLS-Protokoll in diesen Abschnitten gelten auch für die SSL- und PCT-Protokolle.

 

Wann tls verwendet werden soll

TLS ist die einzige Sicherheitsoption, die verfügbar ist, wenn Server ihre Identität für anonyme Clients nachweisen müssen. Dies ist besonders wichtig für Websites, die am E-Commerce teilnehmen möchten, da sie dabei hilft, die Übermittlung vertraulicher Informationen wie Kreditkartennummern zu schützen. TLS stellt sicher, dass die E-Commerce-Kunden sicher sein können, mit wem sie geschäftlich arbeiten, weil sie einen Nachweis der Identität des Servers erhalten. Er verleiht dem E-Commerce-Server auch die Effizienz, sich nicht mit der Authentifizierung der Identität der einzelnen Kunden zu befassen.

TLS erfordert, dass alle Server ihre Identität für Clients nachweisen. Darüber hinaus bietet TLS die Möglichkeit, Clients ihre Identität auf Servern nachzuweisen. Diese gegenseitige Authentifizierung kann nützlich sein, um den Zugriff bestimmter Webseiten in einem großen Unternehmensintranet einzuschränken.

TLS unterstützt die stärksten Authentifizierungsstufen und bietet eine offene Architektur, die die Verschlüsselungsstärke im Laufe der Zeit erhöht, um mit technologischen Innovationen schritt zu halten. TLS ist die beste Wahl für Umgebungen, in denen die höchste Sicherheitsstufe für die daten während der Übertragung gewünscht wird.

Kurze Übersicht über die Funktionsweise von TLS

TLS basiert auf einer Public Key-Infrastruktur (PKI), die öffentliche/private Schlüsselpaare zum Aktivieren der Datenverschlüsselung und zum Herstellen der Datenintegrität verwendet und X.509-Zertifikate für die Authentifizierung verwendet.

Viele Sicherheitsprotokolle, z. B. das Kerberos v5-Protokoll, hängen von einem einzelnen Schlüssel ab, um Daten zu verschlüsseln und zu entschlüsseln. Solche Protokolle hängen daher vom sicheren Austausch von Verschlüsselungsschlüsseln ab; im Kerberos-Protokoll erfolgt dies über Tickets aus dem Key Distribution Center (KDC). Dies erfordert, dass jeder, der das Kerberos-Protokoll verwendet, beim KDC registriert wird, was eine unpraktische Einschränkung für einen E-Commerce-Webserver sein würde, der Millionen von Kunden aus aller Welt anziehen soll. TLS basiert daher auf einer PKI, die zwei Schlüssel für die Datenverschlüsselung verwendet" wenn ein Schlüssel des Paars die Daten verschlüsselt, kann nur der andere Schlüssel des Paars sie entschlüsseln. Der Hauptvorteil dieses Designs besteht darin, dass die Verschlüsselung durchgeführt werden kann, ohne dass der sichere Austausch von Verschlüsselungsschlüsseln erforderlich ist.

Eine PKI verwendet eine Technik, bei der einer der Schlüssel privat gehalten wird und nur für den Prinzipal verfügbar ist, für den sie registriert ist, während der andere Schlüssel für jeden zugänglich gemacht wird. Wenn jemand eine private Nachricht an den Besitzer eines Schlüsselpaars senden möchte, kann die Nachricht mit dem öffentlichen Schlüssel verschlüsselt werden, und nur der private Schlüssel kann zum Entschlüsseln der Nachricht verwendet werden.

Schlüsselpaare werden auch verwendet, um die Integrität der gesendeten Daten zu überprüfen. Dazu kann der Besitzer des Schlüsselpaars vor dem Senden eine digitale Signatur an die Daten anfügen. Das Erstellen einer digitalen Signatur umfasst die Berechnung eines Hashs der Daten und das Verschlüsseln des Hashs mit dem privaten Schlüssel. Jeder, der den öffentlichen Schlüssel zum Entschlüsseln der digitalen Signatur verwendet, ist sicher, dass die digitale Signatur nur von der Person stammen darf, die den privaten Schlüssel besitzt. Darüber hinaus kann der Empfänger einen Hash der Daten mit demselben Algorithmus wie dem Absender berechnen, und wenn der berechnete Hash mit dem in der digitalen Signatur gesendeten übereinstimmt, kann der Empfänger sicher sein, dass die Daten nach der digitalen Signatur nicht geändert wurden.

Ein Nachteil der Verwendung einer PKI für die Datenverschlüsselung mit hohem Volumen ist die relativ langsame Leistung. Aufgrund der intensiven Mathematik kann die Verschlüsselung und Entschlüsselung von Daten mithilfe einer asymmetrischen Verschlüsselung, die von einem Schlüsselpaar abhängt, bis zu 1.000 Mal langsamer sein als Verschlüsselung und Entschlüsselung mithilfe einer symmetrischen Verschlüsselung, die nur von einem einzelnen Schlüssel abhängt. TLS verwendet daher eine PKI nur zum Generieren digitaler Signaturen und zum Aushandeln des sitzungsspezifischen Einzelschlüssels, der sowohl vom Client als auch vom Server für die Massendatenverschlüsselung und -entschlüsselung verwendet wird. TLS unterstützt eine Vielzahl von symmetrischen Schlüsselchiffre, und weitere Verschlüsselungen können in Zukunft hinzugefügt werden.

Weitere Informationen zum TLS-Handshake-Protokoll finden Sie unter TLS Handshake Protocol.

Weitere Informationen zur Kryptografie hinter dem TLS-Protokoll finden Sie unter Cryptography Essentials.

X.509-Zertifikate

Ein kritisches Problem, das von einer PKI behandelt werden muss, ist die Fähigkeit, der Authentizität des verwendeten öffentlichen Schlüssels zu vertrauen. Wenn Sie einen öffentlichen Schlüssel verwenden, der für ein Unternehmen ausgestellt wurde, mit dem Sie Geschäfte machen möchten, möchten Sie sicher sein, dass der Schlüssel tatsächlich zum Unternehmen gehört, anstatt zu einem Thief, der Ihre Kreditkartennummer ermitteln möchte.

Um die Identität eines Prinzipals zu gewährleisten, das ein Schlüsselpaar enthält, wird der Prinzipal von einer Zertifizierungsstelle (CA) ein X.509-Zertifikat ausgestellt. Dieses Zertifikat enthält Informationen, die den Prinzipal identifizieren, den öffentlichen Schlüssel des Prinzipals enthalten und von der Zertifizierungsstelle digital signiert werden. Diese digitale Signatur weist darauf hin, dass die Zertifizierungsstelle der Ansicht ist, dass der öffentliche Schlüssel, der im Zertifikat enthalten ist, wirklich zum Prinzipal gehört, der vom Zertifikat identifiziert wird.

Und wie vertrauen Sie der Zertifizierungsstelle? Da die Zertifizierungsstelle selbst ein X.509-Zertifikat enthält, das von einer Zertifizierungsstelle auf höherer Ebene signiert wurde. Diese Kette von Zertifikatsignaturen wird fortgesetzt, bis sie eine Stammzertifizierungsstelle erreicht, bei der es sich um eine Zertifizierungsstelle handelt, die eigene Zertifikate signiert. Wenn Sie der Integrität der Stammzertifizierungsstelle eines Zertifikats vertrauen, sollten Sie der Echtheit des Zertifikats selbst vertrauen können. Daher ist die Auswahl von Stamm-CAs, denen Sie vertrauen möchten, eine wichtige Aufgabe für einen Systemadministrator.

Clientzertifikate

Als die Protokolle der Sicherheitstransportschicht zum ersten Mal entstanden sind, sollte deren Hauptzweck darin bestehen, sicherzustellen, dass ein Client eine Verbindung mit einem authentischen Server herstellt und die Privatsphäre der Daten während der Übertragung schützt. SSL 3.0 und TLS 1.0 enthalten jedoch auch Unterstützung für die Übertragung des Zertifikats eines Clients während des Handshakes des Protokolls. Dieses optionale Feature ermöglicht die gegenseitige Authentifizierung des Clients und Servers.

Die Entscheidung, ob ein Clientzertifikat verwendet werden soll, sollte im Kontext der Anwendung getroffen werden. Clientzertifikate sind nicht erforderlich, wenn die primäre Anforderung die Authentifizierung des Servers ist. Wenn die Clientauthentifizierung jedoch unerlässlich ist, kann das Zertifikat eines Clients verwendet werden, anstatt auf die benutzerdefinierte Authentifizierung innerhalb der Anwendung zu vertrauen. Die Verwendung von Clientzertifikaten ist gegenüber der benutzerdefinierten Authentifizierung vorzuziehen, da benutzern ein Szenario für einmaliges Anmelden gewährt wird.

Verwenden von TLS in COM

TLS unterstützt nur die Identitätswechselebene (RPC_C_IMP_LEVEL_IMPERSONATE) des Identitätswechsels. Wenn COM TLS als Authentifizierungsdienst für einen Proxy aushandelt, legt COM die Identitätswechselstufe unabhängig vom Prozessstandard fest. Damit der Identitätswechsel in TLS ordnungsgemäß funktioniert, muss der Client dem Server ein X.509-Zertifikat bereitstellen, und der Server muss dieses Zertifikat einem bestimmten Benutzerkonto auf dem Server zugeordnet haben. Weitere Informationen finden Sie in der Schritt-für-Schritt-Anleitung zum Zuordnen von Zertifikaten zu Benutzerkonten.

TLS unterstützt Mantelnnicht. Wenn in einem CoInitializeSecurity- oder einem IClientSecurity::SetBlanket Aufruf ein Verschließen angegeben wird, wird E_INVALIDARG zurückgegeben.

TLS funktioniert nicht mit der Authentifizierungsebene, die auf "None" festgelegt ist. Der Handshake zwischen Client und Server untersucht die von jedem festgelegte Authentifizierungsstufe und wählt die höhere Sicherheitseinstellung für die Verbindung aus.

Die Sicherheitsparameter für TLS können durch Aufrufen von CoInitializeSecurity und CoSetProxyBlanket-festgelegt werden. In den folgenden Abschnitten werden die Nuancen beim Tätigen dieser Anrufe beschrieben.

So legt ein Server die Sicherheitsdecken fest

Wenn ein Server TLS verwenden möchte, muss er Schannel (RPC_C_AUTHN_GSS_SCHANNEL) als Authentifizierungsdienst im asAuthSvc Parameter von CoInitializeSecurityangeben. Um zu verhindern, dass Clients mithilfe eines weniger sicheren Authentifizierungsdiensts eine Verbindung mit dem Server herstellen, sollte der Server nur Schannel als Authentifizierungsdienst angeben, wenn er CoInitializeSecurityaufruft. Der Server kann die Sicherheitsdecken nicht ändern, nachdem er CoInitializeSecurityaufgerufen hat.

Um TLS zu verwenden, sollten die folgenden Parameter angegeben werden, wenn ein Server CoInitializeSecurityaufruft:

  • pVoid- sollte entweder ein Zeiger auf ein IAccessControl-Objekt oder ein Zeiger auf eine SECURITY_DESCRIPTORsein. Es sollte nicht NULL- oder ein Zeiger auf eine AppID sein.
  • cAuthSvc- darf nicht 0 oder -1 sein. COM-Server wählen nie Schannel aus, wenn cAuthSvc--1 ist.
  • asAuthSvc muss Schannel als möglicher Authentifizierungsdienst angeben. Dies geschieht durch Festlegen der folgenden SOLE_AUTHENTICATION_SERVICE Parameter für das Schannel-Mitglied der SOLE_AUTHENTICATION_LIST:
    • dwAuthnSvc- muss RPC_C_AUTHN_GSS_SCHANNEL sein.
    • dwAuthzSvc- sollte RPC_C_AUTHZ_NONE werden. Derzeit wird sie ignoriert.
    • pPrincipalName muss ein Zeiger auf eine CERT_CONTEXTsein, die als Zeiger auf OLECHAR umgestellt wird, der das X.509-Zertifikat des Servers darstellt.
  • dwAuthnLevel- gibt die Mindestauthentifizierungsebene an, die von Clients für eine erfolgreiche Verbindung akzeptiert wird. Es kann nicht RPC_C_AUTHN_LEVEL_NONE werden.
  • dwCapabilities- sollte nicht das EOAC_APPID Flag festgelegt haben. Das EOAC_ACCESS_CONTROL Flag sollte festgelegt werden, wenn pVoid- auf ein IAccessControl--Objekt verweist; sie sollte nicht festgelegt werden, wenn pVoid- auf einen SECURITY_DESCRIPTOR zeigt. Weitere Flags, die festgelegt werden können, finden Sie unter CoInitializeSecurity.

Weitere Informationen zur Verwendung von CoInitializeSecurityfinden Sie unter Festlegen der prozessweiten Sicherheit mit CoInitializeSecurity.

So legt ein Client die Sicherheitsdecken fest

Wenn ein Client TLS verwenden möchte, muss er Schannel (RPC_C_AUTHN_GSS_SCHANNEL) in der Liste der Authentifizierungsdienste im pAuthList Parameter von CoInitializeSecurityangeben. Wenn Schannel nicht als möglicher Authentifizierungsdienst angegeben wird, wenn CoInitializeSecurity aufgerufen wird, schlägt ein späterer Aufruf von CoSetProxyBlanket (oder IClientSecurity::SetBlanket) fehl, wenn versucht wird, Schannel als Authentifizierungsdienst anzugeben.

Die folgenden Parameter sollten angegeben werden, wenn ein Client CoInitializeSecurityaufruft:

  • dwAuthnLevel- gibt die Standardauthentifizierungsebene an, die der Client verwenden möchte. Es kann nicht RPC_C_AUTHN_LEVEL_NONE werden.
  • dwImpLevel- muss RPC_C_IMP_LEVEL_IMPERSONATE sein.
  • pAuthList- müssen die folgenden SOLE_AUTHENTICATION_INFO Parameter als Mitglied der Liste aufweisen:
    • dwAuthnSvc- muss RPC_C_AUTHN_GSS_SCHANNEL sein.
    • dwAuthzSvc- muss RPC_C_AUTHZ_NONE sein.
    • pAuthInfo ein Zeiger auf eine CERT_CONTEXTist, wird als Zeiger auf "void" umgestellt, der das X.509-Zertifikat des Clients darstellt. Wenn der Client kein Zertifikat besitzt oder sein Zertifikat nicht auf dem Server präsentieren möchte, muss pAuthInfo-NULL- sein, und es wird versucht, eine anonyme Verbindung mit dem Server herzustellen.
  • dwCapabilities ist eine Reihe von Flags, die zusätzliche Clientfunktionen angeben. Informationen dazu, welche Flags festgelegt werden sollen, finden Sie unter CoInitializeSecurity.

Weitere Informationen zur Verwendung von CoInitializeSecurityfinden Sie unter Festlegen der prozessweiten Sicherheit mit CoInitializeSecurity.

Wie ein Client die Sicherheitsdecken ändert

Wenn ein Client TLS verwenden möchte, aber die Sicherheitsbeschriftung ändern möchte, nachdem CoInitializeSecurityaufgerufen wurde, muss er entweder CoSetProxyBlanket oder IClientSecurity::SetBlanket mit Parametern aufrufen, die denen ähneln, die im Aufruf von CoInitializeSecurityverwendet werden, wobei die folgenden Unterschiede bestehen:

  • pServerPrincName- gibt den Prinzipalnamen des Servers im msstd- oder fullsic-Format an. Informationen zu diesen Formaten finden Sie unter Prinzipalnamen. Wenn der Client über das X.509-Zertifikat des Servers verfügt, kann er den Prinzipalnamen finden, indem er RpcCertGeneratePrincipalNameaufruft.
  • pAuthInfo- ist ein Zeiger auf eine CERT_CONTEXT, die als Zeiger auf RPC_AUTH_IDENTITY_HANDLE, die das X.509-Zertifikat des Clients darstellt. Wenn der Client kein Zertifikat besitzt oder sein Zertifikat nicht auf dem Server präsentieren möchte, muss pAuthInfo-NULL- sein, und es wird versucht, eine anonyme Verbindung mit dem Server herzustellen.
  • dwCapabilities besteht aus Flags, die zusätzliche Clientfunktionen angeben. Es können nur vier Flags verwendet werden, um Die Einstellungen für Sicherheitsdecken zu ändern: EOAC_DEFAULT, EOAC_MUTUAL_AUTH, EOAC_ANY_AUTHORITY (diese Kennzeichnung ist veraltet) und EOAC_MAKE_FULLSIC. Weitere Informationen finden Sie unter CoSetProxyBlanket.

Weitere Informationen zur Verwendung von CoSetProxyBlanketfinden Sie unter Festlegen der Sicherheit auf der Schnittstellenproxyebene.

Beispiel: Client ändert die Sicherheitsdecken

Das folgende Beispiel zeigt, wie ein Client die Sicherheitsdecken ändern kann, um eine Anforderung vom Server für den Client zur Bereitstellung seines X.509-Zertifikats aufzunehmen. Fehlerbehandlungscode wird aus Platzgründen weggelassen.

void ClientChangesSecurity ()
{
  HCRYPTPROV                   provider           = 0;
  HCERTSTORE                   cert_store         = NULL;
  PCCERT_CONTEXT               client_cert        = NULL;
  PCCERT_CONTEXT               server_cert        = NULL;
  WCHAR                        *server_princ_name = NULL;
  ISecret                      *pSecret           = NULL;
  MULTI_QI                     server_instance;
  COSERVERINFO                 server_machine;
  SOLE_AUTHENTICATION_LIST     auth_list;
  SOLE_AUTHENTICATION_INFO     auth_info[1];



  // Specify all the authentication info. 
  // The client is willing to connect using SChannel,
  //   with no client certificate.
  auth_list.cAuthInfo     = 1;
  auth_list.aAuthInfo     = auth_info;
  auth_info[0].dwAuthnSvc = RPC_C_AUTHN_GSS_SCHANNEL;
  auth_info[0].dwAuthzSvc = RPC_C_AUTHZ_NONE;
  auth_info[0].pAuthInfo  = NULL;  // No certificate

  // Initialize client security with no client certificate.
  CoInitializeSecurity( NULL, -1, NULL, NULL,
                        RPC_C_AUTHN_LEVEL_PKT,
                        RPC_C_IMP_LEVEL_IMPERSONATE, &auth_list,
                        EOAC_NONE, NULL );
  
  // Specify info for the proxy.
  server_instance = {&IID_ISecret, NULL, S_OK};
  server_machine  = {0, L"ServerMachineName", NULL, 0};
  
  // Create a proxy.
  CoCreateInstanceEx( CLSID_Secret, NULL, CLSCTX_REMOTE_SERVER, 
                      &server_machine, 1, &server_instance);
  pSecret = (ISecret *) server_instance.pItf;

  //** The client obtained the server's certificate during the handshake.
  //** The server requests a certificate from the client.

  // Get the default certificate provider.
  CryptAcquireContext( &provider, NULL, NULL, PROV_RSA_SCHANNEL, 0 );

  // Open the certificate store.
  cert_store = CertOpenSystemStore( provider, L"my" );

  // Find the client's certificate.
  client_cert = 
    CertFindCertificateInStore( cert_store,
                                X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
                                0,
                                CERT_FIND_SUBJECT_STR,
                                L"ClientName",  // Use the principal name
                                NULL );

  // Find the fullsic principal name of the server.
  RpcCertGeneratePrincipalName( server_cert, RPC_C_FULL_CERT_CHAIN, 
                                &server_princ_name );

  // Change the client's security: 
  // Increase the authentication level and attach a certificate.
  CoSetProxyBlanket( pSecret, RPC_C_AUTHN_GSS_SCHANNEL,
                     RPC_C_AUTHZ_NONE,
                     server_princ_name, RPC_C_AUTHN_LEVEL_PKT_PRIVACY,
                     RPC_C_IMP_LEVEL_IMPERSONATE, 
                     (RPC_AUTH_IDENTITY_HANDLE *) client_cert,
                     EOAC_NONE );

  cleanup:
  if (server_princ_name != NULL)
    RpcStringFree( &server_princ_name );
  if (client_cert != NULL)
    CertFreeCertificateContext(client_cert);
  if (server_cert != NULL)
    CertFreeCertificateContext(server_cert);
  if (cert_store != NULL)
    CertCloseStore( cert_store, CERT_CLOSE_STORE_CHECK_FLAG );
  if (provider != 0 )
    CryptReleaseContext( provider, 0 );
  if (pSecret != NULL)
    pSecret->Release();
  CoUninitialize();
}

COM- und Sicherheitspakete