SPECIALIST

多様な専門性を持つNRIデジタル社員のコラム、インタビューやインサイトをご紹介します。

BACK

次世代の認証技術 WebAuthnを紹介【前編】

工藤 大樹

みなさん、こんにちは。
NRIデジタルの工藤です。
私たちは、CoE活動として、新技術の探索・調査を行っています。
今回は次世代の認証技術として注目されている「WebAuthn」について前後編でご紹介します。

本記事ではWebAuthnの概要、WebAuthnを実現するための構成要素、実装シーケンスについてご紹介します。後半記事ではWebAuthnが抱える問題点とその解決策としてのPassKeyについてご紹介します。

WebAuthnとは

多くの人が、多数のWebサービスを日々利用しているかと思います。そんな中、複数のサービスのパスワードポリシーに応じてパスワードを設定しなければならないなど、パスワード管理に頭を悩ませている人も少なくないのではないでしょうか。パスワード認証はWebサービス利用を支える重要な技術ですが、課題があることも事実です。

このような悩みを解決するための技術の1つにFIDO(Fast Identity Online)があります。FIDOは生体情報やPINを用いて認証を行う技術で、ユーザはパスワードを入力する必要がなくなります。FIDO自体は、広く普及しておりiPhoneやAndroidのアプリから、パスワードを入力することなく、指紋認証や顔認証を利用してログインを行った経験がある方も多いかと思います。

FIDOは今まではネイティブアプリ用の規格しか用意されていませんでしたが、ブラウザ上で実行される、Webアプリ用にも標準規格が策定されました。それがWebAuthnです。

WebAuthnの仕組み

WebAuthnの仕組みを理解するには、まずはFIDOの仕組みについて知っておく必要があります。
FIDOは、ユーザのデバイスで生体認証やPINによる本人確認を行い、秘密鍵で暗号化した署名をサーバー側に送り、公開鍵で検証することでサーバー認証を行います。そのため、認証情報をネットワークで流す必要がありません。また、サーバーに保管されることもないためパスワード漏洩のリスクが低減します。

WebAuthnの実態は、Webブラウザ上のアプリケーションが利用するJavaScript APIであり、このAPIを利用することで、Webアプリケーション上でFIDO認証を行うことができます。

WebAuthnは以下のような流れになっています。
ブラウザ上で立ち上がるWebアプリから、登録/認証を行うためにボタンを押下する

  1. Webアプリから認証サーバにリクエストが送信される
  2. WebアプリからWebAuthn APIの呼び出しを行う
  3. ブラウザから認証器に生体認証がリクエストされる
  4. 認証器にて生体認証が行われる
  5. 認証器から生体認証の結果がブラウザに送られる
  6. WebアプリがWebAuthn APIのレスポンスとして認証結果を受け取る
  7. 認証サーバに認証結果が送信される
  8.  
    WebAuthnの流れ

    WebAuthnを実現するためには

    WebAuthnを利用するためには、認証器・ブラウザ・認証サーバの3つが必要となります。
    認証器及びブラウザはWebAuthnに対応しているものを利用する必要があります。
    認証サーバについてもAttestationの検証やAssertionの検証(詳細は後述)などいくつかの機能を有している必要があります。

    認証器のWebAuthn対応状況

    Android、iOS、Windowsといった主要なデバイスがWebAuhtnに対応しています。

    OS バージョン 最新(2022年10月時点)
    Android Android 7.0以降 Android 13
    iOS iOS 14 以降 iOS 16
    Windows 19H1 以降 22H2
    MacOS macOS 11.0 以降 macOS 13

    ブラウザのWebAuthn対応状況

    主要な多くのブラウザがWebAuthnに対応しています。

    OS ブラウザ
    Android Chrome、Edge、Firefox
    iOS Safari
    Windows Chrome、Edge、Firefox
    MacOS Safari
    iOSおよびMacOSにおいてFIDO認証をサポート
    (出典:iOSおよびMacOSにおいてFIDO認証をサポート – FIDO Alliance

    WebAuthn 認証サーバを実現のために利用可能なOSS

    認証サーバでは、Attestationの検証やAssertationの検証といった機能が必要となります。
    それらの機能を実現するために、多くのOSSライブラリが公開されています。

    名称 概要 参考(GitHubページ)
    webauthn4j
    • Java(SpringBootベース)で開発されているライブラリ
    • KeyCloakにも利用されているWebAuthnライブラリ
    https://github.com/webauthn4j/webauthn4j
    SimpleWebAuthn
    • TypeScript製のライブラリ
    https://github.com/MasterKale/SimpleWebAuthn
    fido2-lib
    • JavaScript製のライブラリ
    https://github.com/webauthn-open-source/fido2-lib#readme
    webauthn-ruby
    • Ruby製のライブラリ
    https://github.com/cedarcode/webauthn-ruby
    WebAuthn Go library
    • Go製のライブラリ
    https://github.com/duo-labs/webauthn

    WebAuthnのシーケンス

    WebAuthnには、登録/認証と2つのステップが存在します。
    WebAuthnによって登録/認証がどのように行われるかをご紹介します。

    登録

    ブラウザから認証サーバーに登録リクエストを送信する
    認証サーバーでチャレンジと呼ばれる文字列が生成され、サーバー情報とともにブラウザに送信される
    の情報にユーザー情報を付加して、認証器に本人確認をリクエストする
    認証器での本人確認が完了したら、公開鍵と秘密鍵のペアを作成する
    で生成した秘密鍵で署名した署名情報、ユーザー情報、公開鍵をブラウザに送信する
    認証サーバーに署名情報と公開鍵を送信し、DBに保存する

    ウェブ認証 API - Web API | MDN
    (出典:ウェブ認証 API – Web API | MDN

    登録時の流れは上記の通りですが、では実際にはどんなパラメータをやり取りしているのでしょうか。
    登録時にブラウザから実行されるAPIのリクエストとレスポンスのパラメータは次のようになっています。

    リクエスト情報

    登録時のリクエスト サンプル

    {		
        "rp": {		
            "id": "localhost",		
            "name": "WebAuthn4J Spring Security Sample"		
        },		
        "user": {		
            "id": "NaaEsLhmOiXdnWIBoyUKEKgwRH82k3yGTxItVQLfEi8"	
            "name": "sample",		
            "displayName": "sample"		
        },		
        "challenge": "_hVwJhKnnxS33XuhurfAUzdgSeAakVdqmgz_419o78TUk0247gEMY51I26YDyqTG3NgSs"	
        "pubKeyCredParams": [		
            {		
                "type": "public-key",		
                "alg": -257		
            },		
            {		
                "type": "public-key",		
                "alg": -7		
            }		
        ],			
        "authenticatorSelection": {		
            "requireResidentKey": true		
        },		
        "attestation": "direct",		
        "extensions": {		
            "credProps": true		
        }		
    }		

     
    リクエストパラメータ項目の説明

    パラメータ 内容
    rp 認証サーバの情報
    id 認証サーバを識別するためのID
    name 認証サーバ名
    user 登録を行うユーザの情報
    id 登録を行うユーザを識別するためのID
    name 登録を行うユーザの名称
    displayName ユーザの表示名称
    challenge 認証サーバが生成するランダムな文字列
    pubKeyCredparams 認証サーバがサポートするアルゴリズム
    type public-key固定
    alg 認証サーバがサポートするアルゴリズム
    authenticatorSelection 認証サーバが認証器に求める要件
    requireResidentKey 認証器のセキュリティキー内にユーザー情報を記録するオプション
    attestation attestationをどのように認証サーバが受け取るかを示す
    このパラメータの値は、”none”, “indirect”, “direct”から選択可能可能
    direct : 認証サーバは認証器で生成されたattestationをそのまま受け取る
    indirect : 認証サーバはattestationを受け取るが、Webアプリにて編集されたものでもよい
    none : attestationは不要
    extensions Webアプリ、認証器に追加の処理を要求する場合に使う拡張領域

    レスポンス情報

    登録時のレスポンス サンプル

    {	
     "authenticatorAttachment": "platform"	
     "id": "FafJLAJdfweECsR_rBLAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"	
     "rawId": "axifjwlDKejLAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
     "response": 	
      {	
       "attestationObject": "o2NmbXRoZmlkbxxxxx-ODGsrPjUhg9gDkfa9J50mpMg2R05sLaI5P_rB1QNGxcI5BlV5M-xxxxx-aaaaaa)""
       "clientDataJSON": "eyJjaGFsbGVuZ2UiOiJ1cFliNnNpYjlleEw3ZnZTZlFoSUVhek9rQmg4X1lKWFZQelN4MFQxNkIwIiwib3JpZ2luIjoiaHR0cDovL2xvY2FsaG9zdDo5MDAxIiwidHlwZSI6IndlYmF1dGhuLmNyZWF0ZSJ9"	
      }	,
       "type": "public-key"	
    }	

     
    レスポンスパラメータ項目の説明

    パラメータ 内容
    authenticatorAttachment 認証器の接続状態を指定するための文字列
    platform:ビルドインの認証器を表す
    cross-platform:外部接続の認証器を表す
    id rawIdをbase64urlエンコードしたもの
    rawId 公開鍵を特定するためのID
    response
    attestationObject 詳細は後述
    clientDataJSON 認証サーバの情報などををBase64エンコードしたもの
    type “public-key”固定

    Attestation

    認証器からはAttestation Objectと呼ばれる認証情報が返却されます。
    Attestation Objectとは、認証器の情報・ユーザーの公開鍵・認証サーバーの情報・チャレンジを、認証器の秘密鍵で署名したものです。Attestation Object・デバイスの公開鍵・ユーザーの情報を認証サーバーへ送り、デバイスの公開鍵を用いてAttestation Objectが検証されます。Attestation Objectの正当性が確認できたら、ユーザーの公開鍵・ユーザーの情報がDBに保存され、登録処理が完了します。
     
    WebAuthnのシーケンスをAttestation Objectを含めてまとめると下記のようになります。
    WebAutthnシーケンス 登録

    認証

    ブラウザから認証サーバーに認証リクエストを送信する
    認証サーバーでチャレンジと呼ばれる文字列が生成され、サーバー情報とともにブラウザに送信される
    認証器に本人確認をリクエストする
    サーバー情報を元にユーザーの一覧が表示され、ユーザーを選択して本人確認を行う
    認証器での本人確認が完了したら、ユーザーの秘密鍵で署名した署名情報、ユーザー情報をブラウザに送信する
    DBに登録されているユーザーの公開鍵で署名検証し、ユーザーを認証する

    ウェブ認証 API - Web API|MDN
    (出典:ウェブ認証 API – Web API | MDN

    認証時の流れは上記の通りです。
    次に認証時のAPIのリクエストとレスポンスのパラメータは次のようになっています。

    リクエスト情報

    認証時のリクエスト サンプル

    {
        "challenge": "_hVwJhKnnxS33XuhurfAUzdgSeAakVdqmgz_419o78TUk0247gEMY51I26YDyqTG3NgSs"
        "rpId": "localhost",
        "userVerification": "required",
        "extensions": {}
    }

     
    リクエストパラメータ項目の説明

    パラメータ 内容
    challenge 認証サーバが生成するランダムな文字列
    rpId 認証サーバを識別するためのID
    userVerification ユーザ認証を望むかを指定する。
    required:必須
    preferred: 必須でないが望む
    discouraged:不要
    extensions Webアプリ、認証器に追加の処理を要求する場合に使う拡張領域

    レスポンス情報

    認証時のレスポンス サンプル

    {
    	"id": "C3VNU4Wq0SEq4zVp7GPjRV0bIcscgM8nRr-m1hfD8o4",
    	"rawId": "axifjwlDKejLAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
    	"response": {
    		"credentialId": "C3VNU4Wq0SEq4zVp7GPjRV0bIcscgM8nRr-m1hfD8o4",
    		"clientDataJSON": "eyJ0eXBlIjoid2ViYXV0aG4uZ2V0IiwiY2hhbGxlbmdlIjoibmh5NUV2M1lRUW1icXl4SGRZTnFHUSIsIm9yaWdpbiI6Imh0dHA6Ly9sb2NhbGhvc3Q6ODA4MCIsImNyb3NzT3JpZ2luIjpmYWxzZSwib3RoZXJfa2V5c19jYW5fYmVfYWRkZWRfaGVyZSI6ImRvIG5vdCBjb21wYXJlIGNsaWVudERhdGFKU09OIGFnYWluc3QgYSB0ZW1wbGF0ZS4gU2VlIGh0dHBzOi8vZ29vLmdsL3lhYlBleCJ9",
    		"authenticatorData": "SZYN5YgOjGh0NBcPZHZgW4_krrmihjLHmVzzuoMdl2MFAAAABg",
    		"signature": "l-6sRMnfxKnQXkQsutd9YDPaqYmnE2T4MpKak1ppLE-UX9PTk_HR3Lhio1_4I3agqDNASw7Uwh3imDxyb1Ruu0C7U-6OqMdUX3QqK7F8KVVVBe7fBHTPMxzBR8CdkCNP8R_YEs32_DtG2ROfauK9wmYBrpOEKue94UAMreEG1_2G-SH0ilinSYKISpDxZonX9co7I5Sgng2GGOdkeBAvj0_kvl3_eLcVLfIY0Rem2Dbm70_HaI2tlzIhqD2PnncHjnHWt3yEm02qlDy0wMpRiMW-ksqesokszNe81i3UKR9cqOVSxb1HzdmQy3Chb9JPeD-SejVQHtjQbiJZCe_Gwg",
    		"userHandler": "YWFhYWFhYWFhYWFh"
    	},
    	"type": "publick-key"
    }

     
    レスポンスパラメータ項目の説明

    パラメータ 内容
    id rawIdをbase64urlエンコードしたもの
    rawId 公開鍵を特定するためのID
    response
    credentialId 認証器自体が持つID
    clientData 認証サーバの情報などををBase64エンコードしたもの
    authenticatorData 認証器の情報
    signature Assertion Object 詳細は後述
    userHandler 認証器が生成したユーザ識別子
    type “public-key”固定

    Assertion

    認証時は認証器からAssertion Objectが返却されます。Assertion Objectとは認証サーバーの情報とチャレンジをユーザーの秘密鍵で署名したものです。登録時にDBに保存したユーザーの公開鍵を用いてAssertion Objectを検証することで、認証を行います。

    WebAuthnのシーケンスをAssertion Objectを含めてまとめると下記のようになります。

    WebAuthnシーケンス 認証

    まとめ

    本記事では、WebAuthnという認証技術の概要や、WebAuthn APIのシーケンスを紹介しました。WebAuthnは、Webアプリでのパスワードレスな認証を実現する技術です。WebAuthnを利用することにより、ユーザは日々利用している複数のサイト、それぞれに対するパスワードを覚えておく必要がなくなります。
    また、iPhoneとAndroidといった異なるプラットフォームの端末が共通のWebアプリで認証可能となるため、開発者はプラットフォーム毎に認証処理を開発する必要がなくなります。

    しかし、WebAuthnには認証機を紛失してしまった場合リカバリができなかったり、端末を買い替えた際の認証情報の移行ができなかったり、いくつかの課題があります。

    後半の記事では、WebAuthnの課題と課題を解決する技術であるPasskeyについてご紹介します。