Использование самозаверяющего сертификата с .NET HttpWebRequest / Response

Я пытаюсь подключиться к API, который использует самоподписанный сертификат SSL. Я делаю это с использованием объектов .NET HttpWebRequest и HttpWebResponse. И я получаю исключение:

Основное соединение было закрыто: не удалось установить доверительные отношения для безопасного канала SSL / TLS.

Я понимаю, что это значит. И я понимаю, почему .NET считает, что он должен предупредить меня и закрыть соединение. Но в этом случае я хотел бы просто подключиться к API в любом случае, проклятые атаки «человек-в-середине».

Итак, как мне добавить добавление исключения для этого самозаверяющего сертификата? Или можно сказать, что HttpWebRequest / Response не проверяет сертификат вообще? Как мне это сделать?

@Domster: это работает, но вы можете потребовать некоторую защиту, проверив, соответствует ли hash сертификата то, что вы ожидаете. Таким образом, расширенная версия выглядит примерно так (на основе какого-то живого кода, который мы используем):

static readonly byte[] apiCertHash = { 0xZZ, 0xYY, ....}; ///  /// Somewhere in your application's startup/init sequence... ///  void InitPhase() { // Override automatic validation of SSL server certificates. ServicePointManager.ServerCertificateValidationCallback = ValidateServerCertficate; } ///  /// Validates the SSL server certificate. ///  /// An object that contains state information for this /// validation. /// The certificate used to authenticate the remote party. /// The chain of certificate authorities associated with the /// remote certificate. /// One or more errors associated with the remote /// certificate. /// Returns a boolean value that determines whether the specified /// certificate is accepted for authentication; true to accept or false to /// reject. private static bool ValidateServerCertficate( object sender, X509Certificate cert, X509Chain chain, SslPolicyErrors sslPolicyErrors) { if (sslPolicyErrors == SslPolicyErrors.None) { // Good certificate. return true; } log.DebugFormat("SSL certificate error: {0}", sslPolicyErrors); bool certMatch = false; // Assume failure byte[] certHash = cert.GetCertHash(); if (certHash.Length == apiCertHash.Length) { certMatch = true; // Now assume success. for (int idx = 0; idx < certHash.Length; idx++) { if (certHash[idx] != apiCertHash[idx]) { certMatch = false; // No match break; } } } // Return true => allow unauthenticated server, // false => disallow unauthenticated server. return certMatch; } 

Оказывается, если вы просто хотите полностью отключить проверку сертификата, вы можете изменить ServerCertificateValidationCallback на ServicePointManager, например:

 ServicePointManager.ServerCertificateValidationCallback = delegate { return true; }; 

Это подтвердит все сертификаты (включая недействительные, истекшие или самозаверяющие).

Добавьте самоподписанный сертификат в местные доверенные корневые центры сертификации

Вы можете импортировать сертификат, запустив MMC в качестве администратора.

Практическое руководство. Просмотр сертификатов с оснасткой MMC

Обратите внимание, что в .NET 4.5 вы можете переопределить SSL-проверку для самого HttpWebRequest (а не через глобальный делегат, который влияет на все запросы):

http://msdn.microsoft.com/en-us/library/system.net.httpwebrequest.servercertificatevalidationcallback.aspx

 HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(uri); request.ServerCertificateValidationCallback = delegate { return true; }; 

Объем обратного вызова валидации, используемый в ответе Domster, может быть ограничен конкретным запросом, используя параметр отправителя в ServerCertificateValidationCallback . Следующий простой class classа использует эту технику для временного подключения обратного вызова проверки, который выполняется только для данного объекта запроса.

 public class ServerCertificateValidationScope : IDisposable { private readonly RemoteCertificateValidationCallback _callback; public ServerCertificateValidationScope(object request, RemoteCertificateValidationCallback callback) { var previous = ServicePointManager.ServerCertificateValidationCallback; _callback = (sender, certificate, chain, errors) => { if (sender == request) { return callback(sender, certificate, chain, errors); } if (previous != null) { return previous(sender, certificate, chain, errors); } return errors == SslPolicyErrors.None; }; ServicePointManager.ServerCertificateValidationCallback += _callback; } public void Dispose() { ServicePointManager.ServerCertificateValidationCallback -= _callback; } } 

Вышеупомянутый class может использоваться для игнорирования всех ошибок сертификата для конкретного запроса следующим образом:

 var request = WebRequest.Create(uri); using (new ServerCertificateValidationScope(request, delegate { return true; })) { request.GetResponse(); } 

Чтобы добавить в качестве возможной помощи кому-то еще … Если вы хотите, чтобы он предложил пользователю установить самозаверяющий сертификат, вы можете использовать этот код (измененный сверху).

Не требует прав администратора, устанавливает для доверенных профилей локальных пользователей:

  private static bool ValidateServerCertficate( object sender, X509Certificate cert, X509Chain chain, SslPolicyErrors sslPolicyErrors) { if (sslPolicyErrors == SslPolicyErrors.None) { // Good certificate. return true; } Common.Helpers.Logger.Log.Error(string.Format("SSL certificate error: {0}", sslPolicyErrors)); try { using (X509Store store = new X509Store(StoreName.My, StoreLocation.CurrentUser)) { store.Open(OpenFlags.ReadWrite); store.Add(new X509Certificate2(cert)); store.Close(); } return true; } catch (Exception ex) { Common.Helpers.Logger.Log.Error(string.Format("SSL certificate add Error: {0}", ex.Message)); } return false; } 

Это, похоже, хорошо работает для нашего приложения, и если пользователь не нажимает «нет», сообщение не будет работать.

Обновление: 2015-12-11 – Изменено StoreName.Root to StoreName.My – My будет устанавливаться в локальный магазин пользователей вместо Root. Корень на некоторых системах не будет работать, даже если вы «выполняете роль администратора»,

Просто основываясь на ответе от devstuff, чтобы включить тему и эмитента … комментарии приветствуются …

 public class SelfSignedCertificateValidator { private class CertificateAttributes { public string Subject { get; private set; } public string Issuer { get; private set; } public string Thumbprint { get; private set; } public CertificateAttributes(string subject, string issuer, string thumbprint) { Subject = subject; Issuer = issuer; Thumbprint = thumbprint.Trim( new char[] { '\u200e', '\u200f' } // strip any lrt and rlt markers from copy/paste ); } public bool IsMatch(X509Certificate cert) { bool subjectMatches = Subject.Replace(" ", "").Equals(cert.Subject.Replace(" ", ""), StringComparison.InvariantCulture); bool issuerMatches = Issuer.Replace(" ", "").Equals(cert.Issuer.Replace(" ", ""), StringComparison.InvariantCulture); bool thumbprintMatches = Thumbprint == String.Join(" ", cert.GetCertHash().Select(h => h.ToString("x2"))); return subjectMatches && issuerMatches && thumbprintMatches; } } private readonly List __knownSelfSignedCertificates = new List { new CertificateAttributes( // can paste values from "view cert" dialog "CN = subject.company.int", "CN = issuer.company.int", "f6 23 16 3d 5a d8 e5 1e 13 58 85 0a 34 9f d6 d3 c8 23 a8 f4") }; private static bool __createdSingleton = false; public SelfSignedCertificateValidator() { lock (this) { if (__createdSingleton) throw new Exception("Only a single instance can be instanciated."); // Hook in validation of SSL server certificates. ServicePointManager.ServerCertificateValidationCallback += ValidateServerCertficate; __createdSingleton = true; } } ///  /// Validates the SSL server certificate. ///  /// An object that contains state information for this /// validation. /// The certificate used to authenticate the remote party. /// The chain of certificate authorities associated with the /// remote certificate. /// One or more errors associated with the remote /// certificate. /// Returns a boolean value that determines whether the specified /// certificate is accepted for authentication; true to accept or false to /// reject. private bool ValidateServerCertficate( object sender, X509Certificate cert, X509Chain chain, SslPolicyErrors sslPolicyErrors) { if (sslPolicyErrors == SslPolicyErrors.None) return true; // Good certificate. Dbg.WriteLine("SSL certificate error: {0}", sslPolicyErrors); return __knownSelfSignedCertificates.Any(c => c.IsMatch(cert)); } } 

Следует иметь в виду, что наличие ServicePointManager.ServerCertificateValidationCallback, по-видимому, не означает, что проверка CRL и проверка имени сервера не выполняются, это только обеспечивает возможность переопределить их результат. Таким образом, ваша служба может занять некоторое время, чтобы получить CRL, после этого вы узнаете, что не удалось выполнить некоторые проверки.

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

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

Казалось бы, C # может найти сертификат в хранилище машин, даже если он не может использоваться с веб-запросом, и это приводит к тому, что исключение OP вызывается после того, как будет выдан веб-запрос.

  • создать надежный самоподписанный SSL-сертификат для localhost (для использования с Express / Node)
  • Возможно ли иметь сертификат SSL для IP-адреса, а не доменное имя?
  • Как правильно импортировать самоподписанный сертификат в хранилище ключей Java, доступное для всех приложений Java по умолчанию?
  • Получено фатальное предупреждение: handshake_failure через SSLHandshakeException
  • проверка сертификата сервера не удалась. CAfile: /etc/ssl/certs/ca-certificates.crt CRLfile: none
  • Как создать самозаверяющий сертификат с openssl?
  • javax.net.ssl.SSLPeerUnverifiedException: имя хоста не соответствует теме сертификата, предоставленной партнером
  • Java: sun.security.provider.certpath.SunCertPathBuilderException: невозможно найти допустимый путь сертификации для запрошенной цели
  • Не удалось создать путь PKIX: не удалось найти допустимый путь сертификации для запрошенной цели
  • Сертификат клиента SSL в Maven
  • Ошибка SSL: certificate_verify_failed при очистке https://www.thenewboston.com/
  • Interesting Posts

    Как мы можем сопоставить ^ nb ^ n с регулярным выражением Java?

    Процесс перехода от проблемы к коду. Как вы учились?

    Использование командной строки для подключения к беспроводной сети с помощью http-входа

    Невозможно применить объект типа NHibernate.Collection.Generic.PersistentGenericBag к списку

    Как работать с varargs и reflection

    Каким образом Firefox кэширует содержимое формы в любом месте, где я могу восстановить?

    Лучше ли оставить или отключить внешний жесткий диск?

    Поиск нескольких расширений файлов в окне командной строки

    Каковы различия между деревьями сегментов, деревьями интервалов, двоичными индексированными деревьями и деревьями диапазона?

    Поддержка Multi Monitor для Windows 7

    Android – получить детей внутри представления?

    Какие параметры следует искать для уменьшения размера файла .MOV?

    Студия Android добавляет внешний проект для сборки.gradle

    Как грациозно обрабатывать сигнал SIGKILL в Java

    Как удалить Candy Crush Saga из Windows 10?

    Давайте будем гением компьютера.