Applies To.NET

                참고:해결 방법 및 해결 방법을 업데이트하기 위해 2023년 6월 22일 수정

                참고:옵션 4 및 5에 대한 작업을 업데이트하도록 2023년 6월 15일 수정 

배경

2023년 6월 13일 Microsoft는 런타임이 X.509 인증서를 가져오는 방법에 영향을 주는 .NET Framework 및 .NET에 대한 보안 업데이트를 릴리스했습니다. 이러한 변경으로 인해 업데이트 전에 가져오기가 성공한 시나리오에서 X.509 인증서 가져오기가 CryptographicException을 throw할 수 있습니다.

이 문서에서는 영향을 받은 애플리케이션에 사용할 수 있는 변경 및 해결 방법을 설명합니다.

영향 받는 소프트웨어

  • .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

변경에 대한 설명

2023년 6월 13일 이전에 .NET Framework 및 .NET에 가져오기용 이진 인증서 Blob이 제공되면 .NET Framework 및 .NET은 일반적으로 Blob의 유효성 검사 및 가져오기를 기본 OS에 위임합니다. 예를 들어 Windows에서 .NET Framework 및 .NET은 일반적으로 유효성 검사 및 가져오기를 위해 PFXImportCertStore API를 사용합니다.

2023년 6월 13일부터 .NET Framework 및 .NET에 가져오기용 이진 인증서 Blob이 제공되면 .NET Framework 및 .NET은 경우에 따라 Blob을 기본 OS에 전달하기 전에 추가 유효성 검사를 수행합니다. 이 추가 유효성 검사는 일련의 추론 검사를 수행하여 들어오는 인증서가 가져올 때 리소스를 악의적으로 소모하는지 확인합니다. 이는 기본 OS가 일반적으로 수행하는 것 이상의 추가 유효성 검사이므로 2023년 6월 13일 이전에 성공적으로 가져온 인증서 Blob을 차단할 수 있습니다.

알려진 회귀

  1. X.509 인증서를 자주 사용하지 않는 높은 암호 반복 횟수를 사용하여 PFX Blob으로 내보낸 경우 해당 인증서를 가져오지 못할 수 있습니다. 대부분의 인증서 내보내기 기능은 2,000~10,000 사이의 반복 횟수를 사용합니다. 보안 업데이트가 적용되면 600,000보다 큰 반복 수를 포함하는 인증서에 대해 가져오기가 실패합니다.

  2. Null 암호(예:X509Certificate.Export(X509ContentType.Pfx, (string)null)또는 암호 없는X509Certificate.Export(X509ContentType.Pfx)])를 사용하여 X.509 인증서를 내보낸 경우 해당 인증서를 가져오지 못할 수 있습니다.  

    참고: 위의 회귀는 KB5028608에서 논의된 2023년 6월 22일 업데이트에서 해결되었습니다.

  3. WINDOWS의 기능을 사용하여 X.509 인증서를 PFX Blob으로 내보내 SID에 대한 프라이빗 키를 보호한 경우 해당 인증서를 가져오지 못할 수 있습니다. 이렇게 하면 다음과 같은 방식으로 만든 PFX Blob에 영향을 줍니다.

    • Windows의 인증서 내보내기 마법사 를 통해 마법사에서 프라이빗 키를 도메인 사용자로 보호해야 한다고 지정합니다. 또는

    • 명시적 -ProtectTo 인수가 제공되는 PowerShell의 Export-PfxCertificate cmdlet을 통해 또는

    • 명시적 -protectto 인수가 제공되는 certutil 유틸리티를 통해 또는

    • PFXExportCertStoreEx API를 통해 PKCS12_PROTECT_TO_DOMAIN_SIDS 플래그가 제공됩니다.

해결 방법 & 해결 방법

코드 내의 개별 호출 사이트에서 대상을 지정한 변경하거나 단일 애플리케이션의 동작을 변경하려는지 또는 컴퓨터 전체에서 변경하려는지에 따라 다양한 해결 방법이 있습니다.

옵션 1(기본 설정) - 업데이트된 패치 설치

참고: 일반적으로 보고된 고객 회귀를 해결하고 애플리케이션에 대한 코드 변경이 필요하지 않기 때문에 이 옵션이 기본 설정 옵션입니다.

적용 가능성: 이 옵션은 모든 버전의 .NET Framework 및 .NET에 적용됩니다.

이 문제는 KB5028608에서 논의된 2023년 6월 22일 업데이트에서 해결되었습니다.

Microsoft는 2023년 6월 13일 릴리스에서 도입된 회귀가 발생하는 고객에게 이 문서의 뒷부분에 나열된 해결 방법을 시도하기 전에 이 업데이트된 패치를 설치해 보라고 권장합니다.

옵션 2 - 통화 사이트 수정

적용 가능성: 이 옵션은 모든 버전의 .NET Framework 및 .NET에 적용됩니다.

가져오는 Blob이 신뢰할 수 있는지 여부를 고려합니다. 예를 들어 Blob이 사용자의 제어 하에 있는 데이터베이스 또는 구성 파일과 같은 신뢰할 수 있는 위치에서 검색되었거나 인증되지 않거나 권한 없는 클라이언트가 만든 네트워크 요청을 통해 제공되었나요?

이러한 Blob에는 악의적인 리소스 소모 동작이 포함될 수 있으므로 인증되지 않았거나 권한 없는 클라이언트에서 제공한 PFX Blob을 가져오지 않는 것이 좋습니다.

신뢰할 수 없는 당사자가 제공한 공개 키 인증서 Blob을 가져와야 하는 경우 다음 코드를 사용하여 이러한 Blob을 안전하게 가져올 수 있습니다. 이 샘플 코드는 GetCertContentType 메서드를 사용하여 인증서 Blob의 기본 형식을 확인하고 공개 키 인증서 Blob만 가져올 것으로 예상되는 경우 PFX Blob을 거부합니다. X509Certificate2(byte[]) 생성자는 신뢰할 수 없는 비 PFX Blob이 지정된 경우 사용하기에 안전합니다.

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);
    }
} 

암호 없는 프라이빗 키 인증서 Blob을 가져와야 하고 Blob이 신뢰할 수 있다고 판단한 경우 다른 생성자 오버로드를 호출하여 2023년 6월 13일 보안 릴리스에서 수행한 추가 유효성 검사를 표시하지 않을 수 있습니다. 예를 들어 문자열 암호 인수를 수락하고 인수 값에 대해 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 반복 수, 암호화된 안전한 콘텐츠 및 가려진 모음의 반복 횟수의 합계인 반복 제한을 제어합니다. 명시적 반복 횟수 <iter_count>(예: opensl pkcs12 -export -iter <iter_count> 통해)을 사용하여 PFX를 수동으로 내보내고 해당 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 반복 수, 암호화된 안전한 콘텐츠 및 가려진 모음의 반복 횟수의 합계인 총 반복 제한을 제어합니다. 명시적 반복 횟수 <iter_count>(예: opensl pkcs12 -export -iter <iter_count> 통해)을 사용하여 PFX를 수동으로 내보내고 해당 PFX Blob을 가져오려는 경우 이 환경 변수를 예상된 모든 반복의 합계만큼 큰 값으로 설정합니다. 실제로 .NET은 총 반복 횟수가 여기에 구성된 명시적 제한을 약간 초과하도록 허용할 수 있습니다.

애플리케이션의 프로젝트 파일(.csproj 또는 .vbproj) 내에서 스위치를 설정하려면:

<!--

  • This switch only works if the current project file represents an application. It has no effect if the current project file represents a shared library.

-->

<ItemGroup>

  • <RuntimeHostConfigurationOption Include="System.Security.Cryptography.Pkcs12UnspecifiedPasswordIterationLimit" Value="1000000" />

</ItemGroup>

또는 애플리케이션의 프로젝트 파일이 포함된 동일한 디렉터리에 다음 내용이 포함된 runtimeconfig.template.json이라는 파일을 배치할 수 있습니다.

{

     "configProperties": {

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

      }

}

.NET 런타임 구성 설정을 변경하는 방법에 대한 자세한 내용은 설명서 페이지 .NET 런타임 구성 설정을 참조하세요.

추가 검사를 완전히 표시하지 않하려면 아래와 같이 구성 스위치를 특수 sentinel 값 -1로 설정합니다.

⚠️ 경고: 대상 애플리케이션이 신뢰할 수 없는 인증서 입력을 처리하지 않는다고 확신하는 경우에만 AppContext 스위치를 -1로 설정합니다.

애플리케이션의 프로젝트 파일(.csproj 또는 .vbproj) 내에서:

<!--

  • This switch only works if the current project file represents an application. It has no effect if the current project file represents a shared library.

-->

<ItemGroup>

  • <RuntimeHostConfigurationOption Include="System.Security.Cryptography.Pkcs12UnspecifiedPasswordIterationLimit" Value="-1" />

</ItemGroup>

또는 runtimeconfig.template.json 파일 내에서 다음을 수행합니다.

{

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

     }

}

옵션 5 - 레지스트리를 통해 추가 유효성 검사 컴퓨터 전체 수정 또는 표시 안 함(.NET Framework용 Windows 전용)

적용 가능성: 이 옵션은 모든 버전의 .NET Framework 적용됩니다.  .NET 6.0 이상에는 적용되지 않습니다.

기본적으로 .NET Framework 600,000회 이하의 암호 반복을 수행하도록 가져오기 작업을 제한하지만, 이 제한은 HKLM 레지스트리를 사용하여 컴퓨터 전체에서 구성할 수 있습니다. 이 새로운 제한은 위에 나열된 영향을 받는 API의 모든 호출에 적용됩니다.

제한을 변경하려면 레지스트리 키HKLM\Software\Microsoft\.NETFramework에서Pkcs12UnspecifiedPasswordIterationLimit값을 새 제한으로 설정합니다. 예를 들어 제한을 1,000,000(백만 번) 반복으로 설정하려면 관리자 권한 명령 프롬프트에서 아래와 같이 명령을 실행합니다.

  • 이 숫자는 MAC 반복 수, 암호화된 안전한 콘텐츠 및 가려진 모음의 반복 횟수의 합계인 반복 제한을 제어합니다. 명시적 반복 횟수 <iter_count>(예: openssl pkcs12 -export -iter <iter_count> 통해)를 사용하여 PFX를 수동으로 내보내고 해당 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 sentinel을 설정하려면 REG_DWORD 형식 대신 REG_SZ 형식을 사용합니다. 레지스트리 설정은 아키텍처에 따라 달라집니다. 애플리케이션이 대상 아키텍처에 관계없이 구성된 값을 관찰하도록 하려면 아래와 같이 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 값을 삭제합니다.

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

Windows 관련 참고 사항

Windows에서는 PFXImportCertStore 함수를 통해 인증서를 가져올 .NET Framework 있습니다. 이 함수는 PFX Blob의 최대 허용 반복 수에 자체 제한을 두는 등 자체 유효성 검사를 수행합니다. 이러한 검사는 PFX 가져오기 시 계속 수행됩니다. Tthe. 위에서 설명한 NET 관련 환경 변수 및 레지스트리 키는 PFXImportCertStore가 이러한 검사를 수행하는 방식에 영향을 주지 않습니다.

도움이 더 필요하세요?

더 많은 옵션을 원하세요?

구독 혜택을 살펴보고, 교육 과정을 찾아보고, 디바이스를 보호하는 방법 등을 알아봅니다.

커뮤니티를 통해 질문하고 답변하고, 피드백을 제공하고, 풍부한 지식을 갖춘 전문가의 의견을 들을 수 있습니다.