Проблема SSL-сертификат C # - PullRequest
       29

Проблема SSL-сертификат C #

5 голосов
/ 19 апреля 2011

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

РЕШЕНИЕ: Приведенный ниже код должен выполняться только один раз за все время выполнения приложения.При этом мы устанавливаем свойства ServerCertification и SSL, которые будут использоваться всякий раз, когда будет вызван запрос:

        public static void setSSLCertificate()
    {
        clientCert = new X509Certificate2(AUTHEN_CERT_FILE); // Pointing to the .crt file that will be used for server certificate verification by the client
        System.Net.ServicePointManager.ServerCertificateValidationCallback += new System.Net.Security.RemoteCertificateValidationCallback(customXertificateValidation);
    }

    public static bool customXertificateValidation(Object sender, X509Certificate certificate, X509Chain chain, System.Net.Security.SslPolicyErrors sslPoicyErrors)
    {
        switch (sslPoicyErrors)
        {
            case System.Net.Security.SslPolicyErrors.RemoteCertificateChainErrors:
            case System.Net.Security.SslPolicyErrors.RemoteCertificateNameMismatch:
            case System.Net.Security.SslPolicyErrors.RemoteCertificateNotAvailable:
                break;
        }

        return clientCert.Verify();  // Perform the Verification and sends the result
    }

Запрос выполняется обычно, как мы делаем без реализации SSL.Вот код почтового запроса:

        private static String SendPost(String uri, String post_data)
    {
        String resData = "";
        HttpWebRequest request = (HttpWebRequest)WebRequest.Create(uri);
        request.KeepAlive = false;
        request.ProtocolVersion = HttpVersion.Version10;
        request.ContentType = "application/x-www-form-urlencoded";
        request.Method = "POST";

        // turn request string into byte[]
        byte[] postBytes = Encoding.ASCII.GetBytes(post_data);

        Stream requestStream = null;

        try
        {
            // Send it
            request.ContentLength = postBytes.Length;
            requestStream = request.GetRequestStream();
            requestStream.Write(postBytes, 0, postBytes.Length);
        }
        catch (WebException we)
        {   // If SSL throws exception that will be handled here
            if (we.Status == WebExceptionStatus.TrustFailure)
                throw new Exception("Exception Sending Data POST : Fail to verify server " + we.Message);
        }
        catch (Exception e)
        {
            throw new Exception("Exception Sending Data POST : " + e.Message, e.InnerException);
        }
        finally
        {
            if (requestStream != null)
                requestStream.Close();
        }

        // Get the response
        HttpWebResponse response = null;
        try
        {
            response = (HttpWebResponse)request.GetResponse();
            if (response == null)
                return "";
            StreamReader sr = new StreamReader(response.GetResponseStream());
            resData = sr.ReadToEnd().Trim();
            sr.Close();
        }
        catch (Exception e)
        {
            throw new Exception("Error receiving response from POST : " + e.Message, e.InnerException);
        }
        finally
        {
            if (response != null)
                response.Close();
        }

        return resData;
    }

Особая благодарность Дипти Мехте, чье объяснение помогло мне в значительной степени достичь цели, приняв сертификат сервера.Она помогла мне решить мои проблемы.Я наконец нашел, как проверить сертификат сервера, используя файл .crt клиентом.

Надеюсь, это кому-нибудь поможет.

Спасибо

Ответы [ 3 ]

11 голосов
/ 19 апреля 2011

Когда вы заходите на сайт HTTPS, вы, вероятно, получаете диалоговое окно с вопросом, хотите ли вы доверять сертификату, предоставленному веб-сервером.Таким образом, ответственность за принятие сертификата несет пользователь.Давайте вернемся к сценарию веб-службы, если вы хотите вызвать веб-службу, расположенную на веб-сервере, который использует SSL и HTTPS, существует проблема.

Когда вы совершаете вызов из кода, диалоговое окно не появляется и спрашивает, доверяете ли вы сертификату ;возможно, вы получите следующее исключение:

Произошло необработанное исключение типа 'System.Net.WebException' в system.dll

Дополнительная информация: Основное соединение было закрыто: Возможноне устанавливать доверительные отношения с удаленным сервером.

Но есть решение этой проблемы, вы можете решить это в своем коде, создав собственный класс CertificatePolicy (который реализует интерфейс ICertificatePolicy).В этом классе вам нужно написать свою собственную функцию CheckValidationResult, которая должна возвращать true или false, как если бы вы нажимали да или нет в диалоговом окне.Для целей разработки я создал следующий класс, который принимает все сертификаты, поэтому вы больше не получите неприятного WebException:

public class TrustAllCertificatePolicy : System.Net.ICertificatePolicy
{
  public TrustAllCertificatePolicy() 
  {}

  public bool CheckValidationResult(ServicePoint sp, X509Certificate cert,WebRequest req, int problem)
  {
    return true;
  }
}

Как видите, функция CheckValidationResult всегда возвращает true, поэтому все сертификаты будутбыть доверенным.Если вы хотите сделать этот класс немного более безопасным, вы можете добавить дополнительные проверки, например, с помощью параметра X509Certificate.Чтобы использовать этот CertificatePolicy, вы должны указать ServicePointManager использовать его:

System.Net.ServicePointManager.CertificatePolicy = new TrustAllCertificatePolicy();

Это необходимо сделать (один раз в течение жизненного цикла приложения) перед выполнением вызова веб-службы.

1 голос
/ 05 июля 2012

Привет твд,

Я не уверен, что решение, которое вы предоставляете, является действительным решением проблемы. Кроме того, некоторые ваши комментарии относительно HttpWebRequest.ClientCertificates указывают на это.

Во-первых, важно различать сервер, проверяющий сертификат клиента, и клиент, проверяющий сертификат сервера. Коллекция HttpWebRequest.ClientCertificates используется для отправки клиентских сертификатов на сервер, чтобы сервер мог проверить, кто является клиентом. Ваш вопрос (насколько я понимаю) состоял в том, как сертификат сервера, который не проходит проверку по умолчанию (например, самозаверяющий сертификат), можно проверить по сертификату, локально хранящемуся на клиенте.

В этом случае решением действительно является использование System.Net.ServicePointManager.ServerCertificateValidationCallback и предоставление пользовательской проверки. Однако ваш метод проверки кажется неправильным: он проверяет локальный сертификат и не заботится о сертификате, отправленном сервером. Я бы использовал что-то вроде этого:

public static bool customXertificateValidation(
    Object sender, X509Certificate certificate, 
    X509Chain chain, SslPolicyErrors sslPolicyErrors)
{
    if (sslPolicyErrors == SslPolicyErrors.None)
        return true;

    return clientCert.Equals(certificate);
};

Этот метод гарантирует, что если сертификат сервера пройдет проверку по умолчанию (без ошибок), он примет его, а затем сравнивает локальную клиентскую копию сертификата с тем, что было предоставлено сервером. Только если тест Equals успешно пройден, клиент может безопасно продолжить работу.

0 голосов
/ 19 апреля 2011

Под «подтверждать» вы подразумеваете «подтвердить»?В этом случае .crt недостаточно, он содержит только открытый ключ.Вам нужен закрытый ключ, чтобы аутентифицировать себя и поместить его в ClientCertificates.Вы можете либо прочитать файл из файла .pfx, либо импортировать его в контейнер сертификатов и использовать его оттуда.

...