С# HttpWebRequest SEC_I_RENEGOTIATE Периодические ошибки
Я работаю над функциями входа/выхода с использованием SSL POST-вызовов в приложении С# (.Net framework 3.5). Получение ответа с сервера через HttpWebRequest:: BeginGetResponse() работает 80% времени, но другие 20% периодически перебрасываются:
The request was aborted: Could not create SSL/TLS secure channel.
Я включил трассировку SSL, используя предложенную статью из другого вопроса. Это создало два разных шаблона в запросах.
Похоже, что во время выполнения ошибка:
System.Net Error: 0 : [3680] Decrypt returned SEC_I_RENEGOTIATE.
что вызывает повтор инициализации контекста безопасности. Когда это произойдет, и это будет успешным, вот вывод (отметили, что я пропустил фактический адрес):
System.Net Error: 0 : [3680] Decrypt returned SEC_I_RENEGOTIATE.
System.Net Information: 0 : [3680] InitializeSecurityContext(credential = System.Net.SafeFreeCredential_SECURITY, context = 4bec0d0:4c0a8a8, targetName = [omitted].com, inFlags = ReplayDetect, SequenceDetect, Confidentiality, AllocateMemory, InitManualCredValidation)
System.Net Information: 0 : [3680] InitializeSecurityContext(In-Buffer length=0, Out-Buffer length=78, returned code=ContinueNeeded).
System.Net Information: 0 : [7148] InitializeSecurityContext(credential = System.Net.SafeFreeCredential_SECURITY, context = 4bec0d0:4c0a8a8, targetName = [omitted].com, inFlags = ReplayDetect, SequenceDetect, Confidentiality, AllocateMemory, InitManualCredValidation)
System.Net Information: 0 : [7148] InitializeSecurityContext(In-Buffers count=2, Out-Buffer length=0, returned code=ContinueNeeded).
System.Net Information: 0 : [7148] InitializeSecurityContext(credential = System.Net.SafeFreeCredential_SECURITY, context = 4bec0d0:4c0a8a8, targetName = [omitted].com, inFlags = ReplayDetect, SequenceDetect, Confidentiality, AllocateMemory, InitManualCredValidation)
System.Net Information: 0 : [7148] InitializeSecurityContext(In-Buffers count=2, Out-Buffer length=0, returned code=ContinueNeeded).
System.Net Information: 0 : [7148] InitializeSecurityContext(credential = System.Net.SafeFreeCredential_SECURITY, context = 4bec0d0:4c0a8a8, targetName = [omitted].com, inFlags = ReplayDetect, SequenceDetect, Confidentiality, AllocateMemory, InitManualCredValidation)
System.Net Information: 0 : [7148] InitializeSecurityContext(In-Buffers count=2, Out-Buffer length=1259, returned code=ContinueNeeded).
System.Net Information: 0 : [7148] InitializeSecurityContext(credential = System.Net.SafeFreeCredential_SECURITY, context = 4bec0d0:4c0a8a8, targetName = [omitted].com, inFlags = ReplayDetect, SequenceDetect, Confidentiality, AllocateMemory, InitManualCredValidation)
System.Net Information: 0 : [7148] InitializeSecurityContext(In-Buffers count=2, Out-Buffer length=0, returned code=ContinueNeeded).
System.Net Information: 0 : [7148] InitializeSecurityContext(credential = System.Net.SafeFreeCredential_SECURITY, context = 4bec0d0:4c0a8a8, targetName = [omitted].com, inFlags = ReplayDetect, SequenceDetect, Confidentiality, AllocateMemory, InitManualCredValidation)
System.Net Information: 0 : [7148] InitializeSecurityContext(In-Buffers count=2, Out-Buffer length=0, returned code=OK).
System.Net Information: 0 : [7148] Remote certificate: [Version]
V1
При сбое:
System.Net Error: 0 : [3680] Decrypt returned SEC_I_RENEGOTIATE.
System.Net Information: 0 : [3680] InitializeSecurityContext(credential = System.Net.SafeFreeCredential_SECURITY, context = 4bec0d0:4c0ab50, targetName = [omitted].com, inFlags = ReplayDetect, SequenceDetect, Confidentiality, AllocateMemory, InitManualCredValidation)
System.Net Information: 0 : [3680] InitializeSecurityContext(In-Buffer length=0, Out-Buffer length=78, returned code=ContinueNeeded).
System.Net Error: 0 : [3680] Exception in the HttpWebRequest#20730349:: - The request was aborted: Could not create SSL/TLS secure channel.
System.Net Verbose: 0 : [3680] HttpWebRequest#20730349::EndGetResponse()
System.Net Error: 0 : [3680] Exception in the HttpWebRequest#20730349::EndGetResponse - The request was aborted: Could not create SSL/TLS secure channel.
Я могу, конечно, поймать это исключение, но что такое правильная обработка?
Есть ли способ для моего приложения предотвратить (или правильно обработать) эти ошибки? Когда это случается, это кажется постоянной ошибкой какое-то время, но затем снова начинает работать после некоторого неопределенного количества запросов.
Спасибо!
Ответы
Ответ 1
(Для исходного ответа см. ниже.)
Обычно эта ошибка означает, что ваш клиент и сервер не настроены на использование одного и того же типа шифрования. Часто самый простой способ его исправления явно устанавливает версию для использования в клиенте.
Если вы используете .NET 4.5 или новее, вот варианты, которые нужно попробовать, чтобы от самого безопасного до наименее безопасного:
-
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
-
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls11;
-
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls;
Если вы используете .NET 4.0 или старше, вы можете использовать только последнюю строку выше, поскольку эти версии не поддерживают TLSv1.1 и TLSv1.2. Настоятельно рекомендуется обновить до .NET 4.5, чтобы воспользоваться поддержкой TLSv1.2.
В дополнение к настройке свойства SecurityProtocol
вам также может потребоваться установить: ServicePointManager.Expect100Continue = true;
Если ни одна из этих настроек не помогает, это, вероятно, означает, что ваш сервер поддерживает только SSLv3 (или, что еще хуже, SSLv2). Если это так, обновите свой сервер! SSLv3 сломан и больше не должен использоваться.
SSLv3 НЕ ДОЛЖЕН считаться безопасным. НЕ используйте эти настройки! Хотя это был правильный ответ в 2011 году, он остается здесь только по историческим причинам.
Перед запросом необходимо добавить следующие строки кода:
ServicePointManager.Expect100Continue = true;
ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3;
Из того, что я видел, более старые версии (.NET 2 и/или Windows xp/2003 и старше) использовали их как параметры по умолчанию, но более новые версии (.NET 3 и/или Windows Vista/2008 и новее) не.забастовкa >
Ответ 2
Это не объяснение и не истинное решение: это просто самый прагматичный способ решения этой проблемы, который мы нашли в нашем случае (выполнение SOF-запроса WCF через HTTPS с использованием SSL-сертификата клиента с Apache и Java-сервер).
Catch SecurityNegotiationException и повторить попытку на месте (т.е. вместо того, чтобы перерабатывать сообщение, если используете msmq), и подавить сообщение об исключении в этом случае. Просто включите счетчик производительности или что-то простое, чтобы вы могли отслеживать, становится ли проблема хуже.
В конце концов, это всего лишь одна из тех врожденных проблем, связанных с сетью, с которыми ваш код должен справиться.
Ответ 3
Я думал, что поделился своим опытом, поскольку в последнее время я читал большинство вопросов о стеке:
Другим подходом к этому, который я видел, является рассмотрение HTTP Keep-Alive. В последних версиях .Net он использует HTTP 1.1 по умолчанию, что означает, что Keep-Alive установлен на true и Expect100.
Из моего опыта это создает прилипание ресурсов ниже по течению и не является надежным за балансировщиком нагрузки.
Два варианта
1) Восстановите и повторите попытку, которая кажется слегка вонючей. Однако, как упоминает Khanfx, сетевые проблемы могут возникать ergo: заблуждения сетей. TOPAZ - один из способов решения этой проблемы: https://msdn.microsoft.com/en-us/library/hh680901%28v=pandp.50%29.aspx?f=255&MSPPError=-2147217396
2) Отключите Keep-Alive либо через HttpwebRequest, либо испустив заголовок закрытия соединения, если используете HttpClient.
НТН.