KB5025823 Зміна способу імпорту сертифікатів X.509 у програмах .NET

Застосовується до
.NET

Примітка. Переглянуто 22 червня 2023 р. з метою оновлення роздільної здатності та способів вирішення

Примітка. Оновлено 15 червня 2023 р. з метою оновлення варіантів 4 та 5

Передісторія

13 червня 2023 р. корпорація Майкрософт випустила оновлення системи безпеки для .NET Framework і .NET, яке впливає на спосіб імпорту сертифікатів X.509 у середовищі виконання. Ці зміни можуть призвести до того, що імпорт сертифіката X.509 викличе CryptographicException у сценаріях, де імпорт був би успішним до оновлення.

У цьому документі описано зміни та способи вирішення, доступні для програм, яких це стосується.

Програмне забезпечення, якого це стосується

  • .NET Framework.NET Framework 2.0
  • .NET Framework.NET Framework 4.6.2, 4.7, 4.7.1, 4.7.2
  • .NET Framework.NET Framework 4.8
  • .NET Framework.NET Framework 4.8.1
  • .NET 6.0
  • .NET 7.0

API, яких це стосується

Опис змін

До зміни від 13 червня 2023 року, коли .NET Framework і .NET надається BLOB-об'єкт двійкового сертифіката для імпорту, .NET Framework та .NET зазвичай делегували перевірку та імпорт BLOB-об'єктів відповідній ОС. Наприклад, у Windows .NET Framework та .NET зазвичай використовують API PFXImportCertStore для перевірки та імпорту.

Станом на 13 червня 2023 року, коли .NET Framework і .NET надається BLOB-об'єкт двійкового сертифіката для імпорту, .NET Framework та .NET за певних обставин виконуватимуть додаткову перевірку, перш ніж передавати BLOB-об'єкт відповідній ОС. Ця додаткова перевірка виконує серію евристичних перевірок, щоб визначити, чи може вхідний сертифікат зловмисно вичерпати ресурси після імпорту. Оскільки це додаткова перевірка, яка виходить за рамки того, що зазвичай виконує базова ОС, вона може блокувати BLOB-об'єкти сертифікатів, які було б успішно імпортовано до зміни 13 червня 2023 року.

Відомі регресії

  1. Якщо сертифікат X.509 експортовано як BLOB-об'єкт PFX із використанням незвично великої кількості ітерацій пароля, цей сертифікат може не імпортуватися. У більшості засобів експорту сертифікатів кількість ітерацій становить від 2 000 до 10 000. Після застосування оновлення системи безпеки імпорт сертифікатів, які містять кількість ітерацій більше 600 000, завершиться помилкою.

  2. Якщо сертифікат X.509 було експортовано за допомогою нульового пароля [наприклад, через X509Certificate.Export(X509ContentType.Pfx, (string)null) або безпарольний X509Certificate.Export(X509ContentType.Pfx)]), цей сертифікат тепер не вдасться імпортувати.
     

    Примітка.

    Вищезазначений регрес було розглянуто в оновленні від 22 червня 2023 року, про яке йшлося в KB5028608.

  3. Якщо сертифікат X.509 експортовано як BLOB-об'єкт PFX із можливістю Windows захистити закритий ключ SID, цей сертифікат може не імпортуватися. Це вплине на BLOB-об'єкти PFX, створені таким чином:

    • За допомогою майстра експорту сертифікатів Windows і визначення в майстрі, що закритий ключ повинен бути захищений для користувача домену; або
    • За допомогою командлета Export-PfxCertificate PowerShell, де вказано явний -ProtectTo аргумент; або
    • За допомогою утиліти certutil , де вказано явний -protectto аргумент; або
    • Через інтерфейс API PFXExportCertStoreEx , де вказано прапорець PKCS12_PROTECT_TO_DOMAIN_SIDS.

Вирішення & способи вирішення

Існують різні способи вирішення. Це залежить від того, чи потрібно цілеспрямовано вносити зміни до окремих сайтів викликів у коді, або ви хочете змінити поведінку однієї програми, або внести зміни на рівні комп'ютера.

Варіант 1 (рекомендовано) – інсталяція оновленого виправлення

Примітка.

Це рекомендований варіант, оскільки він враховує регресію клієнтів, про які часто повідомляють, і не вимагає внесення змін до коду програми.

Застосовність: Цей параметр застосовується до всіх версій .NET Framework і .NET.

Цю проблему вирішено в оновленні від 22 червня 2023 р., описаному в KB5028608.

Корпорація Майкрософт рекомендує користувачам, які стикаються з регресією, запровадженою у випуску від 13 червня 2023 р., спробувати інсталювати це оновлене виправлення, перш ніж намагатися способи вирішення, наведені далі в цьому документі.

Варіант 2. Змінення сайту виклику

Застосовність: Цей параметр застосовується до всіх версій .NET Framework і .NET.

Подумайте, чи BLOB-об, який ви імпортуєте, заслуговує на довіру. Наприклад, чи було BLOB-об'єкт отримано з надійного розташування, наприклад із підконтрольної вам бази даних або файлу конфігурації, чи через мережевий запит, зроблений неавтентифікованим або непривілейованим клієнтом?

Корпорація Майкрософт наполегливо рекомендує не імпортувати PFX-BLOB-об'єкти, надані неавтентифікованими або непривілейованими клієнтами, оскільки вони можуть містити зловмисну поведінку, пов'язану з вичерпанням ресурсів.

Якщо вам потрібно імпортувати BLOB-об'єкт сертифіката відкритого ключа , наданий ненадійною стороною, ви можете безпечно імпортувати такий BLOB-об'єкт за допомогою наведеного нижче коду. Цей зразок коду використовує метод GetCertContentType , щоб визначити основний тип BLOB-об'єкта сертифіката, і відхиляє PFX-BLOB-об'єкти у випадках, коли ви плануєте імпортувати лише BLOB-об'єкт сертифіката відкритого ключа. Конструктор X509Certificate2(byte[]) є безпечним для використання, якщо йому надано недовірені BLOB-об'єкти, відмінні від PFX.


using System.Security.Cryptography.X509Certificates;
public static X509Certificate2 ImportPublicCertificateBlob(byte[] blob)
{
     if (X509Certificate2.GetCertContentType(blob) == X509ContentType.Pfx)
    {
          throw new Exception("PFX blobs are disallowed.");
    }
   else
   {
         // Import only after we have confirmed it's not a PFX.
        return new X509Certificate2(blob);
    }
} 

Якщо вам потрібно імпортувати безпарольний блок сертифіката закритого ключа та ви переконалися, що йому можна довіряти, ви можете скасувати додаткові перевірки перевірки, які виконуються у випуску системи безпеки від 13 червня 2023 року, викликавши інше перевантаження конструктора. Наприклад, ви можете викликати перевантаження конструктора, який приймає рядковий аргумент password , і передати null для значення аргументу.

byte[] blobToImport = GetBlobToImport(); // fetch this from a database, config, etc. 

// REGRESSION - byte[] ctor performs additional security checks X509Certificate2 certA = new X509Certificate2(blobToImport);

// RECOMMENDED WORKAROUND - different ctor overload suppresses additional security checks X509Certificate2 certB = new X509Certificate2(blobToImport, (string)null);

Варіант 3. Змінення або заборона додаткової перевірки за допомогою змінної середовища

Застосовність: Цей параметр застосовується лише до всіх версій .NET Framework.  Вони не застосовуються до .NET 6.0+.

Хоча .NET Framework за замовчуванням обмежувати операції імпорту щонайбільше 600 000 ітерацій пароля, це обмеження можна настроїти на рівні всієї програми або комп'ютера за допомогою змінної середовища. Це нове обмеження застосовуватиметься до всіх викликів наведених вище API, яких це стосується.

Щоб змінити обмеження, установіть для змінної COMPlus_Pkcs12UnspecifiedPasswordIterationLimit середовища значення нового обмеження. Наприклад, щоб установити обмеження в 1 000 000 (один мільйон) ітерацій, задайте змінну середовища, як показано нижче.

  • Це число контролює загальний ліміт ітерацій, який є сумою кількості ітерацій MAC, зашифрованого безпечного вмісту та кількості ітерацій сумки з кожухом. Якщо ви вручну експортували PFX за допомогою явної кількості <ітерацій iter_count> (наприклад, через openssl pkcs12 -export -iter <iter_count>) і хочете імпортувати цю BLOB-адресу PFX, встановіть для цієї змінної середовища значення принаймні такого ж розміру, як сума всіх очікуваних ітерацій. На практиці .NET Framework і .NET можуть допускати, щоб загальна кількість ітерацій дещо перевищувала будь-яке явне обмеження, налаштоване тут.

COMPlus_Pkcs12UnspecifiedPasswordIterationLimit=1000000

Щоб повністю заборонити додаткові перевірки, встановіть для змінної середовища спеціальне дозорне значення -1, як показано нижче.

  • ⚠️ Попередження: Встановлюйте значення змінної середовища -1, лише якщо ви впевнені, що цільова програма не обробляє ненадійні вхідні дані сертифіката.

COMPlus_Pkcs12UnspecifiedPasswordIterationLimit=-1

Варіант 4. Змінення або заборона додаткової перевірки за допомогою AppContext

Застосовність: Цей параметр застосовується тільки до .NET 6.0+.  Це не стосується .NET Framework

Хоча .NET за замовчуванням обмежує операції імпорту щонайбільше 600 000 ітерацій пароля, це обмеження можна налаштувати для всієї програми за допомогою перемикача AppContext. Це нове обмеження застосовуватиметься до всіх викликів наведених вище API, яких це стосується.

Щоб змінити обмеження, установіть перемикач AppContext для параметра System.Security.Cryptography.Pkcs12UnspecifiedPasswordIterationLimit значення, яке має бути в новому ліміті. Наприклад, щоб установити обмеження в 1 000 000 (один мільйон) повторів, установіть перемикач, як показано нижче.

  • Це число контролює загальний ліміт ітерацій, який є сумою кількості ітерацій MAC, зашифрованого безпечного вмісту та кількості ітерацій сумки з кожухом. Якщо ви вручну експортували PFX за допомогою явної кількості <ітерацій iter_count> (наприклад, через openssl pkcs12 -export -iter <iter_count>) і хочете імпортувати цю BLOB-адресу PFX, встановіть для цієї змінної середовища значення принаймні такого ж розміру, як сума всіх очікуваних ітерацій. На практиці .NET може допускати, щоб загальна кількість ітерацій дещо перевищувала будь-яке явне обмеження, налаштоване тут.

Щоб установити перемикач у файлі проекту програми (CSPROJ або VBPROJ):

<!--

  • Цей перемикач працює, лише якщо поточний файл проекту представляє програму. Вона не діє, якщо файл поточного проекту представляє спільну бібліотеку.

-->

<ItemGroup>

  • <RuntimeHostConfigurationOption include="System.Security.Cryptography.Pkcs12UnspecifiedPasswordIterationLimit" value="1000000" />

</ItemGroup>

Крім того, можна помістити файл з іменем runtimeconfig.template.json із таким вмістом у ту саму папку, яка містить файл проекту вашої програми:

{

     "configProperties": {

  • "System.Security.Cryptography.Pkcs12UnspecifiedPasswordIterationLimit": 1000000

      }

}

Докладні відомості про змінення параметрів конфігурації середовища виконання .NET див. на сторінці документації Параметри конфігурації середовища виконання .NET.

Щоб повністю заборонити додаткові перевірки, встановіть для перемикача конфігурації спеціальне значення вартового -1, як показано нижче.

⚠️ Попередження: Встановлюйте перемикач AppContext на -1, лише якщо ви впевнені, що цільова програма не обробляє ненадійні вхідні дані сертифіката.

У файлі проекту програми (CSPROJ або VBPROJ):

<!--

  • Цей перемикач працює, лише якщо поточний файл проекту представляє програму. Вона не діє, якщо файл поточного проекту представляє спільну бібліотеку.

-->

<ItemGroup>

  • <RuntimeHostConfigurationOption include="System.Security.Cryptography.Pkcs12UnspecifiedPasswordIterationLimit" value="-1" />

</ItemGroup>

Або у файлі runtimeconfig.template.json.

{

  • "configProperties": {
  • "System.Security.Cryptography.Pkcs12UnspecifiedPasswordIterationLimit": -1

     }

}

Варіант 5. Змінення або заборона додаткової перевірки на рівні машини за допомогою реєстру (лише для Windows для .NET Framework)

Застосовність: Цей параметр застосовується лише до всіх версій .NET Framework.  Вони не застосовуються до .NET 6.0+.

Хоча .NET Framework за замовчуванням обмежувати операції імпорту не більше ніж 600 000 ітерацій пароля, це обмеження можна налаштувати на рівні комп'ютера за допомогою реєстру HKLM. Це нове обмеження застосовуватиметься до всіх викликів наведених вище API, яких це стосується.

Щоб змінити обмеження, у розділі HKLM\Software\Microsoft\.NETFrameworkреєстру встановіть нове Pkcs12UnspecifiedPasswordIterationLimit обмеження. Наприклад, щоб установити обмеження в 1 000 000 (один мільйон) повторів, запустіть команди, як показано нижче, з командного рядка у режимі адміністратора.

  • Це число контролює загальний ліміт ітерацій, який є сумою кількості ітерацій MAC, зашифрованого безпечного вмісту та кількості ітерацій сумки з кожухом. Якщо ви вручну експортували PFX за допомогою явного iter_count> кількості <ітерацій (наприклад, через openssl pkcs12 -export -iter <iter_count>) і хочете імпортувати цей BLOB-об'єкт PFX, установіть для цього значення реєстру принаймні таке ж велике, як сума всіх очікуваних ітерацій. На практиці .NET Framework.NET Framework може дозволити дещо перевищувати загальну кількість ітерацій, вказане тут.
  • Параметр реєстру залежить від архітектури. Щоб програми дотримувалися налаштованого значення незалежно від їхньої цільової архітектури, не забудьте змінити 32- і 64-розрядний реєстри, як показано нижче.

reg add "HKLM\Software\Microsoft\.NETFramework" /v Pkcs12UnspecifiedPasswordIterationLimit /t REG_DWORD /d 1000000 /reg:32
reg add "HKLM\Software\Microsoft\.NETFramework" /v Pkcs12UnspecifiedPasswordIterationLimit /t REG_DWORD /d 1000000 /reg:64

Щоб повністю заборонити додаткові перевірки, установіть для реєстру значення -1 у командному рядку в режимі адміністратора, як показано нижче.

  • ⚠️ Попередження: Встановлюйте значення реєстру -1, лише якщо ви впевнені, що служби, запущені на цільовому комп'ютері, не обробляють ненадійні вхідні дані сертифіката.
  • Щоб установити значення -1 вартовий, використовуйте тип REG_SZ, а не тип REG_DWORD. Параметр реєстру залежить від архітектури. Щоб програми дотримувалися налаштованого значення незалежно від їхньої цільової архітектури, не забудьте змінити 32- і 64-розрядний реєстри, як показано нижче.

reg add "HKLM\Software\Microsoft\.NETFramework" /v Pkcs12UnspecifiedPasswordIterationLimit /t REG_SZ /d -1 /reg:32
reg add "HKLM\Software\Microsoft\.NETFramework" /v Pkcs12UnspecifiedPasswordIterationLimit /t REG_SZ /d -1 /reg:64

Щоб скасувати зміни реєстру, видаліть значення реєстру Pkcs12UnspecifiedPasswordIterationLimit із командного рядка в режимі адміністратора.

reg delete "HKLM\Software\Microsoft\.NETFramework" /v Pkcs12UnspecifiedPasswordIterationLimit /reg:32
reg delete "HKLM\Software\Microsoft\.NETFramework" /v Pkcs12UnspecifiedPasswordIterationLimit /reg:64

Нотатки для Windows.

У Windows .NET Framework імпортувати сертифікати за допомогою функції PFXImportCertStore. Ця функція виконує власну перевірку, зокрема накладає власні обмеження на максимально допустиму кількість ітерацій PFX-BLOB-об'єкта. Ці перевірки відбуватимуться під час імпорту PFX. Розділ . Описані вище змінні середовища та розділи реєстру для конкретного NET не впливають на те, як PFXImportCertStore виконує ці перевірки.