023. Web API for accessing FIDO 2.0 credentials - Sample scenarios

FIDO 2.0 Web API for accessing FIDO 2.0 credentials

FIDO의 3가지 스펙 문서 중 두 번째인 Signature Format에 대해서 정리한다.

참고 FIDO alliance : FIDO 2.0 Web API 문서

Sample scenarios

이 포스팅에서 다루는 Sample scenario들은 꼭 이대로만 구현해야한다고 규범으로 정해져있지 않다.

본 포스팅에서는 FIDO 2.0 Credential의 Life cycle에 있는 일부 이벤트와 이 API를 사용하기 위한 샘플 코드를 살펴본다.

이 샘플 코드는 전체 흐름의 예시이며 API 사용 방법을 따로 제한하진 않는다.

Sample scenario는 스마트폰처럼 자체 디스플레이가 포함된 장치를 외부의 1단계 authenticator를 사용하는 사용 방법에 중점을 둔다.

다른 authenticator의 유형도 API에서 지원이 되고 있으며 플랫폼마다 각각 구현할 수 있을 것이다.

따라서, 이 샘플 코드는 클라이언트 플랫폼에 내장된 내장 인증 authenticator는 물론 자체 디스플레이가 없는 외부 Authenticator에서도 동작한다.

클라이언트 플랫폼은 Authenticator가 표시하는 프롬프트 메시지를 표시해야 하며, Authenticator는 클라이언트 적절한 프롬프트 메시지를 표시할 때의 정보를 가질 수 있도록 모든 Authenticator의 Credential을 나열할 수 있어야 한다.

Registration

Registration 은 새로운 Credential을 생성하여 서버에 등록하는 과정을 말한다.

  1. 사용자는 example.com 을 방문하여 서버로부터 스크립트를 제공 받는다. 이때 사용자는 Relying Party가 수용할 수 있는 다른 수단을 이용하여 이미 로그인되어 있어야 한다.

    참고 이름, 암호, Authenticator 등의 정보를 수용한다

  2. Relying Party 스크립트가 아래 EXAMPLE 1 코드를 실행한다.

  3. 클라이언트 플랫폼이 외부의 Authenticator를 검색한다.

  4. 클라이언트 플랫폼이 외부의 Authenticator에 연결하여, 필요한 페어링 작업을 수행한다.

  5. 외부 Authenticator는 사용자에게 새로운 Credential이 생성될 Authenticator를 선택하기 위한 UI를 보여주고, 사용자로부터 지문과 같은 인증 정보가 담긴 제스쳐를 받아온다.

  6. 외부 Authenticator가 클라이언트 플랫폼에게 응답을 반환하고, 이어서 Relying Party 플랫폼에 대한 응답을 반환한다. 이때 사용자가 Authenticator를 선택하거나 권한 부여를 거절하면 적절한 오류를 반환한다.

  7. 새로운 Credential이 생성될 경우 아래 절차에 따라 진행한다.
    a. Relying Party 스크립트는 새로 생성된 public key 를 추가 정보와 함께 서버로 보낸다.
    b. 서버는 데이터베이스에 public key 를 저장하고, authentication과 함께 유저에게 인증의 강력함을 표현한 뒤 추후 사용을 위해 친근한 이름으로 저장한다.
    c. 스크립트는 Credential의 선택 범위를 좁힘으로써, 미래의 UX를 증진시키고, 사용자의 로컬 저장소 내부의 Credential ID와 같은 데이터를 저장한다.

id:"j5962qyb"}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
// EXAMPLE 1
var fidoAPI = window.fido;

if (!fidoAPI) { /* Platform not capable. Handle error. */ }

var userAccountInformation = {
rpDisplayName: "PayPal",
displayName: "John P. Smith",
name: "johnpsmith@gmail.com",
id: "1098237235409872";
imageUri: "https://pics.paypal.com/00/p/aBjjjpqPb.png"
};

// This RP will accept either an ES256 or RS256 credential, but // prefers an ES256 credential.
var cryptoParams = [
{
type: "FIDO",
algorithm: "ES256",
},
{
type: "FIDO",
algorithm: "RS256",
}
];

var challenge = "Y2xpbWIgYSBtb3VudGFpbg";
var timeoutSeconds = 300; // 5 minutes
var blacklist = []; // No blacklist
var extensions = {"fido.location": true}; // Include location information in attestation
// Note: The following call will cause the authenticator to display UI.
fidoAPI.makeCredential(userAccountInformation, cryptoParams, challenge, timeoutSeconds, blacklist, extensions)
.then(function (newCredentialInfo) {
// Send new credential info to server for verification and registration.
}).catch(function (err) {
// No acceptable authenticator or user refused consent. Handle appropriately.
});

Authentication

Authentication 은 이미 등록된 Credential을 가진 사용자가 웹 사이트를 방문하고 Credential을 사용하여 authentication하려 할 때의 과정이다.

  1. 사용자는 example.com을 방문하여 스크립트를 제공받는다.
  2. 스크립트는 클라이언트 플랫폼에 FIDO identity assertion을 요청하고 이를 통해 가능한한 많은 정보를 제공하여 사용자가 선택할 수 있는 Credential의 범위를 좁힌다.
    이후 Registration 이후 로컬 저장소에 저장된 데이터를 가져오거나 사용자에게 사용자 이름을 묻는 방식과 같은 다양한 방법으로 얻을 수 있다.
  3. Relying Party 스크립트가 아래 EXAMPLE 2 코드를 실행한다.
  4. 클라이언트 플랫폼이 외부의 Authenticator를 검색한다.
  5. 클라이언트 플랫폼이 외부의 Authenticator에 연결하여, 필요한 페어링 작업을 수행한다.
  6. 외부의 Authenticator는 사용자에게 인증을 하는 행위에 대해 주의가 필요함을 알림을 통해 알려준다.
    이 알림을 열면 사용자는 Credential을 만들 때 제공되는 계정 정보와 이러한 key를 요청하는 출처에 대한 정보를 사용해 적합한 Credential과 사용자에게 친숙한 선택 메뉴를 표시해준다.
  7. 사용자로부터 지문과 같은 인증 정보가 담긴 제스쳐를 받아온다.
  8. 외부 Authenticator가 클라이언트 플랫폼에게 응답을 반환하고, 이어서 Relying Party 플랫폼에 대한 응답을 반환한다. 이때 사용자가 Authenticator를 선택하거나 권한 부여를 거절하면 적절한 오류를 반환한다.
  9. assertion이 성공적으로 생성되어 반환되면 아래의 동작을 수행한다.
    a. 스크립트가 서버로 assertion을 전송한다.
    b. 서버는 전송받은 assertion을 검사하고 올바르게 생성되었는지 확인한다. 확인 후 assertion과 연관된 public keyidentity 를 조회한다. 조회 후 해당 identity 는 인증이 완료된다.
    만약 public key 가 서버에서 인식되지 못하면 인증은 실패하며 각 Relying Party에 방식에 따라 실패에 대한 처리를 진행한다.

    참고 서버의 비활성으로 등록이 해제된 경우가 있다.

    c. 서버는 인증 성공 페이지를 반환하고 인증 쿠키를 설정하는 등의 성공시 수행할 작업을 수행한다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// EXAMPLE 2
var fidoAPI = window.fido;

if (!fidoAPI) { /* Platform not capable. Handle error. */ }

var challenge = "Y2xpbWIgYSBtb3VudGFpbg";
var timeoutSeconds = 300; // 5 minutes
var whitelist = [{ type: "FIDO" }];

fidoAPI.getAssertion(challenge, timeoutSeconds, whitelist)
.then(function (assertion) {
// Send assertion to server for verification
})
.catch(function (err) {
// No acceptable credential or user refused consent. Handle appropriately.
});

반면에, Relying Party 스크립트가 Credential 목록을 좁히는 데 도움이 되는 몇 가지 힌트를 가지고 있으면 아래와 같은 샘플코드 EXAMPLE 3 로 인증을 수행할 수 있다.
아래 샘플코드 EXAMPLE 3 는 트랜잭션 인증을 위해 external을 사용하는 방법을 표현한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
var fidoAPI = window.fido;

if (!fidoAPI) { /* Platform not capable. Handle error. */ }

var challenge = "Y2xpbWIgYSBtb3VudGFpbg";
var timeoutSeconds = 300; // 5 minutes
var acceptableCredential1 = {
type: "FIDO",
id: "ISEhISEhIWhpIHRoZXJlISEhISEhIQo=",
};
var acceptableCredential2 = {
type: "FIDO",
id: "cm9zZXMgYXJlIHJlZCwgdmlvbGV0cyBhcmUgYmx1ZQo=",
};
var whitelist = [acceptableCredential1, acceptableCredential2];
var extensions = { 'fido.txauth.simple': "Wave your hands in the air like you just don't care"};

fidoAPI.getAssertion(challenge, timeoutSeconds, whitelist, extensions)
.then(function (assertion) {
// Send assertion to server for verification
})
.catch(function (err) {
// No acceptable credential or user refused consent. Handle appropriately.
});

Decommissioning

Decommissioning 은 이미 등록된 Credential을 폐기하는 것으로 크게 3가지 가능성이 존재한다.

모든 Decommissioning 은 서버 츠겡서 처리되므로 지정된 API의 지원이 따로 필요하지 않다.

  • 가능성 #1
    사용자가 Credential을 분실신고하는 경우

    • 사용자가 server.example.net 으로 접속하여 분실 혹은 도난 당한 장치를 보고한다.
    • 서버는 기존에 등록된 Credential 중에서 사용자의 친숙한 이름의 Credential 목록을 보여주는 페이지를 반환한다.
    • 사용자가 Credential을 선택하면 서버는 데이터베이스에서 해당 Credential을 삭제한다.
    • 앞으로 Relying Party 스크립트는 이 Credential을 허용 Credential 목록에 지정하지 않으며 해당 Credential로 서명된 Assertion은 거부된다.
  • 가능성 #2
    서버의 비활성화로 인해 Credential의 등록을 취소하는 경우

    • 서버는 유지보수 작업 중 데이터베이스에서 Credential을 삭제한다.
    • 앞으로 Relying Party 스크립트는 이 Credential을 허용 Credential 목록에 지정하지 않으며 해당 Credential로 서명된 Assertion은 거부된다.
  • 가능성 #3
    사용자가 장치에서 Credential을 삭제하는 경우

    • 사용자는 기기 설정과 같은 해당 기기별 방법으로 Credential을 삭제한다.
    • 이제 장치에서 Credential이 표시되지 않으며 해당 Credential로 Assertion을 생성할 수 없다.
    • 해당 Credential의 비활성으로 추후 서버는 Credential의 등록을 해지한다.