🌐

多要素認証のワンタイムパスワードを利用する方法

2023/04/02に公開

Heroku でアカウントを登録したところ、多要素認証の設定が必要でした。セキュリティ強化の一旦として、Heroku のように多要素認証の設定を強制するサービスが増えてきています。少し調べてみました。

OTP

多要素認証のひとつにワンタイムパスワードの利用があり、よく使われています。ワンタイムパスワード(OTP)とは の説明によると、OTP は One Time Password 略ということなので、一時的に発行されるパスワードを意味します。

OTP には、TOTP(Time-based One-time Password)や HOTP(HMAC-based One-time Password) の方式があります。HOTPの「H」は、Hash-based Message Authentication Code(HMAC) が由来です。それぞれ、RFC 6238: TOTP: Time-Based One-Time Password AlgorithmRFC 4226: HOTP: An HMAC-Based One-Time Password Algorithmにアルゴリズムの説明があります。

OTP の利用方法

OTP を実際に使う場合は、対応している認証アプリをスマートフォンやPCにインストールします。OTP に対応しているシステムでは、システムが生成した QR コードを、認証アプリで読み取って、認証アプリへ登録しておきます。システムへログインするときには、認証アプリでワンタイムパスワードが確認できるので、それを使います。

ここからは TOTP を使う前提で説明します。TOTP を使う場合は時刻ベースなのでシステム側と自分が使うデバイスと両方の時刻が一致している必要があります。

TOTP 対応のスマートフォンアプリ

TOTP 対応のスマートフォンアプリとしては、Google 認証システム(Google LLC)(Android, iOS)や Microsoft Authenticator(Microsoft Corporation)(Android, iOS) があります。

これらをスマートフォンへインストールし、アプリを起動するとカメラからシステムが提供する QR コードを読み取ることができて、登録が簡単にできます。QR コードの画像、もしくは、QR コードの画像に含まれている文字列をバックアップしておけば、デバイスが故障しても他のデバイスへ登録しなおして復旧することができます。当然ながら、バックアップをした場合は、きちんと管理が必要で、それが漏洩しないように注意してください。

TOTP 対応の PC アプリ

スマートフォンだけでなく、PC でも認証アプリが使えます。例えば Chrome 拡張機能の Chrome Authenticator があります。

Chrome の QR コードが表示されている画面で、Authenticator のペンシルアイコンをクリックし、表示される「+」をクリックしてから「QRコードをスキャン」をクリックすると、QR コードをキャプチャする枠を指定できるので、それを使って QR コードの読み込みをします。

あらかじめ保存しておいたQRコードを使って情報を取得してから、「手動入力」することもできます。その場合は、QRコードのデコーダーが必要です。

QRコードのデコーダーを使うと、QR コードから otpauth://totp/Heroku:<ユーザー名>?issuer=<発行者>&secret=<シークレット>&algorithm=<アルゴリズム>&digits=<桁数>&period=<期間> といったテキストが読み取れます。このテキストに含まれる値を Chrome Authenticator へ登録するときに指定します。

  • 発行者: 発行者
  • シークレット: シークレット
  • その他
    • ユーザー名: ユーザー名
    • 期間: 期間
    • 桁数: 桁数
    • アルゴリズム: アルゴリズム
    • タイプ: タイムベース(totp からわかる)

QRコードのデコーダー

Ubuntu Desktop

QRコードのデコーダーとしては、Ubuntu Desktop であれば qtqr パッケージの qtqr コマンドが使えます。インストールは次のようにします。

sudo apt install -y qtqr

これで、アプリの一覧に QtQr が追加されるので、それを起動します。コマンドから起動する場合は次のようにします。

qtqr

QtQr を起動したら「ファイルからデコード」をクリックし、QRコードを保存した画像を指定するとテキストが表示されます。

Python + Docker Compose

Python でプログラムを作成し、Docker Compose を使って動作させることもできます。使い方は README.md を参照してください。

python3-qrcode/
├── README.md
├── docker-compose.yml
├── main.py
├── requirements.txt
├── run.sh
└── sample.png

README.md

# qrcode

下記のファイルを用意します。

```text
python3-qrcode/
├── README.md ... このファイル
├── docker-compose.yml ... 
├── main.py
├── requirements.txt
├── run.sh
└── sample.png
```

以降、python3-qrcode のディレクトリーを `${REPO_DIR}` と表記します。

## 使い方

`${REPO_DIR}/qrcode.png` に QR コードの PNG 画像を用意します。
`${REPO_DIR}` をカレントディレクトリーとして下記コマンドを実行すると、出力の最後に QR コードに含まれるテキストが表示されます。

```console
docker compose run --rm python3-qrcode sh /app/run.sh
```

出力結果例

```console
$ docker compose run --rm python3-qrcode sh /app/run.sh
[+] Running 1/0
(略)
/usr/local/lib/python3.9/site-packages/PIL/Image.py:992: UserWarning: Palette images with Transparency expressed in bytes should be converted to RGBA images
  warnings.warn(
otpauth://totp/Heroku:<ユーザー名>?issuer=<発行者>&secret=<シークレット>&algorithm=SHA1&digits=6&period=30
```

docker-compose.yml

name: qrcode
services:
  python3-qrcode:
    image: python:3.9.16-bullseye
    container_name: python3-qrcode
    hostname: python3-qrcode
    tty: true
    volumes:
      - ./:/app

requirements.txt

numpy==1.24.2
opencv-python==4.7.0.72
Pillow==9.5.0
pyzbar==0.1.9

main.py

import numpy as np
from PIL import Image
import pyzbar.pyzbar as pyzbar
import os

FILENAME = 'qrcode.png'
FILE_PATH = os.path.join(os.path.dirname(os.path.abspath(__file__)), FILENAME)

img = Image.open(FILE_PATH).convert('L')
img_array = np.array(img)
decoded = pyzbar.decode(img_array)
for d in decoded:
    print(d.data.decode('utf-8'))

run.sh

#!/bin/sh
if [ ! -e /usr/local/lib/python3.9/site-packages/PIL ]; then
  apt-get update && apt-get -y install libzbar0
  pip install -r /app/requirements.txt
fi
python /app/main.py 

Discussion