🗝️

パスキー認証 - LINE FIDO2サーバーで体験(masOS & スマホ編)

2024/01/17に公開

概要

パスワードレス認証として話題のパスキー。
パスキー認証をまず体験しAPI通信の内容を見てみて少しずつ理解してくための手順。

実際にパスキーで認証可能なサービス

□ 実際のサービスで体験したい場合は以下のアプリで体験できる。
アカウントを登録後、アカウント設定画面からパスキーを登録しログアウト。
ログイン時にパスキー認証でログインができる。

□ TikTokのアプリ https://www.tiktok.com/ja-JP/

□ ニンテンドーアカウント https://www.nintendo.co.jp/support/nintendo_account/passkey/index.html

LINE FIDO2サーバーを体験

□ パスキーの認証がどのように実現されているか理解するために、実装イメージを確認。
□ オープンソースとして公開されているLINE FIDO2-Serverを利用し、通信の内容を確認。
□ その後にシーケンス図を確認することで理解を深める。

環境

□ macOSのPCを利用
□ スマホとPCは同じネットワークに繋がっている(例:同じwifiに繋がっている)

□ (参考)本記事で利用した環境
 □ DockerDesktop: 4.26.1 (131620), Engine: 24.0.7
 ※ DockerDesktop利用できない場合、Rancher Desktop利用でもOK。
 ※ Docker Desktopは条件に該当した場合のみ無料で利用できる。
 有償条件に該当する企業に所属している場合でDocker Desktopを使用したい場合は、
 自己学習として自宅のPCで実行することをおすすめする。

□ PC: Mac mini(Apple M2), masOS 14.2.1
 □ スマホ: iPhone(iOS17.1.2)

□ 使用するもの:LINE FIDO2-Server
オープンソースとして公開されているLINE FIDO2-Serverを利用し、パスキー認証を体験する。

LINE Security R&Dチームは、FIDO2をより広く普及し、より良いソフトウェアに成長させるため、LINE FIDO2-Serverをオープンソースとして公開することにしました。このような活動が、最終的にFIDOエコシステムの発展に貢献すると期待しています。
私たちが公開したオープンソースのGitHubリポジトリーは以下のとおりです。
https://github.com/line/line-fido2-server

https://engineering.linecorp.com/ja/blog/fido-at-line-fido2-server-opensource

手順.macOSでLINE FIDO2サーバーを試す

1.レポジトリのクローン

□ 任意の名前でフォルダを作成する
□ Visual Studio Codeで作成したフォルダを開く
ctrlキー@キーでTERMINALを開く

□ terminal上で下記を実行

git clone https://github.com/line/line-fido2-server.git

line-fido2-serverのフォルダをVisual Studio Codeで開く

□ Visual Studio Codeでline-fido2-serverのフォルダを開く

□ (参考)line-fido2-serverのレポジトリ
https://github.com/line/line-fido2-server

(参考)M2チップ搭載のmacOSを利用している場合に実行

/line-fido2-server/server/Dockerfileの先頭行を下記に変更する

FROM --platform=linux/amd64 openjdk:8-jdk-slim

※上記変更を加えないとfido2コンテナが立ち上がらないためです。下記を参考。
https://github.com/line/line-fido2-server/issues/45

2.Dockerコンテナを起動

□ terminal上で下記を順番に実行

docker build -t build-image .
docker-compose build
docker-compose up -d

※サーバーが起動するまで時間がかかる可能性あり。
サーバー起動したかはdocker-compose logs rpdocker-compose logs fido2でログから分かる。

3.立ち上がった各サーバーを確認する

http://localhost:8080http://localhost:8081にアクセスできるかを確認

URL 説明 用途 API仕様書
http://localhost:8080 FIDO2 RP SERVER REST API RP側のサーバー(クライアントがアクセスするサーバー) http://localhost:8080/swagger-ui.html#/
http://localhost:8081 FIDO2 SERVER REST API 署名を検証するサーバー http://localhost:8081/swagger-ui.html#/

4.RPサーバーにアクセスしてみる

※ 指紋認証などが無いPCの場合でもPINコード入力で確認できる。
※ 筆者の環境はUSBのYubikeyBioに登録した情報で実行している

http://localhost:8080 にアクセスする

xxxxxx@gmail.comなど任意の値をUser NameとDisplayNameに入力する。

□ PC内蔵の認証機器ではなく、YubiKeyなど含め外部デバイスで認証を行う場合は「On roaming (cross-platform) authenticator」を選択する。
※該当する場合のみ選択。

□ 通信の状態を確認するため、fnキーとF12キーを押して、開発者コンソールを開く。
□ Networkタブを選択し、Preserve Logのチェックボックスにチェックを入れる。
□ ALLが選択されていることを確認する。

□ Registerタブを押下する (パスキー登録)
 □ /attestation/options APIが呼び出されていることが開発者コンソールから確認できる。

□ 認証のモーダルが表示されること
※筆者の環境はUSBのYubikeyを認証情報登録に使用している

□ 指紋などで認証をしてOKの場合、下部に成功メッセージが表示されていること

□ 認証OKの場合、/attestation/result APIが呼び出されていることが確認できる。
 □ リクエストパラメーターはpayloadタブから確認できる
 □ レスポンスデータはPreviewタブから確認できる

□ 青色のAuthenticateボタンを押下する (パスキー認証)
 □ 認証のモーダルが表示される

□ /assertion/options APIが呼び出されていることが開発者コンソールから確認できる。

□ 指紋をかざしOKの場合、/assertion/result APIが呼び出されていることが確認できる。



□ macOSでのパスキー体験に必要な手順はここで終わりです。
※次以降の手順はhttps化やスマホからのアクセスに必要な手順であり、必要な場合に実施してください。

(参考)シーケンスを確認してみる

□ line-fido2-serverが公開しているシーケンスの配置場所
https://github.com/line/line-fido2-server/wiki/Sequence-diagrams

□ 補足:開発者コンソールで確認した通信部分は画像の赤枠部分である。

5.h2-consoleへアクセスできるかを確認

h2-consoleはH2インメモリデータベースで簡易的にサーバーが立ち上がっている間だけデータを保存しておける。

http://localhost:8081/h2-console へアクセス
JDBC URL:にはjdbc:h2:mem:userdb;を入力しconnect。

□ No suitable driver foundエラーになるため、コードを修正する。
https://github.com/line/line-fido2-server のREADME.mdの記載を参考に、implementation('org.zalando:logbook-spring-boot-starter:1.8.1') をコメントアウトする。
<修正対象ファイル>

  • /line-fido2-server/spring-boot-starter/line-fido2-spring-boot-demo/build.gradle

  • /line-fido2-server/server/build.gradle

// implementation('org.zalando:logbook-spring-boot-starter:1.8.1')

□ 下記を順番に実行

docker-compose down
docker build -t build-image .
docker-compose build
docker-compose up -d

※サーバーが起動するまで時間がかかる可能性あり。
サーバー起動したかはdocker-compose logs rpdocker-compose logs fido2でログから分かる。

□ 再度 http://localhost:8081/h2-console へアクセス
JDBC URL:にはjdbc:h2:mem:userdb;を入力しconnect。

下記が表示されていることを確認する。

(参考) SELECT * FROM RPなどSQLでデータを参照できる。

手順.ローカルでLINE FIDO2サーバーをhttps化する

6.ループバックアドレスのエイリアスを追加する

□ ループバックアドレスのエイリアスを追加
https化の前にrpとfido2のdockerコンテナを同じportで立ち上げるようにするためです。

sudo ifconfig lo0 alias 127.0.0.2

□ ループバックの設定が追加されているかを確認する

ifconfg

□ /etc/hostsの設定を変更する
下記を参考にドメイン名を127.0.0.1と127.0.0.2に指定してください

127.0.0.1	localhost
127.0.0.2	localhost

127.0.0.1	fido2.exampletthoge.com # fido2サーバー用
127.0.0.2	exampletthoge.com # rpサーバー用

これでlocalhostに127.0.0.2でもアクセスできるようになります。
PCを再起動したらこのループバックアドレスのエイリアス設定は消えます。

□ docker-compose.ymlを変更

/line-fido2-server/docker-compose.ymlのportsを下記に変更し、docker-compose up -dを実行。

~略~
      ports:
        - "127.0.0.2:8080:8080"
~略~	
     ports:
        - "127.0.0.1:8080:8081"	

変更後の全体は以下。

version : "3.8"
services:
    build:
      container_name: build-image
      image: build-image:latest
      build:
        context: .
        dockerfile: ./Dockerfile
    rp:
      container_name: rp-server
      image: rp:latest
      build:
        context: .
        dockerfile: ./rpserver/Dockerfile
      ports:
        - "127.0.0.2:8080:8080"
      restart: always
    fido2:
      container_name: fido2-server
      image: fido2:latest
      build:
        context: .
        dockerfile: ./server/Dockerfile
      ports:
        - "127.0.0.1:8080:8081"
      restart: always

□ httpとドメインでアクセスできるかを確認する。
※この時点ではhttpsではなく、まだhttpです。

http://exampletthoge.com:8080

http://fido2.exampletthoge.com:8080

※ DockerDesktopではなくRancher Desktop環境を利用している場合http://fido2.exampletthoge.com:8080のみアクセスができることを確認できればOK。
Rancher Desktop環境の場合は127.0.0.2:8080にホスト環境のブラウザから接続が上手く行かない。

Rancher Desktop環境でも後続のhttps化を行なえRPサーバーにアクセスできるので、http://fido2.exampletthoge.com:8080にアクセスできることを確認できたら次に進む。

7.HTTPS化のためのオレオレ証明書を生成する

この手順7はmacのterminalで実行する。
オレオレ証明書(ルート証明書とサーバー証明書)を生成する手順です。

□ 自分のPCのIPアドレスを下記を参考に調べる
https://zenn.dev/ianchen0419/articles/25b066414188a6

□ mkcertのインストール

brew install mkcert

□ ローカル認証局(CA)のインストール

# ローカル認証局用のディレクトリを任意の場所で作成  ※作成は必須ではありません。
cd
mkdir mkcert
cd mkcert
# ローカル認証局のインストール(mkcert install)
mkcert install

□ サーバー証明書と秘密鍵を作成

# ※サーバー証明書, 秘密鍵用のディレクトリを作成  ※作成は必須ではありません。
mkdir mkcert/ssl
cd mkcert/ssl
# サーバー証明書と秘密鍵を作成1(mkcert rpドメイン名 自分のPCのIPアドレス ループバックアドレスを指定)
# ※自分のPCのIPアドレスに置き換えて実行すること
mkcert exampletthoge.com 192.168.0.7 127.0.0.2
# サーバー証明書と秘密鍵を作成2(mkcert fido2ドメイン名 自分のPCのIPアドレス ループバックアドレスを指定)
# ※自分のPCのIPアドレスに置き換えて実行すること
mkcert fido2.exampletthoge.com 192.168.0.7 127.0.0.1

□ トラストストアにローカル認証局(CA)をインストール(mkcert -install)

mkcert -install
# ※Sudo passwordは、macのパスワードを入力

□ キーチェーンのシステムを見るとmkcertで作成したルート証明書が格納されているのが分かる。

□ (参考)
https://zenn.dev/takumiabe21/articles/645a38c0c18389

8.rpとfido2サーバーのhttps化

まず/line-fido2-server/docker-compose.ymlを変更する。

□ nginxコンテナの定義をdocker-compose.ymlに追加する。

~略~
    nginx:
      image: nginx:alpine
      restart: always
      volumes: # ローカルPCのディレクトリ:コンテナの中のディレクトリ
        - ./nginx:/etc/nginx   
        - ./selfcert:/etc/cert/
      ports:
            - 80:80
            - 443:443
      extra_hosts:
        - "host.docker.internal:host-gateway"
      networks:
        app_net:
          ipv4_address: 172.30.0.4     
~略~

□ networksの定義をdocker-compose.ymlに追加

~略~
networks:
  app_net:
    driver: bridge
    ipam:
     driver: default
     config:
       - subnet: 172.30.0.0/24 # コンテナのIPアドレスを指定するために設定
~略~

□ rpとfido2にnetworkとIPアドレスの指定をdocker-compose.ymlに追加

~略~
      networks:
        app_net:
          ipv4_address: 172.30.0.2 # コンテナのIPアドレスを指定する
~略~
      networks:
        app_net:
          ipv4_address: 172.30.0.3 # コンテナのIPアドレスを指定する

□ 変更後の全体は以下となる。

# /line-fido2-server/docker-compose.yml
version : "3.8"
services:
    build:
      container_name: build-image
      image: build-image:latest
      build:
        context: .
        dockerfile: ./Dockerfile
    rp:
      container_name: rp-server
      image: rp:latest
      build:
        context: .
        dockerfile: ./rpserver/Dockerfile
      ports:
        - "127.0.0.2:8080:8080"
      restart: always
      networks:
        app_net:
          ipv4_address: 172.30.0.2 # コンテナのIPアドレスを指定する

    fido2:
      container_name: fido2-server
      image: fido2:latest
      build:
        context: .
        dockerfile: ./server/Dockerfile
      ports:
        - "127.0.0.1:8080:8081"
      restart: always
      networks:
        app_net:
          ipv4_address: 172.30.0.3 # コンテナのIPアドレスを指定する    

    nginx:
      image: nginx:alpine
      restart: always
      volumes: # ローカルPCのディレクトリ:コンテナの中のディレクトリ
        - ./nginx:/etc/nginx   
        - ./selfcert:/etc/cert/
      ports:
            - 80:80
            - 443:443
      extra_hosts:
        - "host.docker.internal:host-gateway"
      networks:
        app_net:
          ipv4_address: 172.30.0.4        

networks:
  app_net:
    driver: bridge
    ipam:
     driver: default
     config:
       - subnet: 172.30.0.0/24 # コンテナのIPアドレスを指定するために設定

□ 手順7で作成したサーバー証明書と秘密鍵を配置する用のselfcertフォルダを作成
/line-fido2-server/selfcert/

□ 手順7で作成したmkcert/sslフォルダ内のサーバー証明書と秘密鍵をコピーして/line-fido2-server/selfcert/に配置する

□ nginxフォルダを作成
/line-fido2-server/nginx/

□ nginxフォルダの中にnginx.confファイルを空ファイルで作成する。
/line-fido2-server/nginx/nginx.conf

□ nginx.confの中身を下記のように記載する

events {
    worker_connections  16;
}
http {
    server {
        listen 443 ssl;
    	ssl_certificate     /etc/cert/exampletthoge.com+2.pem;
    	ssl_certificate_key /etc/cert/exampletthoge.com+2-key.pem;
        server_name  exampletthoge.com;
        location / {
            proxy_pass http://172.30.0.2:8080/; # rpコンテナのipアドレス:port
            proxy_redirect off;
        }
    }

    server {
        listen 443 ssl;
    	ssl_certificate     /etc/cert/fido2.exampletthoge.com+2.pem;
    	ssl_certificate_key /etc/cert/fido2.exampletthoge.com+2-key.pem;
        server_name  fido2.exampletthoge.com;
        location / {
            proxy_pass http://172.30.0.3:8081/; # fido2コンテナのipアドレス:port
            proxy_redirect off;
        }
    }
}

□ 一旦httpsで起動が成功するかを確認する。
下記を順番に実行。

docker-compose down
docker build -t build-image .
docker-compose build
docker-compose up -d

※サーバーが起動するまで時間がかかる可能性あり。
サーバー起動したかはdocker-compose logs rpdocker-compose logs fido2でログから分かる。

https://exampletthoge.com にアクセスアクセスできることを確認

https://fido2.exampletthoge.com にアクセスできることを確認

※ この時点ではhttpsで起動はするがRPサーバーの設定の変更をしていないのでパスキー登録ができない。

9.RPサーバーの設定変更

□ application-docker.ymlをドメイン名に変更
ファイル: /line-fido2-server/rpserver/src/main/resources/application-docker.yml

rp.id, rp.origin, rp.port, conformance.urlの値を下記のように変更する。

# /line-fido2-server/rpserver/src/main/resources/application-docker.yml
# 変更後
spring:
  profiles:
    active: docker
  resources:
    chain:
      cache: false
fido2:
  rp:
    id: exampletthoge.com
    origin: exampletthoge.com
    port: 443
conformance:
  url: https://exampletthoge.com
logging:
  level:
    org.springframework.web: DEBUG
    org.hibernate: DEBUG
    com.linecorp.line: DEBUG
fido2-server:
  host: fido2

□ rpサーバーのAdapterController.javaを変更
※これはローカルでスマホを繋げてパスキー体験してみるための変更です。本来はチェック処理をコメントアウトすべきではないです。

ファイルパス:
/line-fido2-server/rpserver/src/main/java/com/linecorp/line/auth/fido/fido2/rpserver/controller/AdapterController.java

・ append(scheme)の記述をappend("https")に変更
AdapterController.java内の2箇所とも変更する。

        StringBuilder builder = new StringBuilder()
-                .append(scheme)
+                .append("https")

・ rpPortのチェックをコメント化する
AdapterController.java内の2箇所とも変更する。

-        if (!StringUtils.isEmpty(rpPort)) {
-            builder.append(":")
-                   .append(rpPort);
-        }

+        // if (!StringUtils.isEmpty(rpPort)) {
+        //     builder.append(":")
+        //            .append(rpPort);
+        // }

□  AuthenticatorTransport.javaにhybridを追加する。
ファイルパス:
/line-fido2-server/common/src/main/java/com/linecorp/line/auth/fido/fido2/common/AuthenticatorTransport.java

-    INTERNAL("internal");
+    INTERNAL("internal"),
+    HYBRID("hybrid");

□ dockerを起動する。
・ 下記を実行。

docker-compose down
docker build -t build-image .
docker-compose build
docker-compose up -d

※サーバーが起動するまで時間がかかる可能性あり。
サーバー起動したかはdocker-compose logs rpdocker-compose logs fido2でログから分かる。

10.RP IDの登録

□  http://fido2.exampletthoge.com:8080/h2-console へアクセス
JDBC URL:にはjdbc:h2:mem:userdb;を入力しconnect。

□  入っている値を確認する
SELECT * FROM RP

□  RPのドメインをRP IDとして登録する。
INSERT INTO RP(ID, NAME, ICON)VALUES('exampletthoge.com', 'example1', null);

□ 動作確認する (https://exampletthoge.com/)

  • User nameとDisplay nameを入力してRegsiter、Authenticateができるかを確認する。
  • PC内蔵の認証機器ではなく、YubiKeyなど含め外部デバイスで認証を行う場合は「On roaming (cross-platform) authenticator」を選択する。
    ※該当する場合のみ選択。

□ パスキー登録

※筆者の環境はUSBのYubikeyを認証情報登録に使用している

□ パスキー認証
※筆者の環境はUSBのYubikeyを認証に使用している

手順.スマホからアクセスできるようにする

前提:手順.ローカルでLINE FIDO2サーバーをhttps化するが終わっていること。

11.squidのinstall

terminalから実行

brew install squid

12.squid.confの設定を変更

/opt/homebrew/etc/squid.conf を以下のように修正する。

□  以下を新規追加

#
# Recommended minimum configuration:
#
visible_hostname UNKNOWN # <--追加: ホスト名の秘匿
hosts_file /etc/hosts # <--追加:参照するhostsファイル

□  acl lan srcの行を追加

# Example rule allowing access from your local networks.
# Adapt to list your (internal) IP networks from where browsing
# should be allowed
acl localnet src 0.0.0.1-0.255.255.255	# RFC 1122 "this" network (LAN)
acl localnet src 10.0.0.0/8		# RFC 1918 local private network (LAN)
acl localnet src 100.64.0.0/10		# RFC 6598 shared address space (CGN)
acl localnet src 169.254.0.0/16 	# RFC 3927 link-local (directly plugged) machines
acl localnet src 172.16.0.0/12		# RFC 1918 local private network (LAN)
acl localnet src 192.168.0.0/16		# RFC 1918 local private network (LAN)
acl localnet src fc00::/7       	# RFC 4193 local private network range
acl localnet src fe80::/10      	# RFC 4291 link-local (directly plugged) machines

acl lan src exampletthoge.com  # <--追加: RPのドメイン名
acl lan src 192.168.0.7 # <--追加:自分のPCのIPアドレス

□  http_access deny to_localhostをコメントアウトする。

# http_access deny to_localhost # <-- コメント化

□ squidを起動

brew services start squid

□ (参考) squidを停止

brew services stop squid

□ (参考) squidを再起動

brew services restart squid

13.iPhoneのwifiの設定を変更する

□ wifiの設定画面を開き、「自動」になっているプロキシの構成を「手動」にする。
サーバー: 192.168.0.7など自分のPCのIPアドレスを入力する
ポート: 3128
※macでsquidが立ち上がっているport

14.スマホから動作確認を行う

□ スマホから https://exampletthoge.com/ にアクセスする。

□ スマホ側に残っているパスキーの情報を確認
スマホの設定画面を開き、パスワードで検索

exampletthoge.comの欄を押下すると、どのUser nameで登録したかがわかる。

事後処理

□ Dockerコンテナを終了する

docker compose down

□ iPhoneのwifiの設定のプロキシを構成を「自動」に戻す

□ squidを停止する

brew services stop squid

□ PCを再起動しループバックアドレスのaliasを削除する

□ 発行したルート証明書の削除
キーチェーンのシステムからmkcertで作成したルート証明書を削除する。

今回のソースコード

□ マスターのレポジトリから変更したソースコードの差分一覧は以下を参照
https://github.com/sktaz/rp-fido2-sv/pull/1

windows&スマホ編はこちら

https://zenn.dev/ringo_to/articles/b319cd628a620b

Discussion