Uwaga: Zaktualizowano 22 czerwca 2023 r. w celu zaktualizowania rozwiązania i obejść
Uwaga: Zaktualizowano 15 czerwca 2023 r. w celu zaktualizowania obejścia opcji 4 i 5
Informacje ogólne
13 czerwca 2023 r. firma Microsoft wydała aktualizację zabezpieczeń dla platform .NET Framework i .NET, która wpływa na sposób importowania certyfikatów X.509 w środowisku uruchomieniowym. Te zmiany mogą spowodować, że import certyfikatu X.509 zliczy wyjątek CryptographicException w scenariuszach, w których import powiódłby się przed aktualizacją.
W tym dokumencie opisano zmiany i obejścia dostępne dla aplikacji, których dotyczy problem.
Oprogramowanie, którego dotyczy problem
- .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
Interfejsy API, których dotyczy problem
- new X509Certificate(byte[])
- X509Certificate.Import(byte[])
- nowy X509Certificate2(bajt[])
- X509Certificate2.Import(byte[])
- X509Certificate2Collection.Import(byte[])
Opis zmiany
Przed zmianą 13 czerwca 2023 r., gdy platformy .NET Framework i .NET są przedstawiane binarne obiekty blob certyfikatu do importowania, platformy .NET Framework i .NET zwykle delegują walidację i import obiektu blob do bazowego systemu operacyjnego. Na przykład w systemie Windows platformy .NET Framework i .NET zwykle korzystają z interfejsu API PFXImportCertStore na potrzeby sprawdzania poprawności i importowania.
Od 13 czerwca 2023 r. zmiana, gdy platformy .NET Framework i .NET są przedstawiane binarne obiekty blob certyfikatu do importowania, platformy .NET Framework i .NET w pewnych okolicznościach przeprowadzą dodatkową walidację przed przekazaniem obiektu blob do bazowego systemu operacyjnego. Ta dodatkowa weryfikacja wykonuje serię testów heurystycznych w celu ustalenia, czy przychodzący certyfikat złośliwie wyczerpie zasoby podczas importowania. Ponieważ jest to dodatkowa weryfikacja wykraczająca poza to, co normalnie wykonałby bazowy system operacyjny, może blokować obiekty blob certyfikatu, które zostałyby pomyślnie zaimportowane przed zmianą z 13 czerwca 2023 r.
Znane regresje
Jeśli certyfikat X.509 został wyeksportowany jako obiekt blob PFX przy użyciu niezwykle wysokiej liczby iteracji hasła, importowanie tego certyfikatu może się teraz nie powieść. Większość obiektów eksportu certyfikatów używa liczby iteracji z przedziału od 2000 do 10 000. Po zastosowaniu aktualizacji zabezpieczeń importowanie certyfikatów zawierających liczbę iteracji większą niż 600 000 nie powiedzie się.
Jeśli certyfikat X.509 został wyeksportowany przy użyciu hasła null [np. za pośrednictwem
X509Certificate.Export(X509ContentType.Pfx, (string)null)lub bezX509Certificate.Export(X509ContentType.Pfx)]hasła], importowanie tego certyfikatu może się teraz nie powieść.
Uwaga
Powyższa regresja została rozwiązana w aktualizacji z 22 czerwca 2023 r. omówionej w KB5028608.
Jeśli certyfikat X.509 został wyeksportowany jako obiekt blob PFX przy użyciu funkcji systemu Windows do ochrony klucza prywatnego identyfikatora SID, importowanie tego certyfikatu może się teraz nie powieść. Ma to wpływ na obiekty blob PFX utworzone w następujący sposób:
- Za pośrednictwem Kreatora eksportu certyfikatów systemu Windows i określając w kreatorze, że klucz prywatny ma być chroniony przed użytkownikiem domeny; lub
- Za pośrednictwem polecenia cmdlet Export-PfxCertificate programu PowerShell, w którym podano jawny
-ProtectToargument; lub - Za pośrednictwem narzędzia certutil , w którym podano jawny
-protecttoargument; lub - Za pośrednictwem interfejsu API PFXExportCertStoreEx , w którym jest podana flaga PKCS12_PROTECT_TO_DOMAIN_SIDS.
Rozwiązanie & obejścia
Istnieją różne obejścia, w zależności od tego, czy chcesz wprowadzić docelowe zmiany w poszczególnych lokacjach wywołań w kodzie, czy chcesz zmienić zachowanie pojedynczej aplikacji, czy też chcesz wprowadzić zmiany na całej maszynie.
Opcja 1 (preferowana) — zainstalowanie zaktualizowanej poprawki
Uwaga
Jest to preferowana opcja, ponieważ dotyczy często zgłaszanych przez klienta regresji i nie wymaga żadnych zmian w kodzie aplikacji.
Zastosowanie: Ta opcja ma zastosowanie do wszystkich wersji oprogramowania .NET Framework i .NET.
Ten problem został rozwiązany w aktualizacji z 22 czerwca 2023 r. omówionej w KB5028608.
Firma Microsoft zaleca, aby klienci, u których występują regresje wprowadzone przez wydanie z 13 czerwca 2023 r., spróbowali zainstalować tę zaktualizowaną poprawkę przed wypróbowaniem obejść wymienionych w dalszej części tego dokumentu.
Opcja 2 — modyfikowanie witryny połączeń
Zastosowanie: Ta opcja ma zastosowanie do wszystkich wersji oprogramowania .NET Framework i .NET.
Zastanów się, czy importowany obiekt blob jest godny zaufania. Na przykład, czy obiekt blob został pobrany z zaufanej lokalizacji, takiej jak baza danych lub plik konfiguracji pod Twoją kontrolą, czy też został dostarczony za pośrednictwem żądania sieciowego wykonanego przez nieuwierzytelnionego lub nieuprawnionego klienta?
Firma Microsoft zdecydowanie zaleca, aby nie importować obiektów blob PFX dostarczonych przez nieuwierzytelnionych lub nieuprzywilejowanych klientów, ponieważ te obiekty blob mogą zawierać złośliwe zachowania wyczerpania zasobów.
Jeśli musisz zaimportować obiekt blob certyfikatu klucza publicznego przekazany przez niezaufaną stronę, możesz użyć poniższego kodu, aby bezpiecznie zaimportować taki obiekt blob. Ten przykładowy kod używa metody GetCertContentType w celu określenia, jaki jest typ bazowy obiektu blob certyfikatu, i odrzuca obiekty blob PFX w przypadkach, gdy spodziewasz się zaimportować tylko obiekt blob certyfikatu klucza publicznego. Konstruktor X509Certificate2(byte[]) jest bezpieczny w użyciu, gdy otrzyma niezaufane obiekty blob inne niż 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);
}
}
Jeśli musisz zaimportować obiekt blob certyfikatu klucza prywatnego bez użycia haseł i ustalisz, że obiekt blob jest godny zaufania, możesz pominąć dodatkowe testy weryfikacji wykonywane w wersji zabezpieczeń z 13 czerwca 2023 r., wywołując inne przeciążenie konstruktora. Na przykład można wywołać przeciążenie konstruktora, który akceptuje argument hasła ciągu i przekazuje wartość null dla wartości argumentu.
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);
Opcja 3 — modyfikowanie lub pomijanie dodatkowej walidacji przy użyciu zmiennej środowiskowej
Zastosowanie: Ta opcja dotyczy tylko wszystkich wersji programu .NET Framework. Nie dotyczy to platformy .NET 6.0+.
Chociaż program .NET Framework domyślnie ogranicza operacje importowania do nie więcej niż 600 000 iteracji hasła, ten limit można skonfigurować w całej aplikacji lub na całym komputerze przy użyciu zmiennej środowiskowej. Ten nowy limit będzie miał zastosowanie do wszystkich wywołań wymienionych powyżej interfejsów API, których dotyczy problem.
Aby zmienić limit, ustaw zmienną COMPlus_Pkcs12UnspecifiedPasswordIterationLimit środowiskową na wartość nowego limitu. Aby na przykład ustawić limit 1 000 000 (milion) iteracji, ustaw zmienną środowiskową w sposób pokazany poniżej.
- Ta liczba steruje całkowitym limitem iteracji, który jest sumą liczby iteracji MAC, zaszyfrowanej zawartości sejfu i liczby iteracji osłoniętej torby. Jeśli ręcznie wyeksportowałeś PFX przy użyciu jawnej liczby <iteracji iter_count> (np. za pomocą openssl pkcs12 -export -iter <iter_count>) i chcesz zaimportować ten obiekt blob PFX, ustaw tę zmienną środowiskową na wartość co najmniej tak dużą, jak suma wszystkich oczekiwanych iteracji. W praktyce platformy .NET Framework i .NET mogą zezwolić, aby całkowita liczba iteracji nieznacznie przekroczyła jawnie skonfigurowany limit.
COMPlus_Pkcs12UnspecifiedPasswordIterationLimit=1000000
Aby całkowicie pominąć dodatkowe testy, ustaw zmienną środowiskową na specjalną wartość wartowniczą -1, jak pokazano poniżej.
- ⚠️ Ostrzeżenie: ustaw wartość zmiennej środowiskowej na -1 tylko wtedy, gdy masz pewność, że aplikacja docelowa nie obsługuje niezaufanych danych wejściowych certyfikatu.
COMPlus_Pkcs12UnspecifiedPasswordIterationLimit=-1
Opcja 4 — modyfikowanie lub pomijanie dodatkowej weryfikacji przy użyciu funkcji AppContext
Zastosowanie: Ta opcja dotyczy tylko platformy .NET 6.0+. Nie dotyczy to platformy .NET Framework
Podczas gdy platforma .NET domyślnie ogranicza operacje importowania do nie więcej niż 600 000 iteracji hasła, ten limit można skonfigurować w całej aplikacji przy użyciu przełącznika AppContext . Ten nowy limit będzie miał zastosowanie do wszystkich wywołań wymienionych powyżej interfejsów API, których dotyczy problem.
Aby zmienić limit, ustaw przełącznik kontekstu AppContext System.Security.Cryptography.Pkcs12UnspecifiedPasswordIterationLimit na wartość nowego limitu. Aby na przykład ustawić limit 1 000 000 (milion) iteracji, ustaw przełącznik tak, jak pokazano poniżej.
- Ta liczba steruje całkowitym limitem iteracji, który jest sumą liczby iteracji MAC, zaszyfrowanej zawartości sejfu i liczby iteracji osłoniętej torby. Jeśli ręcznie wyeksportowałeś PFX przy użyciu jawnej liczby <iteracji iter_count> (np. za pomocą openssl pkcs12 -export -iter <iter_count>) i chcesz zaimportować ten obiekt blob PFX, ustaw tę zmienną środowiskową na wartość co najmniej tak dużą, jak suma wszystkich oczekiwanych iteracji. W praktyce platforma .NET może pozwolić, aby całkowita liczba iteracji nieznacznie przekroczyła jawny limit skonfigurowany w tym miejscu.
Aby ustawić przełącznik w pliku projektu aplikacji (csproj lub vbproj):
<!--
- Ten przełącznik działa tylko wtedy, gdy bieżący plik projektu reprezentuje aplikację. Nie ma to znaczenia, jeśli bieżący plik projektu reprezentuje bibliotekę udostępnioną.
-->
<ItemGroup>
- <RuntimeHostConfigurationOption include="System.Security.Cryptography.Pkcs12UnspecifiedPasswordIterationLimit" Value="1000000" />
</ItemGroup>
Alternatywnie możesz umieścić plik o nazwie runtimeconfig.template.json z następującą zawartością w tym samym katalogu, który zawiera plik projektu aplikacji:
{
"configProperties": {
- "System.Security.Cryptography.Pkcs12UnspecifiedPasswordIterationLimit": 1000000
}
}
Aby uzyskać więcej informacji na temat zmieniania ustawień konfiguracji środowiska uruchomieniowego platformy .NET, zobacz stronę dokumentacji Ustawienia konfiguracji środowiska uruchomieniowego platformy .NET.
Aby całkowicie pominąć dodatkowe testy, ustaw przełącznik konfiguracji na specjalną wartość wartowniczą -1, jak pokazano poniżej.
⚠️ Ostrzeżenie: ustaw przełącznik AppContext na -1 tylko wtedy, gdy masz pewność, że aplikacja docelowa nie obsługuje niezaufanych danych wejściowych certyfikatu.
W pliku projektu aplikacji (csproj lub vbproj):
<!--
- Ten przełącznik działa tylko wtedy, gdy bieżący plik projektu reprezentuje aplikację. Nie ma to znaczenia, jeśli bieżący plik projektu reprezentuje bibliotekę udostępnioną.
-->
<ItemGroup>
- <RuntimeHostConfigurationOption include="System.Security.Cryptography.Pkcs12UnspecifiedPasswordIterationLimit" wartość="-1" />
</ItemGroup>
Lub w pliku runtimeconfig.template.json:
{
- "configProperties": {
- "System.Security.Cryptography.Pkcs12UnspecifiedPasswordIterationLimit": -1
}
}
Opcja 5 — modyfikowanie lub pomijanie dodatkowej weryfikacji na całym komputerze za pośrednictwem rejestru (tylko system Windows dla platformy .NET Framework)
Zastosowanie: Ta opcja dotyczy tylko wszystkich wersji programu .NET Framework. Nie dotyczy to platformy .NET 6.0+.
Chociaż program .NET Framework domyślnie ogranicza operacje importowania do nie więcej niż 600 000 iteracji hasła, ten limit można skonfigurować na całym komputerze za pomocą rejestru HKLM. Ten nowy limit będzie miał zastosowanie do wszystkich wywołań wymienionych powyżej interfejsów API, których dotyczy problem.
Aby zmienić limit, w obszarze klucz HKLM\Software\Microsoft\.NETFrameworkrejestru ustaw wartość Pkcs12UnspecifiedPasswordIterationLimit nowego limitu. Aby na przykład ustawić limit 1 000 000 (milion) iteracji, uruchom pokazane poniżej polecenia z wiersza polecenia z podwyższonym poziomem uprawnień.
- Ta liczba steruje całkowitym limitem iteracji, który jest sumą liczby iteracji MAC, zaszyfrowanej zawartości sejfu i liczby iteracji osłoniętej torby. Jeśli ręcznie wyeksportowano plik PFX przy użyciu jawnego iter_count> liczby <iteracji (np. za pośrednictwem polecenia openssl pkcs12 -export -iter <iter_count>) i chcesz zaimportować ten obiekt blob PFX, ustaw tę wartość rejestru na wartość co najmniej tak dużą, jak suma wszystkich oczekiwanych iteracji. W praktyce program .NET Framework może zezwolić, aby całkowita liczba iteracji nieznacznie przekroczyła jawnie skonfigurowany limit.
- Ustawienie rejestru zależy od architektury. Aby zapewnić, że aplikacje przestrzegają skonfigurowanej wartości niezależnie od ich architektury docelowej, należy zmodyfikować zarówno 32-bitowe, jak i 64-bitowe rejestry, jak pokazano poniżej.
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
Aby całkowicie pominąć dodatkowe testy, ustaw wartość rejestru na -1 w wierszu polecenia z podwyższonym poziomem uprawnień, jak pokazano poniżej.
- ⚠️ Ostrzeżenie: ustaw wartość rejestru na -1 tylko wtedy, gdy masz pewność, że usługi uruchomione na maszynie docelowej nie obsługują danych wejściowych niezaufanego certyfikatu.
- Aby ustawić wartość -1 sentinel, użyj typu REG_SZ zamiast typu REG_DWORD. Ustawienie rejestru zależy od architektury. Aby zapewnić, że aplikacje przestrzegają skonfigurowanej wartości niezależnie od ich architektury docelowej, należy zmodyfikować zarówno 32-bitowe, jak i 64-bitowe rejestry, jak pokazano poniżej.
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
Aby przywrócić zmiany w rejestrze, usuń wartość rejestru Pkcs12UnspecifiedPasswordIterationLimit z wiersza polecenia z podwyższonym poziomem uprawnień.
reg delete "HKLM\Software\Microsoft\.NETFramework" /v Pkcs12UnspecifiedPasswordIterationLimit /reg:32
reg delete "HKLM\Software\Microsoft\.NETFramework" /v Pkcs12UnspecifiedPasswordIterationLimit /reg:64
Uwagi specyficzne dla systemu Windows
W systemie Windows certyfikaty programu .NET Framework są importowane przy użyciu funkcji PFXImportCertStore. Ta funkcja wykonuje własną weryfikację, w tym nakładanie własnych limitów na maksymalną dopuszczalną liczbę iteracji obiektu blob PFX. Te kontrole nadal będą miały miejsce po imporcie PFX. Plik . Zmienne środowiskowe specyficzne dla sieci NET i klucze rejestru opisane powyżej nie mają wpływu na sposób wykonywania tych testów przez magazyn PFXImportCertStore.