Notă: Revizuit la 22 iunie 2023 pentru a actualiza rezoluția și soluțiile de evitare
Notă: Revizuit la 15 iunie 2023 pentru a actualiza soluția de evitare a opțiunilor 4 și 5
Fundal
Pe 13 iunie 2023, Microsoft a lansat o actualizare de securitate pentru .NET Framework și .NET care afectează modul în care modulul runtime importă certificatele X.509. Aceste modificări pot face ca importul certificatului X.509 să genereze CryptographicException în scenariile în care importul ar fi reușit înainte de actualizare.
Acest document descrie modificarea și soluțiile de evitare disponibile pentru aplicațiile afectate.
Software afectat
- .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-uri afectate
- new X509Certificate(byte[])
- X509Certificate.Import(byte[])
- new X509Certificate2(byte[])
- X509Certificate2.Import(byte[])
- X509Certificate2Collection.Import(byte[])
Descrierea modificării
Înainte de modificarea din 13 iunie 2023, atunci când .NET Framework și .NET sunt prezentate cu un blob de certificat binar pentru import, .NET Framework și .NET delegau de obicei validarea și importul blobului la sistemul de operare subiacent. De exemplu, în Windows, .NET Framework și .NET se bazează de obicei pe API-ul PFXImportCertStore pentru validare și import.
Începând cu modificarea din 13 iunie 2023, atunci când .NET Framework și .NET sunt prezentate cu un blob de certificat binar pentru import, .NET Framework și .NET vor efectua, în unele circumstanțe, validări suplimentare înainte de a preda blobul sistemului de operare subiacent. Această validare suplimentară efectuează o serie de verificări euristice pentru a determina dacă certificatul de intrare ar epuiza rău intenționat resursele la import. Deoarece aceasta este o validare suplimentară dincolo de ceea ce ar efectua în mod normal sistemul de operare de bază, poate bloca bloburile de certificate care s-ar fi importat cu succes înainte de modificarea din 13 iunie 2023.
Regresii cunoscute
Dacă un certificat X.509 a fost exportat ca blob PFX utilizând un număr neobișnuit de mare de iterații de parolă, este posibil ca importul certificatului respectiv să nu reușească. Majoritatea facilităților de export al certificatelor utilizează un număr de iterații undeva între 2.000 și 10.000. După ce se aplică actualizarea de securitate, importul nu va reuși pentru certificatele care conțin un număr de iterații mai mare de 600.000.
Dacă un certificat X.509 a fost exportat utilizând o parolă nulă [de exemplu, prin
X509Certificate.Export(X509ContentType.Pfx, (string)null)sau fărăX509Certificate.Export(X509ContentType.Pfx)]parolă, importul acelui certificat poate acum să nu reușească.
Notă
Regresia de mai sus a fost abordată în actualizarea din 22 iunie 2023 discutată în KB5028608.
Dacă un certificat X.509 a fost exportat ca blob PFX utilizând capacitatea Windows de a proteja cheia privată pentru un SID, importul acelui certificat poate acum să nu reușească. Acest lucru va afecta bloburile PFX create în următoarele moduri:
- Prin Expertul de export certificat din Windows și specificând în expert că cheia privată ar trebui să fie protejată pentru un utilizator de domeniu; sau
- Prin cmdletul Export-PfxCertificate din PowerShell, unde este furnizat un argument explicit
-ProtectTo; sau - Prin intermediul utilitarului certutil , unde este furnizat un argument explicit
-protectto; sau - Prin API-ul PFXExportCertStoreEx , unde este furnizată semnalizarea PKCS12_PROTECT_TO_DOMAIN_SIDS.
Rezolvarea & soluțiile de evitare
Există diverse soluții de evitare, în funcție de ceea ce doriți: dacă doriți să faceți modificări direcționate la site-uri de apelare individuale din codul dvs., dacă doriți să modificați comportamentul unei singure aplicații sau dacă doriți să efectuați modificări la nivel de computer.
Opțiunea 1 (preferată) - Instalați o corecție actualizată
Notă
Aceasta este opțiunea preferată, deoarece se adresează regresiilor clienților raportate frecvent și nu necesită modificări de cod ale aplicației.
Aplicabilitate: această opțiune se aplică tuturor versiunilor de .NET Framework și .NET.
Această problemă a fost abordată în actualizarea din 22 iunie 2023 discutată în KB5028608.
Microsoft recomandă clienților care se confruntă cu regresii introduse prin lansarea din 13 iunie 2023 să încerce să instaleze această corecție actualizată înainte de a încerca soluțiile listate mai jos în acest document.
Opțiunea 2 - Modificarea site-ului de apelare
Aplicabilitate: această opțiune se aplică tuturor versiunilor de .NET Framework și .NET.
Verificați dacă blobul pe care îl importați este de încredere. De exemplu, blobul a fost regăsit dintr-o locație de încredere, cum ar fi o bază de date sau un fișier de configurare controlat de dvs., sau a fost furnizat printr-o solicitare de rețea făcută de un client neautentificat sau neprivilegiat?
Microsoft recomandă cu tărie să nu importați bloburi PFX furnizate de clienți neautentificați sau neprivilegiați, deoarece aceste bloburi ar putea conține comportamente rău intenționate de epuizare a resurselor.
Dacă trebuie să importați un blob de certificat cu cheie publică oferit de o parte care nu este de încredere, puteți utiliza următorul cod pentru a importa în siguranță un astfel de blob. Acest exemplu de cod utilizează metoda GetCertContentType pentru a determina care este tipul de bază al blobului de certificat și respinge bloburile PFX în cazurile în care vă așteptați să importați doar un blob de certificat cu cheie publică. Constructorul X509Certificate2(byte[]) este sigur pentru utilizare atunci când sunt oferite bloburi non-PFX care nu sunt de încredere.
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);
}
}
Dacă trebuie să importați un blob de certificat cu cheie privată fără parolă și ați stabilit că blobul este de încredere, puteți suprima verificările suplimentare de validare efectuate de versiunea de securitate din 13 iunie 2023, apelând o altă supraîncărcare de constructor. De exemplu, puteți să apelați supraîncărcarea constructorului, care acceptă un șir de argument parolă și să transmiteți null pentru valoarea argumentului.
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);
Opțiunea 3 - Modificarea sau suprimarea validării suplimentare utilizând o variabilă de mediu
Aplicabilitate: această opțiune se aplică doar pentru toate versiunile de .NET Framework. Nu se aplică la .NET 6.0+.
Deși .NET Framework limitează în mod implicit operațiunile de import pentru a nu necesita mai mult de 600.000 de iterații ale unei parole, această limită poate fi configurată la nivel de aplicație sau la nivel de computer, utilizând o variabilă de mediu. Această nouă limită se va aplica tuturor invocărilor API-urilor afectate listate mai sus.
Pentru a modifica limita, setați variabila COMPlus_Pkcs12UnspecifiedPasswordIterationLimit de mediu la valoarea noii limite. De exemplu, pentru a stabili limita la 1.000.000 (un milion) de iterații, setați variabila de mediu așa cum se arată mai jos.
- Acest număr controlează limita totală de iterații, care este suma numărului de iterații MAC, a conținutului sigur criptat și a numărului de iterații ale sacului învelit. Dacă ați exportat manual un PFX utilizând un iter_count de număr <explicit de iterații (de exemplu, prin openssl pkcs12 -export -iter <iter_count>) și doriți să importați acel blob PFX, setați această variabilă de mediu la o valoare cel puțin egală cu suma tuturor iterațiilor așteptate.> De obicei, .NET Framework și .NET pot permite numărului total de iterații să depășească ușor orice limită explicită configurată aici.
COMPlus_Pkcs12UnspecifiedPasswordIterationLimit=1000000
Pentru a suprima în întregime verificările suplimentare, setați variabila de mediu la valoarea specială Sentinel, -1, așa cum se arată mai jos.
- ⚠️ Avertisment: setați valoarea variabilei de mediu la -1 doar dacă sunteți sigur că aplicația țintă nu tratează intrările de certificate care nu sunt de încredere.
COMPlus_Pkcs12UnspecifiedPasswordIterationLimit=-1
Opțiunea 4 - Modificarea sau suprimarea validării suplimentare utilizând AppContext
Aplicabilitate: această opțiune se aplică doar la .NET 6.0+. Nu se aplică la .NET Framework
Deși .NET limitează în mod implicit operațiunile de import pentru a nu ocupa mai mult de 600.000 de iterații ale unei parole, această limită poate fi configurată la nivelul întregii aplicații utilizând comutatorul AppContext. Această nouă limită se va aplica tuturor invocărilor API-urilor afectate listate mai sus.
Pentru a modifica limita, setați comutatorul AppContext System.Security.Cryptography.Pkcs12UnspecifiedPasswordIterationLimit la valoarea care ar trebui să fie noua limită. De exemplu, pentru a stabili limita la 1.000.000 (un milion) de iterații, setați comutatorul așa cum se arată mai jos.
- Acest număr controlează limita totală de iterații, care este suma numărului de iterații MAC, a conținutului sigur criptat și a numărului de iterații ale sacului învelit. Dacă ați exportat manual un PFX utilizând un iter_count de număr <explicit de iterații (de exemplu, prin openssl pkcs12 -export -iter <iter_count>) și doriți să importați acel blob PFX, setați această variabilă de mediu la o valoare cel puțin egală cu suma tuturor iterațiilor așteptate.> De obicei, .NET poate permite numărului total de iterații să depășească ușor orice limită explicită configurată aici.
Pentru a seta comutarea în fișierul de proiect al aplicației (.csproj sau .vbproj):
<!--
- Acest comutator funcționează doar dacă fișierul de proiect curent reprezintă o aplicație. Nu are niciun efect dacă fișierul de proiect curent reprezintă o bibliotecă partajată.
-->
<ItemGroup>
- <RuntimeHostConfigurationOption Include="System.Security.Cryptography.Pkcs12UnspecifiedPasswordIterationLimit" Value="1000000" />
</ItemGroup>
Alternativ, puteți plasa un fișier denumit runtimeconfig.template.json cu următorul conținut în același director care conține fișierul de proiect al aplicației:
{
"configProperties": {
- "System.Security.Cryptography.Pkcs12UnspecifiedPasswordIterationLimit": 1000000
}
}
Pentru mai multe informații despre modificarea setărilor de configurare runtime .NET, consultați pagina de documentație Setările de configurare runtime .NET.
Pentru a suprima în întregime verificările suplimentare, setați valoarea specială sentinel -1 în comutatorul de configurație, așa cum se arată mai jos.
⚠️ Avertisment: setați comutatorul AppContext la -1 doar dacă sunteți sigur că aplicația țintă nu tratează intrările de certificate care nu sunt de încredere.
În fișierul de proiect al aplicației (.csproj sau .vbproj):
<!--
- Acest comutator funcționează doar dacă fișierul de proiect curent reprezintă o aplicație. Nu are niciun efect dacă fișierul de proiect curent reprezintă o bibliotecă partajată.
-->
<ItemGroup>
- <RuntimeHostConfigurationOption include="System.Security.Cryptography.Pkcs12UnspecifiedPasswordIterationLimit" value="-1" />
</ItemGroup>
Sau în fișierul runtimeconfig.template.json:
{
- "configProperties": {
- "System.Security.Cryptography.Pkcs12UnspecifiedPasswordIterationLimit": -1
}
}
Opțiunea 5 - Modificarea sau suprimarea validării suplimentare la nivel de computer prin registry (numai pentru Windows pentru .NET Framework)
Aplicabilitate: această opțiune se aplică doar pentru toate versiunile de .NET Framework. Nu se aplică la .NET 6.0+.
Deși .NET Framework limitează în mod implicit operațiunile de import pentru a nu necesita mai mult de 600.000 de iterații ale unei parole, această limită poate fi configurată la nivel de mașină utilizând registry HKLM. Această nouă limită se va aplica tuturor invocărilor API-urilor afectate listate mai sus.
Pentru a modifica limita, sub cheia HKLM\Software\Microsoft\.NETFrameworkde registry, setați valoarea Pkcs12UnspecifiedPasswordIterationLimit la care ar trebui să fie noua limită. De exemplu, pentru a stabili limita la 1.000.000 (un milion) de iterații, rulați comenzile așa cum se arată mai jos dintr-o linie de comandă cu drepturi sporite.
- Acest număr controlează limita totală de iterații, care este suma numărului de iterații MAC, a conținutului sigur criptat și a numărului de iterații ale sacului învelit. Dacă ați exportat manual un PFX utilizând un iter_count> explicit de număr de <iterații (de exemplu, prin openssl pkcs12 -export -iter <iter_count>) și doriți să importați acel blob PFX, setați această valoare de registry la o valoare cel puțin egală cu suma tuturor iterațiilor așteptate. De obicei, .NET Framework poate permite ca numărul total de iterații să depășească ușor orice limită explicită configurată aici.
- Setarea de registry este dependentă de arhitectură. Pentru a vă asigura că aplicațiile respectă valoarea configurată indiferent de arhitectura țintă, nu uitați să modificați atât registry-ul pe 32 de biți, cât și pe cel pe 64 de biți, așa cum se arată mai jos.
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
Pentru a suprima în întregime verificările suplimentare, setați valoarea de registry la -1 dintr-o linie de comandă cu drepturi sporite, așa cum se arată mai jos.
- ⚠️ Avertisment: setați valoarea de registry la -1 doar dacă sunteți sigur că serviciile care rulează pe computerul țintă nu gestionează intrările de certificate care nu sunt de încredere.
- Pentru a seta sentinela -1, utilizați tipul REG_SZ în locul tipului REG_DWORD. Setarea de registry este dependentă de arhitectură. Pentru a vă asigura că aplicațiile respectă valoarea configurată indiferent de arhitectura țintă, nu uitați să modificați atât registry-ul pe 32 de biți, cât și pe cel pe 64 de biți, așa cum se arată mai jos.
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
Pentru a anula modificările din registry, ștergeți valoarea reg Pkcs12UnspecifiedPasswordIterationLimit dintr-o linie de comandă cu drepturi sporite.
reg delete "HKLM\Software\Microsoft\.NETFramework" /v Pkcs12UnspecifiedPasswordIterationLimit /reg:32
reg delete "HKLM\Software\Microsoft\.NETFramework" /v Pkcs12UnspecifiedPasswordIterationLimit /reg:64
Note specifice pentru Windows
În Windows, .NET Framework importă certificate prin funcția PFXImportCertStore. Această funcție efectuează propriile validări, inclusiv plasarea propriilor limite pentru numărul maxim de iterații permise al unui blob PFX. Aceste verificări vor avea loc în continuare la importul PFX. Fișierul . Variabilele de mediu specifice NET și cheile de registry descrise mai sus nu afectează modul în care PFXImportCertStore efectuează aceste verificări.