Ошибка SSL: "Полученное сообщение было неожиданным или неправильно отформатировано" для приложения. NET только на одном компьютере c - PullRequest
0 голосов
/ 03 августа 2020

У меня есть приложение. NET Core 3.1 C#, которое вызывает API через HTTPS (и представляет свой publi c ключ как часть получения токена, поскольку этот сертификат позже используется для расшифровки информации, отправленной обратно отдельно ). Практически на всех наших машинах он работает, но на одном компьютере Windows 8.1 мы получаем следующую серию исключений, когда пытаемся первоначально подключиться для токена аутентификации:

The SSL connection could not be established, see inner exception.
---> System.Security.Authentication.AuthenticationException: Authentication failed, see inner exception.
---> System.ComponentModel.Win32Exception (0x80090326): The message received was unexpected or badly formatted.

Исключение составляет выброшено из System.Net.Http.HttpClient.FinishSendAsyncBuffered, поэтому я подозреваю, что это происходит на уровне HTTPS, и наш сертификат здесь в любом случае не имеет отношения.

Наш код для получения токена выглядит так:

Конструктор для службы аутентификации:

  public XXXXAuthService(IXXDbService dbService, XXXXApiConfig config)
        {
            _dbService = dbService;
            _config = config;
            
            // try forcing TLS1.2 for SSL connection exceptions thrown in some operating environments
            ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
            
            _httpClient = new HttpClient {BaseAddress = new Uri(config.BaseUrl)};
            _httpClient.DefaultRequestHeaders.Accept.Clear();
            _httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
        }

Код для получения токена аутентификации:

private async Task<string> GetXXXXBearerToken(string userId, DateTime creationTime)
        {
            var token = await GenerateProviderJwtForXXXX(userId, creationTime);
            var kvp = new List<KeyValuePair<string, string>>
            {
                new KeyValuePair<string, string>("grant_type", "urn:ietf:params:oauth:grant-type:token-exchange"),
                new KeyValuePair<string, string>("subject_token", token),
                new KeyValuePair<string, string>("subject_token_type", "urn:ietf:params:oauth:token-type:jwt")
            };
            var data = new FormUrlEncodedContent(kvp);
            var publicKey = await GetXXXXPublicKey();

            _httpClient.DefaultRequestHeaders.Remove("X-XXXX-Public-Cert");
            _httpClient.DefaultRequestHeaders.Add("X-XXXX-Public-Cert", publicKey);

            var response = await _httpClient.PostAsync("Identity/token", data);
            if (!response.IsSuccessStatusCode)
                throw new Exception("XXXX Token Server Error: " + response.ReasonPhrase);
            var result = await response.Content.ReadAsStringAsync();

            var authResponse = JsonConvert.DeserializeObject<OAuthResponse>(result);

            if (!string.IsNullOrEmpty(authResponse.access_token))
                return authResponse.access_token;

            System.Diagnostics.Trace.WriteLine("Token Exchange Result: " + result);
            if (!string.IsNullOrEmpty(authResponse.error))
            {
                var outcome = new XXX.XXXX.Model.OperationOutcome();
                outcome.Issue.Add(new XXX.XXXX.Model.OperationOutcome.IssueComponent()
                {
                    //some code to throw an error is here
            }

            throw new XXX.XXXX.Rest.XXXXOperationException("Bearer Token Exchange failed", response.StatusCode);
        }

К сожалению, ни один из существующих вопросов / советов нигде в Stack Overflow или остальная часть Интернета, похоже, помогла именно эта ошибка. В основном они связаны с расхождениями в версиях между клиентом и сервером, что, похоже, здесь не так, поскольку я принудительно использую TLS 1.2 (который активен и включен на отказавшей машине).

Интересно, что я могу посетить URL-адрес сервера в браузере через HTTPS нормально, что говорит о том, что проблема в моем коде, а не в машине, но она работает везде.

Я подтвердил, что:

  • Сертификат, который я использую для аутентификации соединения на машине, действителен и имеет цепочку доверия (хотя, как и выше, я не думаю, что мы зашли так далеко, поскольку само соединение TLS не работает)
  • вызываемый нами сервер поддерживает TLS 1.2 (принудительно)
  • Я могу перейти на веб-сайт по URL-адресу независимо через браузер

Есть ли что-то, что мне нужно сделать в код или на машине, чтобы этот вызов работал везде?

Что я пытался решить проблему

  • Установка всех обновлений Windows 8.1 до сегодняшнего дня
  • Принудительное использование TLS 1.2 в коде (см. Пример кода выше)
  • Ограничение виртуальной машины только TLS 1.2

1 Ответ

0 голосов
/ 06 августа 2020

Я мог бы по крайней мере указать вам в правильном направлении…

Те же симптомы
У меня было веб-приложение. NET Core 3.1, работающее на IIS (Windows Server 2012 R2), который получил ту же ошибку и трассировку стека при попытке подключиться к другому серверу с использованием TLS 1.2. У меня также был симптом, когда я мог подключиться к браузеру (Chrome), но не к приложению. (Было бы интересно посмотреть, работает ли браузер Inte rnet Explorer.)

Root Причина
Рукопожатие TLS не удалось, потому что два сервера не смогли договориться на общем шифровальном наборе . (Используя Wireshark, я обнаружил, что, когда мое приложение пыталось подключиться, оно предоставляло более ограниченный набор наборов шифров, чем когда браузер Chrome делал вызов.)

Решение
В моем случае я использовал IIS Crypto (небольшой бесплатный инструмент: https://www.nartac.com/Products/IISCrypto/), чтобы включить дополнительные наборы шифров на сервере моего веб-приложения. Я загрузил и запустил IIS Crypto, установил флажки для дополнительных наборов шифров на вкладке «Наборы шифров» и затем перезапустил компьютер.

Один из новых наборов шифров работал с моим приложением и целевым сервером, поэтому рукопожатие TLS было успешным и ошибка была устранена.

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

Дополнение
Если вы хотите дополнительно диагностировать сбой, я бы порекомендовал установить Wireshark (другой бесплатный инструмент: https://www.wireshark.org/#download) на машине с вашим приложением. NET Core. Если проблема связана с ошибкой установления связи TLS, вы увидите сообщение типа: Alert (Уровень: фатальный, Описание: сбой рукопожатия)

Мне помог этот учебник по выходным данным wirehark: https://blog.catchpoint.com/2017/05/12/dissecting-tls-using-wireshark/

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...