Практическое руководство по хранилищу сертификатов Windows — пользователь или компьютер, куда класть

· · Сертификаты, Windows, Безопасность, PKI, TLS, PowerShell, Бизнес-приложения, Информационные системы

«После обновления терминала онлайн-проверки полиса переложили клиентский сертификат на новый ПК — и соединение пропало.» «На машине разработки банковский API открывается, а когда сделали службу Windows, говорит „сертификат не найден“.» «Вообще непонятно, какой сертификат настоящий — тот, что видно в certmgr.msc, или тот, что в certlm.msc.» — когда по заказной разработке делают интеграцию Web API с клиентским сертификатом, такие обращения приходят регулярно.

Онлайн-проверка полиса в медучреждениях, электронная подача, банковские API, EDI с контрагентами. Клиентские сертификаты, которыми когда-то занимались только инфраструктурщики крупных компаний, теперь трогают ИТ малого и среднего бизнеса и разработчики бизнес-приложений. И аварии вокруг сертификатов на деле сводятся к горстке шаблонов. Кладут не туда, забывают права на закрытый ключ, забывают срок — эти три.

Статья рассчитана на разработчиков бизнес-приложений, которые используют клиентские сертификаты, и на ИТ-сотрудников, которым поручают замену сертификатов. Осью решения «хранилище пользователя или хранилище компьютера» за один проход разбираем структуру хранилища сертификатов Windows, выдачу прав на закрытый ключ, инвентаризацию сроков через PowerShell и код использования из .NET. Содержание опирается на первоисточники Microsoft Learn по состоянию на август 2026.

1. Сначала вывод

  • Хранилище сертификатов Windows бывает двух систем: «пользователь» (CurrentUser) и «компьютер» (LocalMachine). Хранилище пользователя на каждую учётную запись своё (под HKEY_CURRENT_USER в реестре), хранилище компьютера общее на весь ПК (под HKEY_LOCAL_MACHINE).12
  • Средств управления тоже два. certmgr.msc открывает хранилище текущего пользователя, certlm.msc — локального компьютера. Из PowerShell это Cert:\CurrentUser и Cert:\LocalMachine.34
  • Куда класть, решает «от чьего имени работает программа, которая сертификат использует». Как правило, приложение интерактивного пользователя — хранилище пользователя; работа без присмотра — служба Windows, IIS, планировщик заданий — хранилище компьютера (таблица решений главы 3).
  • Причина «пока разрабатывали — работало, как стало службой — не находится» почти всегда одна. Сертификат, который разработчик положил в своё хранилище пользователя, из CurrentUser службы, работающей под другой учётной записью, невидим (глава 3).
  • Сертификат и закрытый ключ — разные вещи. Одного размещения сертификата в хранилище компьютера недостаточно, чтобы учётная запись службы читала закрытый ключ — это обычная ситуация. Выдайте учётной записи выполнения право на чтение через «Управление закрытыми ключами» в certlm.msc.5
  • При импорте pfx закрытый ключ по умолчанию нельзя экспортировать. Import-PfxCertificate принимает закрытый ключ в форме, из которой его нельзя экспортировать снова, пока не указан -Exportable. Это не авария, а желаемое значение по умолчанию.6
  • Истечение предотвращают автоматизацией инвентаризации. Get-ChildItem Cert:\LocalMachine\My -ExpiringInDays 60 механически извлекает сертификаты, которые истекают в пределах заданного числа дней.4
  • Отпечаток (thumbprint), зашитый в код или конфигурацию, убивает при каждом обновлении сертификата, потому что у нового сертификата отпечаток всегда другой. Вынести в конфигурацию плюс период параллельной работы старого и нового — базовая конструкция (главы 5 и 7).

Карта знаний этой статьи

Хранилище сертификатов Windows делится на две системы — пользователь (CurrentUser) и компьютер (LocalMachine); куда класть клиентский сертификат, решает «от чьего имени работает программа». Для службы Windows, которая работает без присмотра, хранилище компьютера и выдача прав на закрытый ключ идут в комплекте; истечение сертификата и зашитый отпечаток — классические причины сбоя соединения из-за сертификата.

Карта знаний практического руководства по хранилищу сертификатов WindowsРисунок, показывающий связи хранилища сертификатов (пользователь/компьютер), клиентского сертификата, закрытого ключа, цепочки сертификатов, корневого и промежуточного УЦ, истечения и отпечатка со сбоем соединения, порядка замены, реестра и риска самоподписанного сертификатаиспользуеттребуеттребуеттребуеттребуетможет вызватьможет вызватьпроверяетсянастраиваетсянастраиваетсяпроверяетсяпроверяетсяпроверяетсяпроверяетсяхранится впроверяетсяхранится виспользуетхранится внастраиваетсяпредотвращаетпредотвращаетможет вызватьне рекомендуетсяне рекомендуетсярекомендуется длянаследует содержимоехранится вможет вызватьиспользуеттребуетиспользуетможет вызватьне рекомендуетсятребуетдолжен предшествоватьиспользуетснижаеттребуетрекомендуется длярекомендуется дляхранилище сертификатовклиентский сертификатслужба Windowsхранилище сертификатов компьютеразакрытый ключправа доступа к закрытому ключуцепочка сертификатовпромежуточный сертификат УЦкорневой сертификат УЦистечение сертификатасбой соединения из-за сертификатазашитый отпечатокгрупповая политикаMicrosoft Intuneхранилище сертификатов пользователяcertmgr.msccertlm.mscдиск Cert:файл PFXcertutilсертификат подписи кодахранилище доверенных издателейнастольное приложение интерактивного пользователязамена сертификатареестр сертификатовразовый самоподписанный сертификатриск злоупотребления точкой довериявыбор (поиск) сертификатахранилище «Личные» (My)путаница хранилищпул приложений IISнеобслуживаемый запуск Планировщика заданийимпорт с возможностью экспортариск выноса закрытого ключавыдача Everyone полного контроляпредварительная регистрация сертификата у контрагентапереключение на новый сертификаткласс X509Storeпоиск сертификата с validOnlyатрибут использования ключа (Key Usage)вынесение отпечатка в конфигурациюжурнал выбранного сертификата

На схеме сплошная линия обозначает отношение, которое выполняется всегда, а пунктирная — условное отношение (условия указаны в пояснении к каждому отношению на странице сведений). Полный список отношений (всего 41, с доказательствами и степенью уверенности) и определения основных понятий собраны на странице сведений карты знаний (на японском). Данные: JSON-LD / Turtle

2. Общая картина хранилища сертификатов — два места и логические хранилища

2.1. Две системы: пользователь и компьютер

Хранилище сертификатов Windows в целом делится на два «места».1

  • Хранилище сертификатов компьютера (локальный компьютер, LocalMachine): одно на ПК, общее для всех пользователей и служб на этом ПК. Физически живёт под ключом реестра HKEY_LOCAL_MACHINE\Software\Microsoft\SystemCertificates.2
  • Хранилище сертификатов пользователя (текущий пользователь, CurrentUser): на каждую учётную запись пользователя своё. Физически живёт под HKEY_CURRENT_USER\Software\Microsoft\SystemCertificates, то есть как часть профиля пользователя.2

Есть ещё хранилище на учётную запись службы,3 физически — ключ реестра на имя службы.2 Для практики сначала нужно схватить первые два.

Есть одна важная спецификация. Каждое логическое хранилище хранилища пользователя, кроме «Личные», наследует и показывает содержимое одноимённого хранилища хранилища компьютера.1 Например, если положить сертификат корпоративного УЦ в «Доверенные корневые центры сертификации» хранилища компьютера, он появится и в «Доверенных корневых центрах сертификации» каждого пользователя. Наоборот, наследуется всё, кроме хранилища «Личные», поэтому для клиентского сертификата (того, что кладут в личное) вы сами решаете, «кому нужно его видеть». Эта асимметрия — главный персонаж всей статьи.

Хранилище компьютера и хранилище пользователяХранилище компьютера одно на ПК и общее для всех пользователей и служб; хранилище пользователя своё на каждую учётную запись, и кроме «Личные» наследует содержимое хранилища компьютераПользователь (CurrentUser)На каждую учётную запись своёКомпьютер (LocalMachine)Одно на ПК, общее для всех пользователей и службсодержимое видно через наследованиенаследованиенаследованиеЛичные (My)не наследуется = место кладёте самиДоверенные корневые центры сертификации (Root)Промежуточные центры сертификации (CA)Доверенные издатели (TrustedPublisher)Личные (My)Доверенные корневые центры сертификации (Root)Промежуточные центры сертификации (CA)Доверенные издатели (TrustedPublisher)

Рис. 1: Хранилище пользователя, кроме «Личные», наследует содержимое хранилища компьютера; куда класть клиентский сертификат, решаете сами.

2.2. Основные логические хранилища

Внутри каждого места содержимое разделено на логические хранилища по роли. Это папки, которые видно в certmgr.msc / certlm.msc; из PowerShell и командной строки используют английские внутренние имена.24

Отображаемое имя Внутреннее имя Что сюда кладут
Личные My Сертификаты, которыми пользуется этот ПК / этот пользователь. Сюда — клиентские и серверные. Сюда же привязывается закрытый ключ
Доверенные корневые центры сертификации Root Корневые сертификаты УЦ — точка доверия. Всё под УЦ, положенным сюда, «доверяется»
Промежуточные центры сертификации CA Промежуточные сертификаты УЦ между корнем и оконечным. Материал построения цепочки
Доверенные издатели TrustedPublisher Сертификаты, которым доверяют как издателю подписанного ПО (глава 8)

2.3. Три окна просмотра — certmgr.msc / certlm.msc / диск Cert:

Одно и то же хранилище смотрят тремя средствами.34

  • certmgr.msc: консоль управления, открывающая хранилище текущего пользователя.
  • certlm.msc: консоль управления, открывающая хранилище локального компьютера.
  • Диск PowerShell Cert:: иерархия Cert:\CurrentUser\... и Cert:\LocalMachine\... позволяет обращаться с хранилищем как с файловой системой. Сертификаты идентифицируются отпечатком.

Если оснастку сертификатов добавляют в mmc.exe вручную, цель выбирают из трёх видов: «учётная запись пользователя», «учётная запись компьютера», «учётная запись службы». Пользователь без прав администратора может управлять только хранилищем своей учётной записи пользователя.3

Первый шаг расследования сбоя — совместить «какое хранилище смотрит приложение» и «какое хранилище смотрите вы». Пока вы смотрите certmgr.msc и расследуете сбой службы, места разные, и ответ не появится никогда.

3. Куда класть — таблица решений по форме выполнения программы

Критерий один. Под чьей учётной записью работает программа, которая этот сертификат использует.

Форма выполнения Учётная запись выполнения Куда класть Примечание
Настольное приложение, которое запускает интерактивный пользователь Сам вошедший пользователь Пользователь (Cert:\CurrentUser\My) Нужно внедрять на каждую учётную запись пользователя. Если общим ПК пользуются несколько человек, рассмотрите и хранилище компьютера
Служба Windows LocalSystem / NETWORK SERVICE / выделенная учётная запись службы Компьютер (Cert:\LocalMachine\My) Всем, кроме LocalSystem (NETWORK SERVICE, выделенная учётная запись и т. п.), обязательно выдать право читать закрытый ключ (глава 4). LocalSystem читает правом SYSTEM по умолчанию
Веб-приложение на IIS Идентификатор пула приложений Компьютер То же
Работа без присмотра планировщика заданий (выполнять независимо от входа пользователя) Учётная запись, указанная заданию Рекомендуется компьютер Можно и хранилище пользователя учётной записи выполнения, но растёт только проверка профиля и видимости хранилища, выгоды мало
Электронная подача и веб-аутентификация в браузере Сам вошедший пользователь Пользователь Естественно и в смысле «не давать пользоваться никому, кроме того, кому раздали»

Если сомневаетесь: то, что работает без присмотра, — хранилище компьютера; то, чем управляет человек, — хранилище пользователя.

3.1. Разбор классической аварии — «пока разрабатывали — работало, как стало службой — не находится»

Эту аварию точно воспроизводят следующим порядком.

  1. Разработчик на своём ПК дважды щёлкает pfx и импортирует. Значение мастера по умолчанию — «текущий пользователь», поэтому сертификат попадает в хранилище пользователя учётной записи разработчика.
  2. Приложение в разработке запускается из Visual Studio, то есть под учётной записью разработчика, открывает StoreLocation.CurrentUser — сертификат находится. Работает.
  3. На продакшен-сервере регистрируют как службу Windows. Служба работает под NETWORK SERVICE или выделенной учётной записью.
  4. CurrentUser, который открывает код службы, — хранилище пользователя учётной записи выполнения службы. Оно пусто. «Сертификат не найден».
Пока разрабатывали — работало, как стало службой — не находитсяСертификат, положенный в хранилище пользователя разработчика, не виден из CurrentUser службы, которая работает под другой учётной записьюПродакшен-серверМашина разработкиразмещают ту же программуCurrentUser, который открывает код,— хранилище пользователя учётной записи службыРегистрация как службы Windowsучётная запись выполнения — NETWORK SERVICE и т. п.Оно пусто→ «сертификат не найден»Попадает в хранилище пользователяучётной записи разработчикаИмпорт двойным щелчком pfxзначение мастера по умолчанию — «текущий пользователь»Запуск из Visual Studio= работает под учётной записью разработчикаОткрыть CurrentUser — находится→ работает

Рис. 2: Хранилище пользователя разработчика и хранилище пользователя учётной записи службы разные; работа в разработке не гарантирует, что сертификат найдётся в продакшене.

Суть в том, что хранилищ пользователя «столько, сколько учётных записей». Даже если администратор откроет certmgr.msc и скажет «да вот же лежит», это хранилище самого администратора, а не хранилище учётной записи службы. Мера — не копировать по случаю, а положить заново в хранилище компьютера и выровнять код на StoreLocation.LocalMachine. И в комплект входит выдача прав следующей главы.

4. Закрытый ключ и права доступа — вторая классическая авария

4.1. Сертификат и закрытый ключ — разные вещи

В списке хранилища сертификатов виден сертификат (открытые сведения), а не сам закрытый ключ. Для клиентской аутентификации на деле нужна подпись закрытым ключом, поэтому «видно в списке» и «можно пользоваться» — разные проблемы. Если их смешать, получаются плохо читаемые снаружи сбои: «сертификат есть, но TLS-рукопожатие падает», «внутренние ошибки вроде Access Denied».

4.2. Практика импорта pfx — экспортируемость есть решение

Пару сертификат + закрытый ключ передают файлом pfx (PKCS #12) и принимают в хранилище Import-PfxCertificate.6

$pwd = Get-Credential -UserName '(пароль введите ниже)' -Message 'Пароль PFX'
Import-PfxCertificate -FilePath C:\certs\client.pfx `
    -CertStoreLocation Cert:\LocalMachine\My -Password $pwd.Password

Важно: пока не указан -Exportable, принятый закрытый ключ нельзя экспортировать снова — поведение по умолчанию.6 Класть всё как экспортируемое «чтобы потом можно было перенести» — добавить ещё один путь выноса закрытого ключа. Оригинал pfx хранят безопасно, а закрытый ключ в хранилище по умолчанию неэкспортируемый — так рекомендуем мы. Оригинал pfx и его пароль как раз часто оставляют открытым текстом. Мышление разобрано в «Хранение секретов в Windows-приложениях — избегаем открытых настроек с помощью DPAPI» и «Безопасная работа с учётными данными в PowerShell».

4.3. Выдача прав на закрытый ключ учётной записи службы

Закрытый ключ сертификата, положенного в хранилище компьютера, по умолчанию обычно не читают ниоткуда, кроме администраторов и SYSTEM. Поэтому служба под LocalSystem читает закрытый ключ как есть, а если работает под NETWORK SERVICE, выделенной учётной записью службы, идентификатором пула приложений IIS и т. п. — всем, кроме этого, явно выдайте учётной записи выполнения право на чтение. Шаги — из UI оснастки сертификатов.5

  1. Открыть certlm.msc (или оснастку сертификатов с целью «учётная запись компьютера»).
  2. «Личные» → «Сертификаты», правый щелчок по целевому сертификату, «Все задачи» → «Управление закрытыми ключами».
  3. На вкладке «Безопасность» добавить учётную запись выполнения (NETWORK SERVICE, выделенная учётная запись службы, идентификатор пула приложений IIS и т. п.) и разрешить «Чтение».5

Полный контроль не нужен. Для подписи достаточно чтения. Наоборот, выдать Everyone полный контроль «потому что не работает» — опустить закрытый ключ до обращения как с открытым паролем; этого абсолютно избегать. Размещение в хранилище компьютера и выдача прав на закрытый ключ всегда в комплекте — одной этой фразой в инструкции этот класс аварий исчезает.

5. Не допустить аварию истечения — инвентаризация, замена, реестр

5.1. Инвентаризация через PowerShell

Срок действия сертификата лежит в свойстве NotAfter. Инвентаризировать механически можно Get-ChildItem по диску Cert:.4

# Личные хранилища компьютера списком по сроку действия
Get-ChildItem Cert:\LocalMachine\My |
    Sort-Object NotAfter |
    Format-Table Thumbprint, Subject, NotAfter

# Только те, что истекают в пределах 60 дней (0 — уже истёкшие)
Get-ChildItem -Path Cert:\LocalMachine\My -ExpiringInDays 60

-ExpiringInDays возвращает «сертификаты, которые истекают в пределах заданного числа дней»; 0 даёт уже истёкшие.4 Сделайте это ежемесячным заданием планировщика по всем серверам и сводите результат в почту или реестр — и аварии вида «истёк срок, с утра понедельника проверка полиса не проходит» почти исчезают.

5.2. Порядок замены — период параллельной работы и ловушка отпечатка

Обновление сертификата — не «удалить и положить», а «добавить, затем переключить, проверить, затем удалить».

  1. Импортировать новый сертификат (pfx) в то же хранилище. Отпечатки разные, поэтому старый и новый могут сосуществовать в одном хранилище.
  2. Выдать права на закрытый ключ нового сертификата (глава 4). При обновлении это чаще всего забывают. Права висят на закрытом ключе каждого сертификата, поэтому после замены сертификата выдачу делают заново.
  3. Уведомление контрагента (API, где сертификат нужно регистрировать заранее) сначала, продолжая работать на старом сертификате, и обеспечить период, когда принимают и старый, и новый. Если переключить раньше, контрагент отвергнет новый сертификат, и продакшен-обмен встанет.
  4. Переключить конфигурацию приложения на новый сертификат и проверить работу.
  5. После достаточного периода удалить старый сертификат.
Обновление сертификата — сначала добавить, затем переключитьНовый pfx кладут в то же хранилище, выдают права, заранее регистрируют у контрагента, затем переключают отпечаток и после периода параллельной работы удаляют старый сертификат1. Импорт нового pfx в то же хранилище(старый и новый сосуществуют)2. Выдать права на закрытый ключнового сертификата3. Заранее зарегистрировать у контрагента(продолжать работу на старом)4. Переписать отпечаток в конфигурации,переключить, проверить работу5. После периода параллельной работыудалить старый сертификат

Рис. 3: Порядок замены сертификата — добавить → выдать права → заранее зарегистрировать → сменить конфигурацию → удалить старый; не забудьте обновить отпечаток.

Главная ловушка здесь — отпечаток, записанный в файл конфигурации или в код. Отпечаток уникален на сертификат, при обновлении он обязательно меняется. Если хоть в одном месте остаётся ссылка на старый отпечаток, получается «сертификат обновили, а соединиться нельзя». Надёжно вести в реестре, где отпечаток записан (конфигурация приложения, привязка IIS, скрипты, уведомление контрагента).

5.3. Зачем реестр сертификатов

Реестр — для начала хватит одного листа Excel. Минимум колонок: назначение / издатель / субъект / отпечаток / место (имя сервера + хранилище) / учётные записи с правом на закрытый ключ / срок действия / ссылка на процедуру обновления / ответственный — и сверять с результатом инвентаризации 5.1. Суть аварий с сертификатами — не техника, а «ни у кого нет списка», поэтому реестр действует сильнее всего.

6. Проверка и чтение сбоя — цепочка и раздача корня

6.1. База проверки цепочки и certutil

Ошибки вида «этому сертификату не доверяют» — состояние, в котором цепочка (путь сертификации) от оконечного сертификата до корневого УЦ где-то разорвана. Для разбора удобен certutil.7

Три классические причины разрыва проверки цепочкиОшибка доверия возникает, когда промежуточный УЦ получить нельзя, корень не роздан или оконечный сертификат истёкполучить нельзя(ни предъявление, ни AIA, ни хранилище)не розданистёкОконечный сертификат(клиентский, серверный)Промежуточный сертификат УЦместо: хранилище промежуточных УЦ (CA)Корневой сертификат УЦместо: доверенные корневые УЦ (Root)Цепочку построить нельзя(классическая причина 1)Ошибка «не доверяют»(классическая причина 2)Ошибка срока действия(классическая причина 3)

Рис. 4: Цепочка рвётся, если нет промежуточного УЦ или корня, либо из-за срока действия; слой определяют через certutil.

:: Построить и проверить цепочку файла сертификата (с получением URL отзыва)
certutil -urlfetch -verify client.cer

:: Если целевое приложение использует хранилище пользователя — тот же контекст с -user
certutil -user -urlfetch -verify client.cer

:: Дамп содержимого хранилища (-user — хранилище пользователя)
certutil -store My
certutil -user -store My

certutil -verify проверяет сертификат, CRL и цепочку и, если CACertFile не задан, строит полную цепочку и проверяет её.7 Вывод длинный, но из него читается, на каком уровне оборвалось доверие и получены ли сведения об отзыве. Типичные причины: (1) промежуточный сертификат УЦ получить нельзя (собеседник TLS его не прислал, из сведений AIA сертификата тоже не взять, в хранилище «Промежуточные центры сертификации» его нет); (2) корень корпоративного УЦ не роздан в «Доверенные корневые центры сертификации»; (3) истёк сам сертификат. Промежуточный УЦ решается и предъявлением собеседника, и автоматическим получением через AIA, поэтому размещение в хранилище — «один из способов сделать надёжно».

6.2. Раздача корня корпоративного УЦ и самоподписанного — через GPO/Intune

Если используете корпоративный УЦ или самоподписанный сертификат для проверки, его корневой сертификат нужно раздать на каждый ПК. Не класть вручную по одной машине, а посадить на механизм раздачи.

  • Среда Active Directory (GPO): импорт сертификата в «Доверенные корневые центры сертификации» в Конфигурация компьютера\Политики\Конфигурация Windows\Параметры безопасности\Политики открытого ключа раздаёт его на целевые ПК.8
  • Среда управления Intune: профилем «Доверенный сертификат» раздают корневой / промежуточный сертификат УЦ. В Windows можно выбрать целевое хранилище (корень / промежуточный компьютера, промежуточный пользователя).9

Как сказано в 2.1, положив в корень хранилища компьютера, доверяют все пользователи.1 Поэтому смотрите и обратный риск. Положить самоподписанный сертификат в «Доверенные корневые центры сертификации» — посадить на этот ПК новую точку доверия. Если его закрытый ключ утечёт, появляется площадка выпускать сертификаты, выдающие себя за любой сайт или ПО. Для постоянной эксплуатации — либо корпоративный УЦ с надлежащей защитой закрытого ключа, либо сертификаты публичного УЦ; самоподписанный корень — принцип «только среда проверки, со сроком».

7. Взгляд разработчика — правильно пользоваться хранилищем из .NET

7.1. Поиск по отпечатку через X509Store

Из .NET хранилище открывают X509Store и получают сертификат через Find.1011

using System.Security.Cryptography.X509Certificates;

static X509Certificate2 GetClientCertificate(string thumbprint)
{
    using var store = new X509Store(StoreName.My, StoreLocation.LocalMachine);
    store.Open(OpenFlags.ReadOnly | OpenFlags.OpenExistingOnly);

    var found = store.Certificates.Find(
        X509FindType.FindByThumbprint, thumbprint, validOnly: true);

    if (found.Count == 0)
        throw new InvalidOperationException(
            $"Сертификат не найден: отпечаток={thumbprint}, " +
            $"место={store.Location}\\{store.Name}");

    var cert = found[0];
    if (!cert.HasPrivateKey)
        throw new InvalidOperationException(
            $"Сертификат есть, но закрытый ключ не связан (импорт " +
            $"из .cer и т. п.): отпечаток={thumbprint}, место={store.Location}\\{store.Name}");

    return cert;
}

Решение главы 3 сюда стыкуется напрямую. Код, работающий как служба, — StoreLocation.LocalMachine; интерактивное приложение — StoreLocation.CurrentUser. Ещё одно: третий аргумент Find, validOnly. true возвращает только действительные сертификаты, прошедшие проверку.11 Это страховка не схватить истёкший, но тестовый самоподписанный, которому цепочка не доверяет, тоже падает в «не найден» — когда «лежит, а не находится», подозревайте и это. И в сообщение об ошибке, когда не найден, как в примере выше, обязательно включайте, какое хранилище искали. Время расследования аварии главы 3 меняется на порядки.

7.2. Положить клиентский сертификат в HttpClient

Полученный сертификат добавляют в HttpClientHandler.ClientCertificates и предъявляют серверу. Эта коллекция — множество сертификатов, предъявляемых серверу при аутентификации клиента по сертификату.12

var handler = new HttpClientHandler();
handler.ClientCertificates.Add(GetClientCertificate(thumbprint));

var client = new HttpClient(handler);
// дальше — обычный HttpClient

В семействе .NET Core в документации прямо сказано: если у сертификата есть атрибут использования ключа (Key Usage), без «Digital Signature» он не используется при отправке запроса.12 Когда заказываете выпуск клиентского сертификата, правильно передавайте назначение (аутентификация клиента). Кроме того, HttpClient при неверном шаблоне создания даёт исчерпание сокетов и проблемы следования за DNS. Конструкцию с долгоживущим обработчиком разбирали в «Не оборачивайте HttpClient в using».

7.3. Проблема зашитого отпечатка, который умирает при замене

Поиск по отпечатку надёжен, но если отпечаток вшить в код, при каждом обновлении сертификата нужны сборка и выпуск. Мера в проекте — три ступени.

  • Минимум: вынести отпечаток в файл конфигурации (appsettings и т. п.), чтобы менять без выпуска. Место конфигурации занести в реестр 5.3.
  • Шаг дальше: искать по имени субъекта или издателю и в сочетании с validOnly: true выбирать «из сейчас действительных с этим именем тот, у кого NotAfter дальше всех». В период параллельной работы старого и нового автоматически пересядет на новый сертификат. Но есть риск схватить одноимённый непреднамеренный сертификат, поэтому в комплект — проверка издателя и вывод в журнал. И эта автоматическая пересадка работает только если контрагенту не нужна предварительная регистрация сертификата. В API, где регистрация нужна (5.2), самовольное переключение на только что импортированный незарегистрированный сертификат может остановить обмен — оставайтесь на вынесении в конфигурацию с переключением после подтверждения регистрации.
  • Закрепить эксплуатацией: при любом способе при запуске писать в журнал, «какой сертификат (отпечаток, срок) выбран». И для расследования сбоя, и для сверки с реестром работает эта одна строка.

8. Связь с сертификатом подписи кода — хранилище «Доверенные издатели»

До сих пор речь шла о сертификатах для обмена (TLS), но в хранилище сертификатов живёт ещё один мир — подпись кода. Точка касания — хранилище «Доверенные издатели (TrustedPublisher)» из таблицы 2.2: место, куда регистрируют сертификат издателя подписанного ПО как доверенный. Есть и в месте пользователя, и в месте компьютера,10 и используется в эксплуатации вроде раздачи издателя внутреннего приложения через GPO в TrustedPublisher каждого ПК.

Если вы на «стороне раздачи» приложения и нужно закрыть подпись кода и предупреждение SmartScreen («Windows защитил ваш компьютер»), это собрано в отдельной статье «Почему Windows показывает сообщение „Windows защитил ваш компьютер“». Знания этой статьи (две системы хранилища, раздача корня) остаются предпосылками как есть.

9. Итог

  • Хранилище сертификатов — две системы: пользователь (CurrentUser) и компьютер (LocalMachine). certmgr.msc / certlm.msc / диск Cert: — три окна на одно и то же. Первый шаг расследования — совместить, «о каком хранилище речь».
  • Куда класть, решает «от чьего имени работает программа». Работа без присмотра (служба, IIS, задание) — хранилище компьютера; интерактивное приложение — хранилище пользователя, как правило.
  • «Пока разрабатывали — работало, в продакшене не находится» — потому что хранилище пользователя разработчика и хранилище пользователя учётной записи службы разные. Выравнивают на хранилище компьютера + StoreLocation.LocalMachine.
  • Размещение в хранилище компьютера и выдача права на чтение в «Управлении закрытыми ключами» — всегда в комплекте. Не забудьте выдать заново при обновлении.
  • Импорт pfx по умолчанию неэкспортируемый. -Exportable — только когда действительно нужно. Хранение оригинала pfx и пароля тоже входит в проект.
  • Истечение предотвращают регулярной инвентаризацией Get-ChildItem Cert: ... -ExpiringInDays и реестром сертификатов. Замена — порядок «добавить → переключить → проверить → удалить», следите за пропуском обновления отпечатка в конфигурации.
  • Разбор цепочки — certutil -urlfetch -verify. Корень корпоративного УЦ раздают через GPO/Intune; самоподписанный в корень — только среда проверки, со сроком.
  • В коде отпечаток выносят в конфигурацию и выбранный сертификат пишут в журнал. Одного этого достаточно, чтобы разбор сбоев из-за сертификатов стал другим.

Похожие статьи

Смежные области консультирования

KomuraSoft LLC занимается разработкой бизнес-приложений с интеграцией Web API по клиентскому сертификату (банковские API, онлайн-проверка полиса и т. п.), расследованием сбоев вида «сертификат не найден», «после обновления не соединяется» и наведением порядка в процедуре замены сертификатов. Можно начинать уже с этапа «непонятно, куда в хранилище смотреть».

Справочные ссылки

  1. Microsoft Learn, Local Machine and Current User Certificate Stores. О том, что хранилище сертификатов компьютера локально для ПК и общее для всех пользователей, живёт под HKEY_LOCAL_MACHINE; о том, что хранилище сертификатов пользователя своё на учётную запись и живёт под HKEY_CURRENT_USER; о том, что хранилище пользователя наследует содержимое хранилища компьютера, кроме хранилища «Личные» (сертификат, добавленный в «Доверенные корневые центры сертификации» компьютера, появляется и в одноимённом хранилище каждого пользователя).  2 3 4

  2. Microsoft Learn, System Store Locations. О положении в реестре CERT_SYSTEM_STORE_CURRENT_USER / CERT_SYSTEM_STORE_LOCAL_MACHINE (соответственно Software\Microsoft\SystemCertificates под HKEY_CURRENT_USER / HKEY_LOCAL_MACHINE); о предопределённых логических хранилищах MY, Root, Trust, CA; о том, что хранилище служб живёт в ключе реестра на имя службы (Software\Microsoft\Cryptography\Services\ServiceName\SystemCertificates); о том, что отдельно существуют хранилища для раздачи групповой политикой.  2 3 4 5

  3. Microsoft Learn, How to: View certificates with the MMC snap-in. О том, что certlm.msc управляет сертификатами локального устройства (локального компьютера), certmgr.msc — сертификатами текущего пользователя; о трёх видах цели оснастки сертификатов: «учётная запись компьютера», «учётная запись пользователя», «учётная запись службы»; о том, что пользователь без прав администратора может управлять только сертификатами своей учётной записи пользователя.  2 3 4

  4. Microsoft Learn, about_Certificate_Provider. О том, что диск PowerShell Cert: — иерархическое пространство имён с двумя местами хранилища CurrentUser и LocalMachine; о перечислении хранилищ и сертификатов через Get-ChildItem; о том, что параметр -ExpiringInDays возвращает сертификаты, истекающие в пределах заданного числа дней (0 — уже истёкшие); о динамических параметрах вроде -CodeSigningCert; о том, что срок действия хранится в свойстве NotAfter; о том, что сертификаты идентифицируются отпечатком.  2 3 4 5 6

  5. Microsoft Learn, How to Modify Private Key Permissions to Support Management Server or Streaming Server. О порядке открыть «Управление закрытыми ключами» (Manage Private Keys) в оснастке сертификатов с целью хранилища локального компьютера и на вкладке «Безопасность» добавить учётной записи выполнения службы (например Network Service) разрешение «Чтение».  2 3

  6. Microsoft Learn, Import-PfxCertificate. О том, что Import-PfxCertificate принимает сертификат и закрытый ключ из файла PFX в указанное хранилище; о том, что без переключателя -Exportable принятый закрытый ключ экспортировать нельзя; о синтаксисе и примерах параметров -CertStoreLocation, -Password, -FilePath.  2 3

  7. Microsoft Learn, certutil. О том, что certutil -verify проверяет сертификат, CRL и цепочку сертификатов и, если файл сертификата УЦ не задан, строит полную цепочку и проверяет её; о доступности параметра -urlfetch; о том, что certutil -store дампит хранилище сертификатов, а параметр -user обращается к хранилищу пользователя вместо хранилища компьютера.  2

  8. Microsoft Learn, Distribute Certificates to Client Computers by Using Group Policy. О порядке импорта сертификата в «Доверенные корневые центры сертификации» в Конфигурация компьютера\Политики\Конфигурация Windows\Параметры безопасности\Политики открытого ключа групповой политики и раздачи клиентским компьютерам в домене; о нужных правах (уровень Domain Admins / Enterprise Admins). 

  9. Microsoft Learn, Create trusted certificate profiles in Microsoft Intune. О том, что профиль Intune «Доверенный сертификат» раздаёт корневой или промежуточный сертификат УЦ на управляемые устройства; о том, что он используется для установления доверия к корневому УЦ как предпосылка профилей сертификатов SCEP/PKCS; о том, что в Windows можно выбрать целевое хранилище: «хранилище сертификатов компьютера — корень», «хранилище сертификатов компьютера — промежуточные», «хранилище сертификатов пользователя — промежуточные». 

  10. Microsoft Learn, X509Store Class. О том, что X509Store строится с указанием StoreName и StoreLocation (CurrentUser / LocalMachine), открывается методом Open и OpenFlags (ReadOnly, OpenExistingOnly и др.), коллекцию сертификатов получают свойством Certificates; о том, что в стандартные имена хранилищ входят My, Root, CA, TrustedPublisher и др. и хранилище TrustedPublisher есть и в CurrentUser, и в LocalMachine.  2

  11. Microsoft Learn, X509Certificate2Collection.Find(X509FindType, Object, Boolean) Method. О том, что метод Find ищет сертификаты по X509FindType (FindByThumbprint и др.) и значению поиска; о том, что при true в третьем аргументе validOnly возвращаются только действительные сертификаты, прошедшие проверку.  2

  12. Microsoft Learn, HttpClientHandler.ClientCertificates Property. О том, что свойство ClientCertificates — X509CertificateCollection, предъявляемая серверу при аутентификации клиента по сертификату; о том, что в .NET Core при наличии у сертификата атрибута использования ключа нужно включать «Digital Signature».  2

Недавние статьи с теми же тегами помогут подробнее изучить близкие темы.

Политика аудита безопасности Windows и расследование журнала событий на практике — как стать ИТ-службой, которая умеет читать 4625

Практическое руководство, чтобы ответить на просьбу «посмотрите журналы неудачных входов». Разбирает связь базовой и расширенной политики...

Теневое копирование тома (VSS): устройство и практика — почему резервное копирование может скопировать файл, который ещё используется

Занятый файл обычно нельзя скопировать из-за нарушения совместного доступа — как тогда это делает ПО резервного копирования? Статья разби...

Эти страницы показывают тему статьи в более широком контексте услуг и решений.

Статья напрямую связана со следующими услугами.

Частые вопросы

Вопросы, которые часто возникают при консультациях по теме статьи.

Чем отличаются certmgr.msc и certlm.msc?
Целевые хранилища разные. certmgr.msc открывает хранилище сертификатов текущего вошедшего пользователя (текущий пользователь, CurrentUser); certlm.msc открывает хранилище сертификатов компьютера (локальный компьютер, LocalMachine). Хранилище компьютера общее для всех пользователей и служб на ПК, для управления нужны права администратора. Пользователь без прав администратора может управлять только своим хранилищем пользователя. Внутри обоих содержимое разделено на логические хранилища вроде «Личные» и «Доверенные корневые центры сертификации»; из PowerShell та же структура видна как Cert:\CurrentUser и Cert:\LocalMachine.
Клиентский сертификат класть в хранилище пользователя или компьютера?
Решает, «от чьего имени» работает программа, которая сертификат использует. Для настольного приложения, которое запускает интерактивный пользователь, базовый выбор — хранилище пользователя того, кто им пользуется (Cert:\CurrentUser\My). Для программы, которая работает без присмотра — служба Windows, пул приложений IIS, планировщик заданий — кладите в хранилище компьютера (Cert:\LocalMachine\My) и выдайте учётной записи выполнения право читать закрытый ключ. Хранилище пользователя на каждую учётную запись своё, поэтому сертификат, который разработчик положил в своё хранилище пользователя, службе, работающей под другой учётной записью, невидим. Это классическая причина «пока разрабатывали — работало, в продакшене не находится».
Что проверять, когда служба Windows не находит сертификат или не может им пользоваться?
Проверка в два шага. Первое: какое хранилище смотрит. Если код открывает StoreLocation.CurrentUser, это хранилище пользователя учётной записи выполнения службы, а не то, которое администратор видит, открыв certmgr.msc для себя. Перенесите сертификат в хранилище компьютера и выровняйте код на StoreLocation.LocalMachine. Второе: читается ли закрытый ключ. Быть в списке сертификатов и мочь пользоваться ключом — разные вещи: по умолчанию к закрытому ключу в хранилище компьютера обычно имеют доступ только администраторы и SYSTEM. В certlm.msc откройте «Управление закрытыми ключами» у целевого сертификата и выдайте «Чтение» учётной записи выполнения службы (NETWORK SERVICE и т. п.).
Как заранее ловить истечение сертификата через PowerShell?
Инвентаризировать можно Get-ChildItem по диску Cert:. Например, Get-ChildItem Cert:\LocalMachine\My | Sort-Object NotAfter | Format-Table Thumbprint, Subject, NotAfter выводит личное хранилище хранилища компьютера в порядке срока действия. Параметр -ExpiringInDays извлекает только «сертификаты, которые истекают в пределах заданного числа дней»; 0 возвращает уже истёкшие. Запускайте это ежемесячно по всем серверам и сверяйте результат с реестром сертификатов — и почти все аварии вида «с утра понедельника не аутентифицируется, потому что сертификат истёк» исчезают.

Об авторе

Страница с профилем автора статьи.

Го Комура

Представитель KomuraSoft LLC

Специализируется на разработке программного обеспечения для Windows, техническом консалтинге и расследовании сбоев, особенно в проектах с унаследованными системами и трудно воспроизводимыми ошибками.

Публичные ссылки

Вернуться в блог