Schannel

Пакет безопасности Secure Channel (Schannel), идентификатор службы проверки подлинности которого RPC_C_AUTHN_GSS_SCHANNEL, поддерживает следующие протоколы на основе открытого ключа: SSL (уровень безопасных сокетов) версии 2.0 и 3.0, tls (TLS) 1.0 и частная технология коммуникации (РСТ) 1.0. TLS 1.0 — это стандартизованная, немного измененная версия SSL 3.0, выпущенная в рабочей группе по разработке Интернета (IETF) в документе RFC 2246. Так как протокол TLS был стандартизирован, разработчикам рекомендуется использовать ПРОТОКОЛ TLS, а не SSL. РСТ включается только для обеспечения обратной совместимости и не следует использовать для новой разработки. При использовании пакета безопасности Schannel DCOM автоматически согласовывает лучший протокол в зависимости от возможностей клиента и сервера.

В следующих разделах кратко описывается протокол TLS и его работа с DCOM.

Примечание.

Все сведения о протоколе TLS в этих разделах также применяются к протоколам SSL и PCT.

 

Когда следует использовать TLS

TLS — это единственный вариант безопасности, доступный, если серверы должны подтвердить свое удостоверение анонимным клиентам. Это особенно важно для веб-сайтов, которые хотят участвовать в электронной коммерции, так как это помогает защитить передачу конфиденциальной информации, такой как кредитные карта номера. TLS гарантирует, что клиенты электронной коммерции могут быть уверены, с кем они занимаются бизнесом, так как они получают подтверждение удостоверения сервера. Он также дает серверу электронной коммерции эффективность того, чтобы не беспокоиться о проверке подлинности личности каждого из своих клиентов.

Протокол TLS требует, чтобы все серверы доказали свое удостоверение клиентам. Кроме того, TLS предоставляет возможность подтверждения подлинности клиентов серверам. Эта взаимная проверка подлинности может оказаться полезной при ограничении доступа к определенным веб-страницам в крупной корпоративной интрасети.

TLS поддерживает самые сильные уровни проверки подлинности и предлагает открытую архитектуру, которая позволяет повысить уровень шифрования с течением времени, чтобы поддерживать технологические инновации. TLS — это лучший выбор для сред, где для передаваемых данных необходим самый высокий уровень безопасности.

Краткий обзор работы TLS

TLS основан на инфраструктуре открытых ключей (PKI), которая использует пары открытых и закрытых ключей для включения шифрования данных и установления целостности данных и использования сертификатов X.509 для проверки подлинности.

Многие протоколы безопасности, такие как протокол Kerberos версии 5, зависят от одного ключа для шифрования и расшифровки данных. Таким образом, такие протоколы зависят от безопасного обмена ключами шифрования; в протоколе Kerberos это делается с помощью билетов, полученных из Центра распространения ключей (KDC). Для этого требуется, чтобы все пользователи, использующие протокол Kerberos, регистрировались в KDC, что было бы непрактическим ограничением для веб-сервера электронной коммерции, который предназначен для привлечения миллионов клиентов из всего мира. Таким образом TLS использует PKI, который использует два ключа для шифрования данных", если один ключ пары шифрует данные, только другой ключ пары может расшифровать его. Принципом этого проектирования является то, что шифрование можно выполнять без необходимости безопасного обмена ключами шифрования.

PKI использует метод, в котором один из ключей хранится в закрытом режиме и доступен только субъекту, которому он зарегистрирован, в то время как другой ключ становится общедоступным для всех, кто имеет доступ. Если кто-то хочет отправить закрытое сообщение владельцу пары ключей, сообщение можно зашифровать с помощью открытого ключа, а для расшифровки сообщения можно использовать только закрытый ключ.

Пары ключей также используются для проверки целостности отправленных данных. Для этого владелец пары ключей может присоединить цифровую подпись к данным перед отправкой. Создание цифровой подписи включает вычисление хэша данных и шифрование хэша с помощью закрытого ключа. Любой, кто использует открытый ключ для расшифровки цифровой подписи, гарантирует, что цифровая подпись должна поступать только от человека, которому принадлежит закрытый ключ. Кроме того, получатель может вычислить хэш данных с помощью того же алгоритма, что и отправитель, и если вычисляемый хэш соответствует одному отправленному в цифровой подписи, получатель может быть уверен, что данные не были изменены после того, как он был цифрово подписан.

Одним из недостатков использования PKI для шифрования данных с большим объемом является относительно низкая производительность. Из-за интенсивной математики, шифрования и расшифровки данных с использованием асимметричного шифра, который зависит от пары ключей, может быть до 1000 раз медленнее, чем шифрование и расшифровка с помощью симметричного шифра, который зависит только от одного ключа. Таким образом TLS использует PKI только для создания цифровых подписей и для согласования единого ключа для конкретного сеанса, который будет использоваться как клиентом, так и сервером для массового шифрования и расшифровки данных. TLS поддерживает широкий спектр симметричных шифров с одним ключом, а дополнительные шифры могут быть добавлены в будущем.

Дополнительные сведения о протоколе подтверждения TLS см. в разделе "Протокол подтверждения TLS".

Дополнительные сведения о шифровании протокола TLS см. в статье Cryptography Essentials.

Сертификаты X.509

Критически важной проблемой, которая должна обрабатываться PKI, является возможность доверять подлинности открытого ключа, который используется. Если вы используете открытый ключ, выданный компании, с которой вы хотите заниматься бизнесом, вы хотите быть уверены, что ключ на самом деле принадлежит компании, а не вору, который хочет обнаружить свой кредитный карта номер.

Чтобы гарантировать удостоверение субъекта, включающего пару ключей, субъект выдает сертификат X.509 центром сертификации (ЦС). Этот сертификат содержит сведения, определяющие субъект, содержит открытый ключ субъекта и цифровую подпись ЦС. Эта цифровая подпись указывает, что ЦС считает, что открытый ключ, содержащийся в сертификате, действительно принадлежит субъекту, определяемому сертификатом.

И как вы доверяете ЦС? Так как сам ЦС содержит сертификат X.509, подписанный ЦС более высокого уровня. Эта цепочка подписей сертификатов продолжается до тех пор, пока он не достигнет корневого ЦС, который является ЦС, который подписывает свои собственные сертификаты. Если вы доверяете целостности корневого ЦС сертификата, вы сможете доверять подлинности самого сертификата. Поэтому выбор корневых ЦС, которым вы готовы доверять, является важной обязанностью системного администратора.

Сертификаты клиента

Когда впервые появились протоколы транспортного уровня безопасности, их основной целью было гарантировать, что клиент подключается к аутентичному серверу и помогает защитить конфиденциальность данных во время передачи. Однако ssl 3.0 и TLS 1.0 также включают поддержку передачи сертификата клиента во время подтверждения протокола. Эта необязательная функция обеспечивает взаимную проверку подлинности клиента и сервера.

Решение о том, следует ли использовать сертификат клиента в контексте приложения. Сертификаты клиента не нужны, если основное требование выполняет проверку подлинности сервера. Однако если проверка подлинности клиента необходима, сертификат клиента можно использовать, а не использовать пользовательскую проверку подлинности в приложении. Использование сертификатов клиента предпочтительнее по сравнению с пользовательской проверкой подлинности, так как она предоставляет пользователям сценарий единого входа.

Использование TLS в COM

TLS поддерживает только олицетворение (RPC_C_IMP_LEVEL_IMPERSONATE) уровня олицетворения. Если COM согласовывает TLS как службу проверки подлинности на прокси-сервере, COM устанавливает уровень олицетворения для олицетворения независимо от используемого по умолчанию процесса. Чтобы олицетворение работало правильно в TLS, клиент должен предоставить сертификат X.509 серверу, а сервер должен иметь этот сертификат, сопоставленный с определенной учетной записью пользователя на сервере. Дополнительные сведения см. в пошаговом руководстве по сопоставлению сертификатов с учетными записями пользователей.

TLS не поддерживает маскировку. Если флаг маскировки и TLS указаны в вызове CoInitializeSecurity или IClientSecurity::SetBlanket , E_INVALIDARG будет возвращен.

TLS не работает с уровнем проверки подлинности, заданным как None. Подтверждение между клиентом и сервером проверяет уровень проверки подлинности, заданный каждым из них, и выбирает более высокий параметр безопасности для подключения.

Параметры безопасности для TLS можно задать путем вызова CoInitializeSecurity и CoSetProxyBlanket. В следующих разделах описываются нюансы, связанные с выполнением этих вызовов.

Как сервер задает одеяло безопасности

Если сервер хочет использовать TLS, он должен указать Schannel (RPC_C_AUTHN_GSS_SCHANNEL) в качестве службы проверки подлинности в параметре asAuthSvc coInitializeSecurity. Чтобы предотвратить подключение клиентов к серверу с помощью менее безопасной службы проверки подлинности, сервер должен указать только Schannel в качестве службы проверки подлинности при вызове CoInitializeSecurity. Сервер не может изменить одеяло безопасности после вызова CoInitializeSecurity.

Чтобы использовать TLS, необходимо указать следующие параметры, когда сервер вызывает CoInitializeSecurity:

  • PVoid должен быть указателем на объект IAccessControl или указатель на SECURITY_DESCRIPTOR. Он не должен иметь значение NULL или указатель на AppID.
  • cAuthSvc не может быть 0 или -1. COM-серверы никогда не выбирают Schannel, если cAuthSvcимеет значение -1.
  • asAuthSvc должен указать Schannel в качестве возможной службы проверки подлинности. Это делается путем задания следующих SOLE_AUTHENTICATION_SERVICE параметров для элемента Schannel SOLE_AUTHENTICATION_LIST:
    • dwAuthnSvc должен быть RPC_C_AUTHN_GSS_SCHANNEL.
    • dwAuthzSvc должен быть RPC_C_AUTHZ_NONE. В настоящее время он игнорируется.
    • pPrincipalName должен быть указателем на CERT_CONTEXT, приведение в качестве указателя на OLECHAR, который представляет сертификат X.509 сервера.
  • dwAuthnLevel указывает минимальный уровень проверки подлинности, который будет принят от клиентов для успешного подключения. Это не может быть RPC_C_AUTHN_LEVEL_NONE.
  • DwCapabilities не должен иметь набор флагов EOAC_APPID. Флаг EOAC_ACCESS_CONTROL следует задать, если pVoid указывает на объект IAccessControl; его не следует задавать, если pVoid указывает на SECURITY_DESCRIPTOR. Другие флаги, которые могут быть заданы, см. в разделе CoInitializeSecurity.

Дополнительные сведения об использовании CoInitializeSecurity см. в разделе "Настройка защиты по всей процедуре" с помощью CoInitializeSecurity.

Как клиент задает одеяло безопасности

Если клиент хочет использовать TLS, он должен указать Schannel (RPC_C_AUTHN_GSS_SCHANNEL) в своем списке служб проверки подлинности в параметре pAuthList coInitializeSecurity. Если Schannel не указан в качестве возможной службы проверки подлинности при вызове CoInitializeSecurity, последующий вызов CoSetProxyBlanket (или IClientSecurity::SetBlanket) завершится ошибкой, если он пытается указать Schannel в качестве службы проверки подлинности.

При вызове CoInitializeSecurity клиент должен указывать следующие параметры:

  • DwAuthnLevel указывает уровень проверки подлинности по умолчанию, который клиент хочет использовать. Это не может быть RPC_C_AUTHN_LEVEL_NONE.
  • dwImpLevel должен быть RPC_C_IMP_LEVEL_IMPERSONATE.
  • pAuthList должен иметь следующие SOLE_AUTHENTICATION_INFO параметры в качестве члена списка:
    • dwAuthnSvc должен быть RPC_C_AUTHN_GSS_SCHANNEL.
    • dwAuthzSvc должен быть RPC_C_AUTHZ_NONE.
    • pAuthInfo — это указатель на CERT_CONTEXT, который представляет сертификат X.509 клиента в качестве указателя на пустоту. Если у клиента нет сертификата или не требуется представить сертификат серверу, pAuthInfo должен иметь значение NULL, а анонимное подключение будет предпринята с сервером.
  • dwCapabilities — это набор флагов, указывающих на дополнительные возможности клиента. Сведения о том, какие флаги следует задать, см. в разделе CoInitializeSecurity.

Дополнительные сведения об использовании CoInitializeSecurity см. в разделе "Настройка защиты по всей процедуре" с помощью CoInitializeSecurity.

Как клиент изменяет одеяло безопасности

Если клиент хочет использовать TLS, но измените одеяло безопасности после вызова CoInitializeSecurity, он должен вызвать CoSetProxyBlanket или IClientSecurity::SetBlanket с параметрами, аналогичными параметрам, используемым в вызове CoInitializeSecurity, со следующими различиями:

  • pServerPrincName указывает имя субъекта сервера в формате msstd или fullsic. Сведения об этих форматах см. в разделе "Имена субъектов". Если у клиента есть сертификат X.509 сервера, он может найти имя участника, вызвав RpcCertGeneratePrincipalName.
  • pAuthInfo — это указатель на CERT_CONTEXT, который представляет сертификат X.509 клиента в качестве указателя на RPC_AUTH_IDENTITY_HANDLE. Если у клиента нет сертификата или не требуется представить сертификат серверу, pAuthInfo должен иметь значение NULL, а анонимное подключение будет предпринята с сервером.
  • dwCapabilities состоит из флагов, указывающих на дополнительные возможности клиента. Для изменения параметров безопасности можно использовать только четыре флага: EOAC_DEFAULT, EOAC_MUTUAL_AUTH, EOAC_ANY_AUTHORITY (этот флаг не рекомендуется) и EOAC_MAKE_FULLSIC. Дополнительные сведения см. в разделе CoSetProxyBlanket.

Дополнительные сведения об использовании CoSetProxyBlanket см. в разделе "Настройка безопасности на уровне прокси-сервера интерфейса".

Пример: клиент изменяет одеяло безопасности

В следующем примере показано, как клиент может изменить одеяло безопасности для размещения запроса от сервера, чтобы клиент предоставил свой сертификат X.509. Код обработки ошибок опущен для краткости.

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 и безопасности