Рекомендации по использованию ServerCertificateValidationCallback
Я работаю над проектом, который использует некоторую HTTP-связь между двумя серверными серверами. Серверы используют сертификаты X509 для аутентификации. Излишне говорить, что когда сервер A (клиент) устанавливает соединение с сервером B (сервер), существует ошибка проверки SSL/TLS, поскольку используемые сертификаты не принадлежат доверенным сторонним организациям.
Обычно способ обращения с ним - это ServicePointManager.ServerCertificateValidationCallback
, например:
ServicePointManager.ServerCertificateValidationCallback +=
(sender, cert, chain, error) =>
{
return cert.GetCertHashString() == "xxxxxxxxxxxxxxxx";
};
Этот подход работает, за исключением того, что он не идеален. По сути, это процедура переопределения проверки для КАЖДОГО HTTP-запроса, выполняемого приложением. Таким образом, если другой класс попытается запустить HTTP-запрос, он не удастся. Кроме того, если другой класс переопределяет ServicePointManager.ServerCertificateValidationCallback
для своих целей, то мое сообщение начинает выходить из строя внезапно.
Единственное решение, которое приходит на ум, создает отдельный AppDomain для выполнения клиентских HTTP-запросов. Это будет работать, но на самом деле - глупо делать это только для того, чтобы можно было выполнять HTTP-запросы. Накладные расходы будут ошеломляющими.
С учетом этого, кто-нибудь исследовал, есть ли в .NET более эффективная практика, которая позволила бы получать доступ к веб-службам при обработке проверки SSL/TLS клиента, не затрагивая других веб-клиентов?
Ответы
Ответ 1
Допустимой (безопасной) методологией, работающей в .NET 4.5+, является использование HttpWebRequest.ServerCertificateValidationCallback
. Назначение этого обратного вызова для конкретного экземпляра запроса изменяет логику проверки только для запроса, не влияя на другие запросы.
var request = (HttpWebRequest)WebRequest.Create("https://...");
request.ServerCertificateValidationCallback +=
(sender, cert, chain, error) =>
{
return cert.GetCertHashString() == "xxxxxxxxxxxxxxxx";
};
Ответ 2
Прямой подход для этого сценария должен заключаться в установке двух самогенерируемых сертификатов в доверенных корневых хранилищах на клиентских машинах. Когда вы это сделаете, вы получите предупреждение о безопасности, потому что сертификаты не могут быть аутентифицированы с помощью Thawte или аналогичных, но после того, как эта нормальная безопасная связь должна работать. IIRC, вам необходимо установить полную версию (как для открытого, так и для частного) в доверенном корне, чтобы это работало.
Ответ 3
Альтернатива для кода, который не использует HttpWebRequest, и для сред, где вы не можете установить доверенные сертификаты в хранилище сертификатов: Проверьте параметр ошибки обратного вызова, который будет содержать любую ошибку, обнаруженную до обратного вызова. Таким образом, вы можете игнорировать ошибки для конкретных хэш-строк, но при этом принимать другие сертификаты, которые проходят проверку.
ServicePointManager.ServerCertificateValidationCallback +=
(sender, cert, chain, error) =>
{
if (cert.GetCertHashString() == "xxxxxxxxxxxxxxxx")
{
return true;
}
else
{
return error == SslPolicyErrors.None;
}
};
Ссылка:
https://msdn.microsoft.com/en-us/library/system.net.security.remotecertificatevalidationcallback(v=vs.110).aspx
Обратите внимание, что это все равно повлияет на другие экземпляры веб-клиента в том же appdomain (все они будут принимать указанную строку хэша), но по крайней мере он не будет блокировать другие сертификаты.