Забележка: Преработено на 22 юни 2023 г. за актуализиране на разделителната способност и заобиколните решения
Забележка: Преработено на 15 юни 2023 г. с цел актуализиране на заобикалянето на опции 4 и 5
Обща информация
На 13 юни 2023 г. Microsoft пусна актуализация на защитата за .NET Framework (платформа) и .NET, която влияе върху начина, по който изпълнимият модул импортира X.509 сертификати. Тези промени може да доведат до връщане на CryptographicException при импортирането на X.509 сертификат в сценарии, при които импортирането е било успешно преди актуализацията.
Този документ описва промяната и заобиколните решения, налични за засегнатите приложения.
Засегнат софтуер
- .NET Framework (платформа) 2.0
- .NET Framework (платформа) 4.6.2, 4.7, 4.7.1, 4.7.2
- .NET Framework (платформа) 4.8
- .NET Framework (платформа) 4.8.1
- .NET 6.0
- .NET 7.0
Засегнати API
- new X509Certificate(byte[])
- X509Certificate.Import(byte[])
- new X509Certificate2(byte[])
- X509Certificate2.Import(байт[])
- X509Certificate2Collection.Import(byte[])
Описание на промяната
Преди промяната от 13 юни 2023 г., когато .NET Framework (платформа) и .NET се представят с двоичен сертификат за импортиране, .NET Framework (платформа) и .NET обикновено делегират проверка и импортиране на BLOB на основната операционна система. Например в Windows .NET Framework (платформа) и .NET обикновено разчитат на API на PFXImportCertStore за валидиране и импортиране.
Считано от промяната от 13 юни 2023 г., когато .NET Framework (платформа) и .NET се представят с двоичен сертификат за импортиране, .NET Framework (платформа) и .NET при някои обстоятелства ще извършат допълнителна проверка, преди да предадат големия двоичен обект на основната операционна система. Тази допълнителна проверка извършва поредица от евристични проверки, за да определи дали входящият сертификат ще изчерпи злонамерено ресурси при импортиране. Тъй като това е допълнителна проверка извън това, което обикновено би изпълнявала основната операционна система, тя може да блокира големи двоични обекти на сертификати, които биха били успешно импортирани преди промяната от 13 юни 2023 г.
Известни регресии
Ако X.509 сертификат е бил експортиран като PFX blob с помощта на необичайно голям брой итерации на пароли, този сертификат може да не успее да се импортира. Повечето съоръжения за експорт на сертификати използват брой на итерации някъде между 2000 – 10 000. След като се приложи актуализацията на защитата, импортирането ще бъде неуспешно за сертификати, съдържащи брой итерации, по-голям от 600 000.
Ако X.509 сертификат е експортиран чрез нулева парола [например чрез
X509Certificate.Export(X509ContentType.Pfx, (string)null)или безX509Certificate.Export(X509ContentType.Pfx)]парола, този сертификат сега може да не успее да се импортира.
Забележка
Горната регресия е разгледана в актуализацията от 22 юни 2023 г., обсъдена в KB5028608.
Ако X.509 сертификат е бил експортиран като PFX blob с помощта на възможността на Windows да защитава личния ключ за SID, този сертификат сега може да не успее да се импортира. Това ще се отрази на PFX обектите, създадени по следните начини:
- Чрез съветника за експортиране на сертификати на Windows и указване в съветника, че личният ключ трябва да бъде защитен за потребител на домейн; или
- Чрез кратката команда Export-PfxCertificate на PowerShell, където е предоставен изричен
-ProtectToаргумент; или - Чрез помощната програма certutil , където е предоставен изричен
-protecttoаргумент; или - Чрез API на PFXExportCertStoreEx , където е предоставен флагът за PKCS12_PROTECT_TO_DOMAIN_SIDS.
Решение & заобиколни решения
Съществуват различни заобиколни решения в зависимост от това дали искате да направите целенасочени промени в отделни сайтове за повиквания във вашия код, или искате да промените поведението на едно приложение, или искате да направите промени за целия апарат.
Опция 1 (предпочитана) – Инсталиране на актуализирана корекция
Забележка
Това е предпочитаната опция, тъй като тя адресира често съобщавани регресии на клиенти и не изисква промени в кода на приложението.
Приложимост: Тази опция се прилага за всички версии на .NET Framework (платформа) и .NET.
Този проблем е разгледан в актуализацията от 22 юни 2023 г., обсъдена в KB5028608.
Microsoft препоръчва на клиентите, които се сблъскват с регресии, въведени от изданието от 13 юни 2023 г., да се опитат да инсталират тази актуализирана корекция, преди да опитат заобиколните решения, изброени по-нататък в този документ.
Опция 2 – Промяна на сайта за повикване
Приложимост: Тази опция се прилага за всички версии на .NET Framework (платформа) и .NET.
Помислете дали големият двоичен обект, който импортирате, е надежден. Например дали голям двоичен обект е извлечен от надеждно местоположение, като например база данни или конфигурационен файл под ваш контрол, или е предоставен чрез мрежова заявка, направена от неудостоверен или непривилегирован клиент?
Microsoft силно препоръчва да не импортирате PFX BLOB, предоставени ви от неудостоверени или непривилегировани клиенти, тъй като тези BLOB обекти може да съдържат злонамерено поведение на изчерпване на ресурсите.
Ако трябва да импортирате голям двоичен обект на сертификат на публичен ключ , предоставен ви от ненадеждно лице, можете да използвате следния код за безопасно импортиране на такъв голям двоичен обект. Този примерен код използва метода GetCertContentType , за да определи какъв е базовият тип на сертификата, и отхвърля PFX BLOB в случаите, когато очаквате да импортирате само голям двоичен обект на сертификат с публичен ключ. Конструкторът X509Certificate2(byte[]) е безопасен за използване, когато му са дадени ненадеждни не-PFX blobs.
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 г., като извикате претоварване с друг конструктор. Можете например да извикате претоварване на конструктора, който приема аргумента за низова парола , и да предадете 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>) и искате да импортирате този PFX BLOB, задайте за тази променлива на средата стойност поне колкото сумата на всички очаквани итерации. На практика .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>) и искате да импортирате този PFX BLOB, задайте за тази променлива на средата стойност поне колкото сумата на всички очаквани итерации. На практика .NET може да позволи общият брой итерации да надхвърли малко което и да е изрично конфигурирано тук ограничение.
За да зададете ключа във файла на проекта на вашето приложение (.csproj или .vbproj):
<!--
- Този ключ работи само ако текущият файл на проекта представлява приложение. Това няма ефект, ако текущият файл на проекта представлява споделена библиотека.
-->
<ItemGroup>
- <RuntimeHostConfigurationOption include="System.Security.Cryptography.Pkcs12UnspecifiedPasswordIterationLimit" value="1000000" />
</ItemGroup>
Можете също така да поставите файл с име runtimeconfig.template.json със следното съдържание в същата директория, която съдържа файла на проекта на вашето приложение:
{
"configProperties": {
- "System.Security.Cryptography.Pkcs12UnspecifiedPasswordIterationLimit": 1000000
}
}
За повече информация относно промяната на настройките за конфигурация на изпълнимия модул на .NET вижте страницата с документация за настройките за конфигурация на .NET Runtime.
За да забраните напълно допълнителните проверки, задайте на превключвателя на конфигурацията специалната стойност за стража -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>) и искате да импортирате този PFX BLOB, задайте за тази стойност в системния регистър стойност поне равна на сумата на всички очаквани итерации. На практика .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 извършва тези проверки.