SslStream, как отключить кэширование сеанса?

Рейтинг: 6Ответов: 2Опубликовано: 04.05.2015

В документации сказано:

Платформа Framework кэширует сеансы SSL при их создании и пытается повторно использовать кэшированный сеанс для нового запроса, если это возможно. При попытке повторного использования сеанса SSL платформа Framework использует первый элемент ClientCertificates (если таковой существует) или пытается повторно использовать анонимные сеансы при пустом значении ClientCertificates.

Как отключить кэширование?

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

Update

Дело 100% в кэшировании сессии!

Дошли руки, проверил сниффером пакеты. Различаются сообщения типа Client Hello в одном месте.

Первое подключение к серверу (успешное): скриншот

Второе подключение к серверу без перезапуска программы (не успешное): скриншот

Думаю различие в идентификаторе сессии видно невооруженным взглядом.

p.s. очень не хочется использовать сторонние ssl клиенты. Есть ли разумный выход из ситуации?

Ответы

▲ 5Принят

К сожалению, кеширование происходит во внутреннем классе, и честно говоря не нашел в коде каких-либо точек, позволяющих его отключить полностью. Как вариант - можете между подключениями чистить кеш через Reflection:

var sslAssembly = Assembly.GetAssembly(typeof(SslStream));

var sslSessionCacheClass = sslAssembly.GetType("System.Net.Security.SslSessionsCache");

var cachedCredsInfo = sslSessionCacheClass.GetField("s_CachedCreds", BindingFlags.NonPublic | BindingFlags.Static);
var cachedCreds = (Hashtable)cachedCredsInfo.GetValue(null);

cachedCreds.Clear();

Хотя конечно тоже костыль.. Вообще вся эта история с отключением кеширования сеансов является бооольшим костылем. Оно не должно никогда отключатся для клиента.

Самым правильным решением было бы исправление проблемы внутри серверной части. Попробуйте поговорить с разработчиками серверного приложения к которому вы подключаетесь.

Обновлено: В случае с многопоточностью, можно ещё больше "закостылится", создав заглушку для Hashtable, ничего в себя не сохраняющую:

public class DummyHashtable : Hashtable
{
    public override object this[object key]
    {
        get { return null; }
        set { return; }
    }

    public override void Add(object key, object value)
    {
        return;
    }
}

Ну и соответственно вместо GetValue()/Clear() просто подменить значение этого поля:

var dummyCache = new DummyHashtable();
cachedCredsInfo.SetValue(null, dummyCache);

В итоге, кеш не сработает никогда.

▲ 4

После дня поисков чудом набрел на статью с блога msdn: ссылка

Windows дает возможность отключить кэширование SSL с помощью ключа регистра:
[HKEY_LOCAL_MACHINE]
[System]
[CurrentControlSet]
[Control]
[SecurityProviders]
[SCHANNEL]
ClientCacheTime
ClientCacheTime это DWORD в миллисекундах. Если Вы установите ключ в значение 0 и перезагрузите устройство, то кэширование SSL сессий не будет использоваться.

Создал x32 DWORD параметр в реестре, перезагрузил машину. Тем самым отключил кэширование всех SSL\TLS запросов в Windows. Это лишь костыль. Приму любой, более адекватный способ решения, т.к. этот способ требует:

а) прав администратора

б) внесение записи в реестр

в) удаления записи из реестра после удаления программы