다음을 통해 공유


Windows Hello

이 문서에서는 Windows의 일부로 제공되는 Windows Hello 기술에 대해 설명하고 개발자가 이 기술을 구현하여 Windows 앱 및 백 엔드 서비스를 보호하는 방법을 설명합니다. 기존 자격 증명을 사용하여 발생하는 위협을 완화하는 데 도움이 되는 이러한 기술의 특정 기능을 강조하고 Windows 클라이언트 롤아웃의 일부로 이러한 기술을 디자인하고 배포하는 방법에 대한 지침을 제공합니다.

참고 항목

이 문서에서는 앱 개발에 중점을 둡니다. Windows Hello의 아키텍처 및 구현 세부 정보에 대한 자세한 내용은 비즈니스용 Windows Hello 배포 계획을 참조하세요.

Windows Hello 및 백업 인증 서비스를 사용하여 WinUI 앱을 만드는 단계별 연습은 Windows Hello 로그인 앱Windows Hello 로그인 서비스 문서를 참조하세요.

소개

정보 보안에 대한 근본 가정은 시스템에서 이를 사용하는 사람을 식별할 수 있다는 것입니다. 사용자를 식별하면 시스템에서 사용자가 적절하게 식별(인증 프로세스)됬는지 확정하고, 제대로 인증된 사용자가 수행할 수 있는 작업을 결정(권한 부여)할 수 있습니다. 전 세계에서 사용중인 압도적 다수의 컴퓨터 시스템은 인증 및 권한 부여 결정을 내리기 위한 사용자 자격 증명에 의존합니다. 즉, 이러한 시스템들은 보안의 기반으로 사용자가 만든 중복 사용이 가능한 암호에 의존합니다. 인증요소에 "알고 있는 것, 가지고 있는 것 또는 자기 자신"이 포함될 수 있다는 익숙한 격언은 문제점을 깔끔하게 수면위로 보여줍니다. 중복 가능한 암호는 그 자체로 인증 요소이므로 암호를 아는 사람은 누구나 암호를 소유한 사용자를 가장할 수 있습니다.

기존 자격 증명 문제

매사추세츠 공과대학(MIT)의 페르난도 코르바토(Fernando Corbató)와 그의 팀이 암호체계의 도입을 지지한 1960년대 중반부터, 사용자와 관리자는 사용자 인증 및 권한 부여를 위해 암호 사용을 다루어야 했습니다. 시간이 지남에 따라 암호 저장 및 사용에 대한 최신 기술은 다소 발전했지만(예: 보안 해시 및 솔트 사용) 여전히 두 가지 문제에 직면해 있습니다. 암호는 복제가 용이하고 도난당하기 쉽습니다. 또한 구현 오류로 인해 안전성을 잃을 수 있으며 사용자는 편리성과 보안성의 균형을 맞추기가 어렵습니다.

자격 증명 도용

암호의 가장 큰 위험은 단순성입니다. 공격자가 쉽게 도용할 수 있습니다. 암호가 입력되고, 처리되고, 저장되는 모든 장소가 취약합니다. 예를 들어 공격자는 애플리케이션 서버로 가는 네트워크 트래픽을 감청하거나, 애플리케이션 또는 디바이스에 맬웨어를 설치하거나, 디바이스 사용자 키 입력을 로그화하거나, 사용자가 입력하는 문자를 확인하는 방식으로 인증 서버에서 암호 또는 해시 컬렉션을 훔칠 수 있습니다. 이것들은 그저 가장 일반적인 공격 방식에 불과합니다.

또 다른 관련 위험은 자격 증명 재전송입니다, 이는 공격자가 안전하지 않은 네트워크에서 감청하여 유효한 자격 증명 전송 기록을 얻어낸 다음 나중에 재전송하여 유효한 사용자를 가장하는 것 입니다. 대부분의 인증 프로토콜(Kerberos 및 OAuth 포함)은 자격 증명 교환 프로세스에 시간기록을 포함하여 재전송 공격으로부터 보호하지만, 이 방식은 인증 시스템에서 발급하는 토큰만 보호하지 먼저 입력해야 하는 사용자의 암호는 보호하지 못합니다.

자격 증명 재사용

전자 메일 주소를 사용자 이름으로 사용하는 일반적인 방식은 이미 나쁜 문제를 더 악화시킬 수 있습니다. 노출된 시스템에서 사용자 이름-암호 쌍을 성공적으로 복구한 공격자는 다른 시스템에서 동일한 쌍을 시도할 수 있습니다. 이 전술은 공격자가 노출된 시스템을 발판으로 다른 시스템으로 도약할 수 있고 놀라울 정도로 효과적입니다. 사용자 이름으로 전자 메일 주소를 사용하는 것은 이 가이드의 뒷부분에서 살펴볼 추가 문제를 발생시킵니다.

자격 증명 문제 해결

암호로 인해 발생하는 문제를 해결하는 것은 까다롭습니다. 암호 정책 강화만으론 부족합니다. 사용자는 그냥 암호를 재활용하거나, 공유 또는 메모 해 놓을 수 있습니다. 사용자 교육은 인증 보안의 핵심이지만 교육만으로 문제가 제거되지는 않습니다.

Windows Hello는 기존 자격 증명을 확인하고 생체 인식 또는 PIN 기반 사용자 제스처로 보호되는 디바이스별 자격 증명을 만들어 암호를 강력한 2FA(2단계 인증)로 바꿉니다.

Windows Hello란?

Windows Hello는 Microsoft가 Windows에 기본 제공되는 새로운 생체 인식 로그인 시스템에 부여한 이름입니다. 운영 체제 안에서 함께 기본 제공되므로 Windows Hello를 사용하면 얼굴 또는 지문 식별을 통해 사용자의 디바이스 잠금을 해제할 수 있습니다. 사용자가 디바이스별 자격 증명에 액세스하기 위해 고유한 생체 인식 식별자를 제공하면 인증이 시작됩니다. 이는 디바이스를 훔친 공격자에게 PIN이 없으면 로그온할 수 없음을 뜻합니다. Windows 보안 자격 증명 저장소는 디바이스의 생체 데이터를 보호합니다. Windows Hello를 사용하여 디바이스의 잠금을 해제하는 것으로 권한이 부여된 사용자는 모든 Windows 환경, 앱, 데이터, 웹 사이트 및 서비스에 접근할 수 있습니다.

Windows Hello 인증기를 Hello라고 합니다. 고유한 Hello가 각각의 개별 디바이스와 특정 사용자의 조합에 존재합니다. 디바이스 간에 이동되지 않고, 서버 또는 호출 앱과 공유되지 않으며, 디바이스에서 쉽게 추출할 수 없습니다. 여러 사용자가 한 디바이스를 공유하는 경우 사용자들은 각각 자신의 계정을 설정해야 합니다. 모든 계정은 해당 디바이스에 대해 고유한 Hello를 가집니다. Hello를 저장된 자격 증명의 잠금을 해제(풀어주는)하는 데 사용할 수 있는 토큰으로도 생각할 수 있습니다. Hello 자체는 앱 또는 서비스에 사용자를 인증하지 않지만, 해당하는 앱 또는 서비스의 자격 증명을 풀어줍니다. 즉, Hello는 사용자 자격 증명이 아니라 인증 프로세스에 대한 두 번째 요소입니다.

Windows Hello 인증

Windows Hello는 디바이스가 개별 사용자를 인식할 수 있도록 탄탄한 방식을 제공합니다. 사용자와 요청된 서비스, 데이터 간의 경로, 그 첫 파트를 다루는 방식이죠. 디바이스가 사용자를 인식한 후 일지라도 요청된 리소스에 대한 액세스 권한을 부여할지 여부를 결정하기 위해선 사용자를 인증이 필요합니다. Windows Hello는 Windows에 완전히 통합된 강력한 2FA 방식이며 재사용할 수 있는 암호를 특정 디바이스와 생체 인식 제스처 또는 PIN의 조합으로 대체합니다.

그러나 Windows Hello는 기존 2FA 시스템을 대체하는 데 그치는 것은 아닙니다. 개념적으로 스마트 카드와 비슷합니다. 인증은 스트링 비교 대신 암호화 기본 형식을 사용하여 수행되며 사용자의 키 자료는 변조 방지 하드웨어 내에 안전하게 보관됩니다. Windows Hello에는 스마트 카드 배포에 필요한 추가 인프라 구성 요소도 필요하지 않습니다. 특히 현재 인증서가 없는 경우 인증서를 관리하기 위해 PKI(공개 키 인프라)를 필요치 않습니다. Windows Hello는 가상 스마트 카드의 배포 유연성과 물리적 스마트 카드의 강력한 보안과 같은 스마트 카드 기술의 주요 장점만 가져오고 단점은 제외하였습니다.

Windows Hello 작동 방식

사용자가 자신의 머신에서 Windows Hello를 설정하면 Windows Hello는 해당 디바이스에 새 퍼블릭-프라이빗 키 쌍을 만듭니다. TPM(신뢰할 수 있는 플랫폼 모듈 이 프라이빗 키를 생성하고 보호합니다. 디바이스에 TPM 칩이 없는 경우 프라이빗 키가 암호화되고 소프트웨어로 보호됩니다. 또한 TPM이 설치된 디바이스는 키가 TPM에 바인딩되어 있음을 증명하기 위해 사용될 수 있는 데이터 블록을 생성합니다. 이 증명 정보는 당신의 솔루션에서 사용자에게 다른 권한 부여 수준을 부여할지 여부를 결정하는데 사용될 수 있습니다.

디바이스에서 Windows Hello를 사용하도록 설정하려면 사용자에게 Microsoft Entra ID 계정 또는 Windows 설정에 연결된 Microsoft 계정이 있어야 합니다.

키를 보호하는 방법

키 자료가 생성될 때는 공격으로부터 무조건 보호되어야 합니다. 이 작업을 수행하는 가장 든든한 방법은 특수 하드웨어를 사용하는 것입니다. HSM(하드웨어 보안 모듈)을 사용하여 보안에 중요한 애플리케이션에 대한 키를 생성, 저장 및 처리하는 유구한 역사가 존재합니다. 스마트 카드는 특수한 유형의 HSM입니다. 신뢰 컴퓨팅 그룹 TPM 표준을 준수하는 디바이스와 마찬가지고요. 가능한 경우 Windows Hello 구현은 온보드 TPM 하드웨어를 사용하여 키를 생성, 저장, 처리합니다. 그러나 Windows Hello과 Windows Hello for Work는 온보드 TPM이 필요하지 않습니다.

Microsoft는 언제든 가능하다면 TPM 하드웨어를 사용을 권장합니다. TPM은 PIN 무차별 암호 대입 공격을 비롯한 알려져 있는 다양한 잠재적 공격으로부터 보호합니다. TPM은 계정 잠금 이후에도 추가 보호막을 제공합니다. TPM이 키 관련 자료를 잠궜을 경우 사용자는 PIN을 재설정해야 합니다. PIN을 재설정하면 이전 키 자료로 암호화된 모든 키와 인증서가 제거됩니다.

인증

사용자가 보호된 키 자료에 접근하려는 경우 인증 프로세스는 사용자가 PIN 또는 생체인증 제스처를 입력하여 디바이스 잠금을 해제하는 것으로 시작합니다. 이 프로세스를 "키 해제"라고도 합니다.

애플리케이션은 절대 다른 애플리케이션의 키를 사용할수 없으며 사용자는 절대 다른 사용자의 키를 사용할 수 없습니다. 이러한 키는 신분 공급자 또는 IDP 로 전송된 요청의 서명에 이용되며 지정된 리소스 접근에 사용됩니다. 애플리케이션은 특정 API를 사용하여 키 자료가 필요한 특수한 행동을 필요로하는 작업요청이 가능합니다. 이러한 API를 통해 액세스하려면 사용자 제스처를 통한 명시적 유효성 검사가 필요하며, 키 자료는 요청하는 애플리케이션에 노출되지 않습니다. 그 대신에 애플리케이션이 데이터 서명과 같은 특정 작업을 요청하고 Windows Hello 계층에서 실제 작업을 처리하여 결과를 반환합니다.

Windows Hello 구현 준비

Windows Hello 작동 방식에 대해 기본적인 사항을 이해했으므로 이제 애플리케이션에서 Windows Hello를 구현하는 방법에 대해 살펴보겠습니다.

Windows Hello를 사용하여 구현할 수 있는 여러 가지 시나리오가 있습니다. 예를 들자면, 그저 디바이스에서 앱에 로그인하는 것입니다. 다른 일반적인 시나리오는 서비스에 대해 인증하는 것입니다. 로그온 이름과 암호를 사용하는 대신 Windows Hello를 사용하게 됩니다. 다음 섹션에서는 Windows Hello를 사용하여 서비스에 대해 인증하는 방법 및 기존 사용자 이름/암호 시스템에서 Windows Hello 시스템으로 변환하는 방법을 포함하여 몇 가지 다른 시나리오를 구현하는 방법을 설명합니다.

Windows Hello 구현

이 섹션에서는 기존 인증 시스템이 없는 greenfield 시나리오로 시작하고 Windows Hello를 구현하는 방법을 설명합니다.

다음 섹션은 기존 사용자 이름/암호 시스템으로부터 마이그레이션하는 방법을 다룹니다. 그러나 해당 섹션이 더 관심이 있더라도 이 섹션을 통해 프로세스와 필요한 코드를 기본적으로 이해할 수 있습니다.

새 사용자 등록

Windows Hello를 사용하는 새 서비스, 그리고 새 디바이스에 등록할 준비가 된 가상의 새 사용자부터 시작하겠습니다.

첫 번째 단계는 Windows Hello를 사용할 수 있는 사용자인지 확인하는 것입니다. 앱은 사용자 설정 및 기기 성능을 검증하여 사용자 ID 키를 생성할 수 있는지 확인합니다. 사용자가 아직 Windows Hello를 활성화하지 않았음을 앱이 확인하면 사용자가 그 앱을 사용하기 전에 이를 설정하라는 메시지가 표시됩니다.

Windows Hello를 사용하려면 사용자가 OOBE(첫 실행 경험)에서 설정하지 않은 경우, Windows 설정에서 PIN을 설정하기만 하면 됩니다.

다음 코드 줄은 사용자가 Windows Hello를 사용하도록 설정했는지 여부를 간단히 확인하는 방법입니다.

var keyCredentialAvailable = await KeyCredentialManager.IsSupportedAsync();
if (!keyCredentialAvailable)
{
    // User didn't set up PIN yet
    return;
}

다음 단계는 사용자에게 서비스 가입을 위한 정보를 요청하는 것입니다. 이름, 성, 전자 메일 주소 및 중복되지 않는 사용자명을 요청할지 선택할 수 있습니다. 이메일 주소를 고유 식별자로 사용할 수도 있습니다. 어떻게 하던 당신 마음입니다.

이 시나리오에서는 전자 메일 주소를 사용자의 고유 식별자로 사용하겠습니다. 사용자가 가입하면 이메일 주소가 유효한지 확인하기 위해 확인 메일을 보내보는 것을 고려하세요. 이것은 필요한 경우 계정을 다시 설정하는 메커니즘을 제공합니다.

사용자가 PIN을 설정하면 앱은 사용자의 KeyCredential을 만듭니다. 또한 앱은 TPM에서 키가 생성된다는 암호화 증명을 얻기 위해 선택적으로 키 입증 정보를 얻습니다. 생성된 공개 키와, 만약 얻었다면, 그 입증은 사용 중인 디바이스를 등록하기 위해 백 엔드 서버로 전송됩니다. 모든 디바이스에서 생성된 모든 키 쌍은 중복되지 않습니다.

KeyCredential 을 만드는 코드는 다음과 같습니다:

var keyCreationResult = await KeyCredentialManager.RequestCreateAsync(
    AccountId, KeyCredentialCreationOption.ReplaceExisting);

RequestCreateAsync는 퍼블릭 및 프라이빗 키를 만드는 호출입니다. 디바이스에 올바른 TPM 칩이 있는 경우 API는 TPM 칩에 프라이빗 및 퍼블릭 키를 만들고 결과를 저장하도록 요청하게 됩니다. TPM 칩이 디바이스에 없으면 OS는 코드로 키 쌍을 만듭니다. 앱에서 만든 프라이빗 키에 직접 액세스할 수 있는 방법은 존재하지 않습니다. 키 쌍 생성의 일부는 결과적으로 발생된 입증 정보 이기도 합니다. (입증에 대한 더 자세한 내용은 다음 섹션을 참조하세요.)

디바이스에서 키 쌍과 입증 정보를 만든 후에는 공개 키, 선택적 증명 정보 그리고 고유 식별자(예: 이메일 주소)를 백 엔드 등록 서비스로 보내고 백 엔드에 저장해야 합니다.

사용자가 여러 디바이스에서 앱에 접속할 수 있도록 하기 위해선 백 엔드 서비스가 동일한 사용자의 여러 키를 저장할 수 있어야 합니다. 모든 키는 모든 디바이스마다 고유하기 때문에 같은 사용자에 연결된 이 모든 키들을 저장할 겁니다. 디바이스 식별자는 사용자를 인증할 때 서버 부분 최적화시 도움을 주는 대 사용됩니다. 이에 대한 자세한 내용은 다음 섹션에서 설명합니다.

이 정보를 백 엔드에 저장하기 위한 샘플 데이터베이스 스키마는 다음과 같습니다:

Windows Hello 샘플 데이터베이스 스키마

등록 로직은 다음과 같을 수 있습니다:

Windows Hello 등록 논리

물론 당신이 수집한 등록 정보에는 이 간단한 시나리오에 포함된 것보다 훨씬 더 많은 식별 정보가 포함될 수 있습니다. 예를 들어 앱이 은행업무 서비스와 같은 보안 서비스에 액세스하는 경우 가입 프로세스의 일부로 신원 증명 및 기타 사항을 요청해야 합니다. 모든 조건이 충족되면 이 사용자의 공개 키가 백 엔드에 저장되고 다음에 사용자가 서비스를 사용할 때 유효성 검사에 사용됩니다.

using System;
using System.Runtime;
using System.Threading.Tasks;
using Windows.Storage.Streams;
using Windows.Security.Credentials;

static async void RegisterUser(string AccountId)
{
    var keyCredentialAvailable = await KeyCredentialManager.IsSupportedAsync();
    if (!keyCredentialAvailable)
    {
        // The user didn't set up a PIN yet
        return;
    }

    var keyCreationResult = await KeyCredentialManager.RequestCreateAsync(AccountId, KeyCredentialCreationOption.ReplaceExisting);
    if (keyCreationResult.Status == KeyCredentialStatus.Success)
    {
        var userKey = keyCreationResult.Credential;
        var publicKey = userKey.RetrievePublicKey();
        var keyAttestationResult = await userKey.GetAttestationAsync();
        IBuffer keyAttestation = null;
        IBuffer certificateChain = null;
        bool keyAttestationIncluded = false;
        bool keyAttestationCanBeRetrievedLater = false;

        keyAttestationResult = await userKey.GetAttestationAsync();
        KeyCredentialAttestationStatus keyAttestationRetryType = 0;

        switch (keyAttestationResult.Status)
        {
            case KeyCredentialAttestationStatus.Success:
                keyAttestationIncluded = true;
                keyAttestation = keyAttestationResult.AttestationBuffer;
                certificateChain = keyAttestationResult.CertificateChainBuffer;
                break;
            case KeyCredentialAttestationStatus.TemporaryFailure:
                keyAttestationRetryType = KeyCredentialAttestationStatus.TemporaryFailure;
                keyAttestationCanBeRetrievedLater = true;
                break;
            case KeyCredentialAttestationStatus.NotSupported:
                keyAttestationRetryType = KeyCredentialAttestationStatus.NotSupported;
                keyAttestationCanBeRetrievedLater = true;
                break;
        }
    }
    else if (keyCreationResult.Status == KeyCredentialStatus.UserCanceled ||
        keyCreationResult.Status == KeyCredentialStatus.UserPrefersPassword)
    {
        // Show error message to the user to get confirmation that user
        // does not want to enroll.
    }
}

증명

키 쌍을 만들 때 TPM 칩이 생성하는 입증 정보를 요청하는 옵션도 있습니다. 이 선택적 정보는 가입 프로세스의 일환으로 서버로 보낼 수 있습니다. TPM 키 입증은 키가 TPM에 의해 생성되었음을 암호화적으로 증명하는 프로토콜입니다. 이러한 유형의 입증을 사용하면 특정 컴퓨터의 TPM에서 특정 암호화 작업 발생을 보장할 수 있습니다.

생성된 RSA 키, 입증서 그리고 AIK 인증서를 전달 받으면 서버는 다음 조건을 확인합니다:

  • 유효한 AIK 인증서 서명입니다.
  • AIK 인증서는 신뢰할 수 있는 루트에 체인 됩니다.
  • AIK 인증서 및 해당 체인은 EKU OID "2.23.133.8.3" (친숙하게 "입증 ID 키 인증서" 라고 불림) 에 사용 가능하도록 설정됩니다.
  • AIK 인증서는 유효시간이 있습니다.
  • 체인에서 발급된 모든 CA 인증서는 유효시간이 있으며 취소되지 않습니다.
  • 입증문이 올바르게 작성되었습니다.
  • KeyAttestation 블랍의 서명은 AIK 공개 키를 사용합니다.
  • KeyAttestation 블랍에 포함된 공개 키는 클라이언트가 입증문과 함께 보낸 공용 RSA 키와 일치합니다.

당신의 앱은 이러한 조건에 따라 사용자에게 다른 권한 수준을 할당할 수도 있습니다. 예를 들어 이러한 검사 중 하나가 실패하면 사용자를 등록하지 않거나 사용자가 수행할 수 있는 작업을 제한할 수 있습니다.

Windows Hello로 로그온

사용자가 시스템에 등록되면 앱을 사용할 수 있습니다. 시나리오에 따라 사용자가 앱을 사용하기 전에 인증을 요청하거나, 백 엔드 서비스 사용을 시작한 후에 인증하도록 요청할 수 있습니다.

사용자가 다시 로그인하도록 강제 적용

일부 시나리오에서 당신은 사용자가 앱에 액세스하기 전, 또는 앱 내에서 특정 작업을 수행하기 전에 현재 로그인된 사람이 맞는지 증명을 원할수 있습니다. 예를 들어 은행 앱이 서버에 송금 명령을 보내기 전, 우연히 로그인된 디바이스를 주운 사람이 아닌 실제 사용자가 송금하려고 하는지 확인할 필요가 있습니다. UserConsentVerifier 클래스를 사용하여 앱에서 사용자의 재 로그인을 강제할 수 있습니다. 다음 코드 라인은 사용자가 자격 증명을 입력하도록 강제합니다.

다음 코드 라인은 사용자가 자격 증명을 입력하도록 강제합니다.

UserConsentVerificationResult consentResult = await UserConsentVerifier.RequestVerificationAsync("userMessage");
if (consentResult.Equals(UserConsentVerificationResult.Verified))
{
    // continue
}

사용자가 PIN 코드 또는 생체 인식 자격 증명을 입력해야 하는 서버의 챌린지 응답 메커니즘을 사용할 수도 있습니다. 이건 당신과 같은 개발자가 구현해야 하는 시나리오에 따라 달라집니다. 이 메커니즘에 대해서는 다음 섹션에서 설명합니다.

백 엔드에서 인증

앱이 보호된 백 엔드 서비스에 액세스하려고 하면 서비스가 앱에 시도를 전송합니다. 앱은 사용자의 프라이빗 키를 사용하여 시도에 서명하고 서버로 다시 전송합니다. 서버는 해당 사용자의 공개 키를 저장했기 때문에 표준 암호화 API를 사용하여 메시지가 올바른 프라이빗 키로 실제로 서명되었는지 확인합니다. 클라이언트 서명은 Windows Hello API를 통해 이루어지며, 개발자는 모든 사용자의 프라이빗 키에 액세스할 수 없습니다.

서비스는 키 검사 외에도, 키 입증을 검사하고 디바이스에 키가 저장되는 방법에 적용된 제한 사항이 있는지 식별할 수 있습니다. 예를 들면, 디바이스가 TPM을 사용하여 키를 보호하는 경우에 TPM 없이 키를 저장하는 디바이스보다 더 안전합니다. 예를 들어 백 엔드 로직은 사용자가 TPM을 사용하지 않는 경우 특정 금액 이하만을 이체할 수 있다고 결정하여 위험을 줄일 수 있습니다.

입증은 버전 2.0 이상인 TPM 칩이 있는 디바이스에서만 제공됩니다. 따라서 이 정보를 사용할 수 없는 디바이스가 있다는 가능성을 고려해야 합니다.

클라이언트 워크플로는 다음 차트와 같이 표시될 수 있습니다:

Windows Hello 클라이언트 워크플로

앱이 백 엔드에서 서비스를 호출하면 서버에서 시도를 전송합니다. 시도는 다음과 같은 코드로 서명됩니다:

var openKeyResult = await KeyCredentialManager.OpenAsync(AccountId);

if (openKeyResult.Status == KeyCredentialStatus.Success)
{
    var userKey = openKeyResult.Credential;
    var publicKey = userKey.RetrievePublicKey();
    var signResult = await userKey.RequestSignAsync(message);

    if (signResult.Status == KeyCredentialStatus.Success)
    {
        return signResult.Result;
    }
    else if (signResult.Status == KeyCredentialStatus.UserPrefersPassword)
    {

    }
}

첫 번째 줄인 KeyCredentialManager.OpenAsync는 Windows에 키 핸들을 열도록 요청합니다. 성공하면 KeyCredential.RequestSignAsync 메서드를 사용하여 챌린지 메시지에 서명하면 Windows에서 Windows Hello를 통해 사용자의 PIN 또는 생체 인식을 요청할 수 있습니다. 개발자는 절대 사용자의 프라이빗 키에 접근할 권한이 없습니다. 이 모든 것은 API를 통해 안전하게 유지됩니다.

API는 Windows에 프라이빗 키로 챌린지에 서명하도록 요청합니다. 그런 다음 시스템은 사용자에게 PIN 코드 또는 구성된 생체인식 로그온을 요청합니다. 올바른 정보가 입력되면 시스템에서 TPM 칩이 암호화 기능을 수행하고 시도에 서명하도록 요청할 수 있습니다. (TPM이 없는 경우 대체 소프트웨어 솔루션을 사용합니다). 클라이언트는 서명된 시도를 반드시 서버로 다시 전송해야 합니다.

기본 시도-응답 흐름은 다음 시퀀스 다이어그램에 표시됩니다.

Windows Hello 챌린지 응답

다음으로, 서버는 서명의 유효성 검사를 수행해야 합니다. 퍼블릭 키를 요청하고 나중에 유효성 검사를 위해 사용하기 위해 서버로 보내면 이 키는 ASN-1로 인코딩된 publicKeyInfo Blob에 있는 것입니다. GitHub에서 Windows Hello 코드 샘플을 검사하면 ASN.1로 인코딩된 Blob을 더 일반적으로 사용되는 CNG Blob으로 변환하기 위해 Crypt32 함수를 래핑하는 도우미 클래스가 있음을 알 수 있습니다. 블랍에는 RSA인 공개 키와 RSA 알고리즘이 포함됩니다.

샘플에서 ASN.1로 인코딩된 Blob을 CNG Blob으로 변환하는 이유는 CNG 및 BCrypt API와 함께 사용할 수 있기 때문입니다. CNG Blob을 조회하는 경우 관련 BCRYPT_KEY_BLOB 구조가 표시됩니다. 이 API 화면은 Windows 애플리케이션의 인증 및 암호화에 사용할 수 있습니다. ASN.1은 serialize할 수 있는 데이터 구조를 전달하기 위한 문서화된 표준이며 일반적으로 퍼블릭 키 암호화에서 인증서와 함께 사용됩니다. 이렇게 하면 퍼블릭 키 정보가 이러한 방식으로 반환됩니다. 퍼블릭 키는 RSA 키입니다. 또한 이 알고리즘은 데이터에 서명할 때 Windows Hello에서 사용하는 알고리즘입니다.

CNG 블랍이 있으면 사용자의 공개 키에 대해 서명된 시도의 유효성 검사가 필요합니다. 모든 사용자가 자신만의 시스템 또는 백 엔드 기술을 사용하므로 이 로직를 구현하는 일반적인 방법은 없습니다. 클라이언트의 서명된 응답 유효성을 검사할 때 반드시 SHA256을 해시 알고리즘으로 사용하고 Pkcs1을 SignaturePadding에 사용하는지 확인합니다. 다시 알려드리지만, .NET 4.6 서버에서 시행하는 방법은 샘플을 참조하세요. 일반적으로는 다음과 같을겁니다:

using (RSACng pubKey = new RSACng(publicKey))
{
    retval = pubKey.VerifyData(originalChallenge, responseSignature, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);
}

RSA 키인 저장된 공개 키를 읽습니다. 공개 키를 사용하여 서명된 시도 메시지의 유효성을 검사하고, 유효하다면 사용자에게 권한을 부여합니다. 사용자가 인증된 경우에 앱은 정상적으로 백 엔드 서비스 호출이 가능합니다.

완성된 코드는 다음과 같을겁니다:

using System;
using System.Runtime;
using System.Threading.Tasks;
using Windows.Storage.Streams;
using Windows.Security.Cryptography;
using Windows.Security.Cryptography.Core;
using Windows.Security.Credentials;

static async Task<IBuffer> GetAuthenticationMessageAsync(IBuffer message, String AccountId)
{
    var openKeyResult = await KeyCredentialManager.OpenAsync(AccountId);

    if (openKeyResult.Status == KeyCredentialStatus.Success)
    {
        var userKey = openKeyResult.Credential;
        var publicKey = userKey.RetrievePublicKey();
        var signResult = await userKey.RequestSignAsync(message);
        if (signResult.Status == KeyCredentialStatus.Success)
        {
            return signResult.Result;
        }
        else if (signResult.Status == KeyCredentialStatus.UserCanceled)
        {
            // Launch app-specific flow to handle the scenario 
            return null;
        }
    }
    else if (openKeyResult.Status == KeyCredentialStatus.NotFound)
    {
        // PIN reset has occurred somewhere else and key is lost.
        // Repeat key registration
        return null;
    }
    else
    {
        // Show custom UI because unknown error has happened.
        return null;
    }
}

올바른 시도-응답 메커니즘 구현은 이 문서의 범위를 벗어나지만 이 항목은 성공적으로 재전송 공격 또는 중간자 공격 등을 방지하기 위한 보안 메커니즘을 생성하기 위해서 주의가 필요합니다.

다른 디바이스 등록

사용자가 현재 동일한 앱을 사용하는 여러 디바이스를 설치하는 것이 일반적입니다. 여러 디바이스에서 Windows Hello를 사용하는 경우 어떻게 작동하나요?

Windows Hello를 사용하는 경우 모든 디바이스는 고유한 프라이빗 및 공개 키 집합을 만듭니다. 즉, 사용자의 여러 디바이스 사용이 가능 하려면 백 엔드에서 이 사용자의 여러 공개 키를 저장할 수 있어야 합니다. 테이블 구조의 예제는 새 사용자 등록 섹션의 데이터베이스 다이어그램을 참조하세요.

다른 디바이스를 등록하는 것은 처음으로 사용자를 등록하는 것과 거의 동일합니다. 이 새 디바이스에 등록하는 사용자가 실제로 자신이 주장하는 사용자인지 확인해야 합니다. 현재 사용되는 2중 인증 메커니즘을 사용하여 이를 진행할 수 있습니다. 이 작업을 안전하게 수행하는 방법은 여러 가지가 존재합니다. 모두 당신의 시나리오에 따라 달라집니다.

예를 들어 로그인 이름 과 암호를 계속 사용하는 경우 이들을 사용하여 사용자를 인증하고 SMS 또는 전자 메일과 같은 확인 방법 중 하나를 선택해 추가 인증을 요청할 수 있습니다. 로그인 이름 및 암호가 없는 경우 이미 등록된 디바이스 중 하나를 사용하여 해당 디바이스의 앱에 알림을 보낼 수도 있습니다. MSA 인증기 앱이 바로 그 예입니다. 요약하자면, 일반적인 2FA 메커니즘을 사용하여 사용자의 추가 디바이스를 등록하세요.

새 디바이스를 등록하는 코드는 앱 내에서 최초로 사용자를 등록하는 것과 정확히 동일합니다.

var keyCreationResult = await KeyCredentialManager.RequestCreateAsync(
    AccountId, KeyCredentialCreationOption.ReplaceExisting);

사용자가 등록된 디바이스를 쉽게 구별할 수 있도록 등록 절차의 일부로 디바이스 이름 또는 다른 식별자를 보내도록 선택할 수 있습니다. 예를 들어 사용자가 디바이스를 분실했을 시 등록을 취소할 수 있는 서비스를 백 엔드에 구현하려는 경우에도 유용합니다.

앱에서 여러 계정 사용

단일 계정에 대해 여러 디바이스를 지원하는 것 말고 단일 앱에서 여러 계정을 지원하는 것 또한 일반적입니다. 예를 들어 앱 내에서 여러 Twitter 계정에 연결할 수도 있습니다. Windows Hello를 사용하면 여러 키 쌍을 만들어 앱 내에서 여러 계정을 지원할 수 있습니다.

이 작업을 수행하는 한 가지 방법은 격리된 스토리지의 이전 섹션에서 설명한 사용자 이름 또는 고유 식별자를 유지하는 것입니다. 따라서 새 계정을 만들 때마다 계정 ID를 격리된 스토리지에 저장하세요.

앱 UI에서 사용자가 이전에 만든 계정 중 하나를 선택하여 로그인 하거나 새 계정등록이 가능하게 만드세요. 새 계정을 만드는 플로우는 앞에서 설명한 것과 동일합니다. 계정을 선택할수 있게 하기 위해서는 저장된 계정 리스트를 화면에 나열해야 합니다. 사용자가 계정을 선택하면 계정 ID를 사용하여 앱에서 사용자를 로그온 시킵니다.

var openKeyResult = await KeyCredentialManager.OpenAsync(AccountId);

나머지 플로우는 앞에서 설명한 것과 동일합니다. 분명하게 하자면, 이 시나리오에서 계정들은, 단일 디바이스에 사용되며 같은 Windows 계정을 사용하기에, 동일한 PIN과 동일한 생체인식 제스쳐로 보호됩니다.

기존 시스템을 Windows Hello로 마이그레이션

이 짧은 섹션에서는 사용자 이름과 해시된 암호를 저장하는 데이터베이스를 사용하는 기존 패키지 앱 및 백 엔드 시스템을 다룹니다. 이러한 앱은 앱이 시작될 때 사용자의 자격 증명을 수집하고 백 엔드 시스템이 인증 시도를 응답할 때 이를 사용합니다.

여기서는 Windows Hello가 작동하도록 하기 위해 변경 또는 대체해야 할 부분에 대해 설명합니다.

이전 섹션에서는 대부분의 기술을 이미 설명했습니다. Windows Hello를 기존 시스템에 추가하려면 코드의 등록 및 인증 부분에 몇 가지 다른 흐름을 추가해야 합니다.

한 가지 방법은 사용자가 업그레이드 시기를 선택할 수 있도록 허용하는 것입니다. 사용자가 앱에 로그온한 후에 해당 앱과 OS에서 Windows Hello를 지원할 수 있음을 감지하면, 더 안전한 이 최신 시스템을 사용하기 위해 자격 증명을 업그레이드할지 사용자에게 물어볼 수 있습니다. 사용자가 Windows Hello를 사용할 수 있는지 여부를 확인하려면 다음 코드를 사용하면 됩니다.

var keyCredentialAvailable = await KeyCredentialManager.IsSupportedAsync();

UI가 다음과 유사하게 표기됩니다:

Windows Hello 사용자 인터페이스의 스크린샷

사용자가 Windows Hello를 사용하기로 한 경우, 앞의 설명대로 KeyCredential을 만듭니다. 백 엔드 등록 서버는 공개 키 및 선택적인 입증문을 데이터베이스에 추가합니다. 사용자가 이미 사용자 이름 및 암호로 인증되어 서버는 새 자격 증명을 데이터베이스의 현재 사용자 정보에 연결할 수 있습니다. 데이터베이스 모델은 앞에서 설명한 예제와 같을 수 있습니다.

앱이 사용자의 KeyCredential 을 생성할 수 있었다면, 격리된 스토리지에 사용자 ID를 저장하여 앱이 다시 시작될 시 사용자가 목록에서 이 계정을 선택할 수 있도록 합니다. 이 시점부터 흐름은 이전 섹션에서 설명한 예제를 정확히 따릅니다.

전체 Windows Hello로 마이그레이션하는 시나리오에서 마지막 단계는 앱에서 로그온 이름 및 암호 옵션을 사용하지 않도록 설정한 후 저장해 둔 해시 암호를 데이터베이스에서 제거하는 것입니다.

요약

Windows는 더 높은 수준의 보안을 도입하며, 이 보안도 간단하게 구현할 수 있습니다. Windows Hello는 사용자를 인식하고 식별 회피 시도를 자동으로 무효화시키는 새로운 생체인식 로그인 시스템을 제공합니다. 그 다음에는 신뢰할 수 있는 플랫폼 모듈 외부에서 표시 또는 사용할 수 없는 여러 계층의 키와 인증서를 제공할 수 있습니다. 또한, 입증 신원 키 및 인증서의 선택적 사용을 통해 추가 보안 보호막을 제공합니다.

개발자는 이러한 기술의 설계 및 배포에 대한 이 지침을 사용하여 패키지된 Windows 앱 롤아웃에 보안 인증을 쉽게 추가하여 앱 및 백 엔드 서비스를 보호할 수 있습니다. 최소한의 코드만 필요하며 이해하기 쉽습니다. Windows는 무거운 리프팅을 처리합니다.

유연한 구현 옵션 덕분에 Windows Hello가 기존 인증 시스템을 대체하거나 기존 인증 시스템과 함께 작동할 수 있습니다. 설치 경험은 안락하고 경제적입니다. Windows 보안을 배포하는 데 추가 인프라가 필요하지 않습니다. 운영 체제에 기본 제공되는 Microsoft Hello를 사용하여 Windows는 최신 개발자가 직면한 인증 문제에 대한 가장 안전한 솔루션을 제공합니다.

임무 완수입니다! 당신은 방금 인터넷을 더 안전한 곳으로 만들었습니다!

추가 리소스

문서 및 샘플 코드

용어

기간 정의
Attestation Identity Key 입증 ID 키는 마이그레이션이 불가능한 키 속성에 서명하고 신뢰 당사자에게 검증을 위한 속성과 서명을 제공하여 암호화 증거(TPM 키 입증)를 제공하는 데 사용됩니다. 이 서명을 "인증문"이라고 합니다. 서명은 생성된 TPM에서만 사용할 수 있는 AIK 프라이빗 키를 이용하여 만들어져 신뢰 당사자는 증명된 키가 실제로 마이그레이션할 수 없으며 해당 TPM 외부에서 사용할 수 없다고 신뢰할 수 있습니다.
AIK 인증서 AIK 인증서는 TPM 내에 AIK 존재여부를 증명하기 위해 사용됩니다. 또한 AIK에서 인증한 다른 키들이 해당 특정 TPM에서 생성되었음을 입증하기 위해 사용됩니다.
IDP IDP(Identity Provider) 는 신원 공급자입니다. 예로는 Microsoft 계정용 Microsoft IDP 빌드가 있습니다. 애플리케이션이 MSA를 사용하여 인증해야 할 때마다 MSA IDP를 호출할 수 있습니다.
PKI 공개 키 인프라는 일반적으로 조직에서 직접 호스트하고 하는데 사용되며 키 생성, 키 폐기 등을 담당하는 환경을 포인트 하는데 사용됩니다.
TPM 신뢰할 수 있는 플랫폼 모듈을 사용하여 프라이빗 키가 TPM 외부에 노출되거나 사용할 수 없는 방식으로 암호화 퍼블릭/프라이빗 키 쌍을 만들 수 있습니다(결과적으로 키는 마이그레이션할 수 없습니다).
TPM 키 증명 키가 TPM에서 생성되었음을 암호화적으로 증명하는 프로토콜입니다. 이러한 유형의 입증을 사용하면 특정 컴퓨터의 TPM에서 특정 암호화 작업이 진행된 사실을 보증할 수 있습니다.