Webauthn | Javascript Client

WebAuthn(Web Authentication API)은 공개 키 암호화를 사용하여 안전한 비밀번호 없는 인증을 가능하게 하는 W3C 표준입니다. 사용자는 비밀번호 대신 하드웨어 기반 인증자(지문 판독기, Face ID, YubiKey 등) 또는 플랫폼 인증자(Touch ID와 같은 내장형)를 사용하여 등록하고 인증합니다.

 

Javascript 클라이언트를 사용하여 등록 및 인증을 처리하는 방법은 아래에서 확인하십시오.

WebAuthn Registration

WebAuthn Registration의 작동 방식

 

 

 

TsgcWSAPIServer_WebAuthn 구성 요소에는 WebAuthn 프로토콜을 테스트하기 위한 html 파일이 있습니다. 이 HTML 파일에는 WebAuthn과 상호 작용하기 위한 최소한의 UI와 JavaScript가 포함되어 있습니다.

 

sgcWebAuthn.html 둘러보기

 

구조 개요:

 

 

 

1. 입력용 HTML UI

 

<input type="text" id="username" name="username" autocomplete="username webauthn" />
<button id="btnRegBegin"><strong>Register</strong></button>

 

2. JavaScript: 버튼 클릭 핸들러

 

document.querySelector('#btnRegBegin').addEventListener('click', async () => {
  const username = document.getElementById("username").value;
  if (username == "") {
    document.getElementById('Error').innerText = 'Please enter a username to register';
    return;
}

  const resp = await fetch('<#webauthn_registration_options>', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ username, algorithms: [] })
});

  const options = await resp.json();
const attResp = await startRegistration(options);  // WebAuthn API

 

3. 서버 응답(HTML의 가짜 엔드포인트)

 

fetch('/sgcWebAuthn/Registration/Options', ...)

fetch('/sgcWebAuthn/Registration/Verify', ...)

 

4. 등록 완료

 

const verificationResp = await fetch('/webauthn/register/verify', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify(attResp)
});

const verificationJSON = await verificationResp.json();
if (verificationJSON && verificationJSON.verified) {
  document.getElementById('Success').innerHTML = `Authenticator registered!`;
}

 

 

 

WebAuthn Authentication

WebAuthn 인증 작동 방식

 

 

1. HTML UI 설정

 

<div class="container">
<h1>WebAuthn Authentication Sample</h1>

  <section id="userdata">
    <label for="username">Username:</label>
    <input type="text" id="username" name="username" autocomplete="username webauthn" autofocus />
</section>

  <button id="btnAuthBegin"><strong>Authenticate</strong></button>

  <p id="Success" class="success"></p>
<p id="Error" class="error"></p>

  <details open>
    <summary>Console</summary>
    <textarea id="Debug"></textarea>
  </details>
</div>

 

2. Authentication Options 가져오기

 

startAuthentication을 호출하기 전에 사용자 이름을 서버로 보냅니다

 

const resp = await fetch('<#webauthn_authentication_options>', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    username: document.getElementById("username").value,
    user_verification: 'preferred'
  }),
});

 

서버는 다음을 포함하는 JSON 객체로 응답합니다:

 

{
  "challenge": "base64url-encoded-random-string",
  "allowCredentials": [
    {
      "id": "base64url-credential-id",
      "type": "public-key"
    }
  ],
  "userVerification": "preferred",
  "rpId": "yourdomain.com"
}

 

이것을 PublicKeyCredentialRequestOptions라고 합니다.

 

 

3. Authenticator 응답 수신

 

asseResp는 다음과 같습니다(단순화됨):

 

{
  "id": "credentialId",
  "rawId": "base64url-encoded-id",
  "response": {
    "authenticatorData": "...",
    "clientDataJSON": "...",
    "signature": "...",
    "userHandle": "..."
  },
  "type": "public-key",
  "clientExtensionResults": {}
}

 

이 응답은 사용자가 다음을 증명합니다:

 

 

 

4. 서명된 Authentication Response를 서버에 전송

 

사용자가 인증자와 상호 작용한 후(startAuthentication()을 통해) JavaScript에서 응답 객체를 얻습니다.

 

const verificationResp = await fetch('/webauthn/authenticate/verify', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(asseResp), // 서명된 응답입니다
});

 

 

5. 서버의 응답 받기

 

서버는 다음과 같은 결과로 응답합니다:

 

{ "verified": true }

 

또는 문제가 발생한 경우:

 

{ "verified": false, "error": "Invalid signature" }

 

그리고 프런트엔드 코드에서 이를 처리합니다:

 

const result = await verificationResp.json();

if (result.verified) {
  document.getElementById('Success').textContent = 'User authenticated!';
} else {
  document.getElementById('Error').textContent = 'Authentication failed!';
}