Twilio Verify を使った2要素認証の実現

## 目的
最近はセキュリティ、セキュリティと情報の流出を防ぐ必要がますます増えてきています。

そんな中でも、特にユーザーのメールアドレス・パスワードの流出で、アカウントが盗まれるような問題が発生するのが後を絶ちません。そもそも、パスワードを生でデータベースに保存していること自体、問題のある管理ですが、仮にパスワードを暗号化していたとしても、緩いパスワード制限による、ブルートフォース攻撃での問題も後を絶ちません。

そこで2要素認証ですね。仮にメールアドレスパスワードが通っても、2要素認証で防ぐことが可能となります。そんな時に Twilio Verify を使って簡単に実装していきましょうというのが本記事のテーマです。

https://www.twilio.com/ja/verify

Twilio Verify を見ると、SMS、音声、メール、プッシュ、WhatsApp、期限付きワンタイムパスワードといった選択肢があります。SMSや音声での2要素認証は、まさにTwilioらしい認証の方法ですね。

本記事では Twilio Verify の中でも、執筆時点で Beta の Verify TOTP にフォーカスして実際に学んだことをまとめたいと思います！

https://www.twilio.com/docs/verify/quickstarts/totp

Twilio Verify での TOTP を使えば、Authy や Google認証システムを使って2要素認証を実現できます。この方法での2要素認証が当たり前になりつつありますよね。

では始めていきましょう。

## Twilio Verify 実装手順
### 1 アカウント作成
まずは Twilio アカウントがなければ何も始まりません。作りましょう。

https://www.twilio.com/blog/how-to-create-twilio-account-jp

### 2 Twilio Verify 初期設定
その後、Twilio Verify にアクセスして Service を一つ作りましょう。

![スクリーンショット 2022-07-03 13.33.29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/11103/72a489b5-5091-89f9-da24-e39c5264a628.png)

ここでの設定は、DTMF Input を ON にするだけで大丈夫です。もしかしたら今後何か設定内容が追加されるかもしれないため、執筆時点ではとなります。TOTP関連の設定が出て来れば必須となります。

必要なのは、作った後に表示される Verify Service SID です。これをまずどこかに保存しておきます。

VAXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

### 3 Factor の作成
今回は Ruby REST API でサンプル掲示していきます。

まず、 Factor と呼ばれる認証の種類で、'totp' を作ります。

```ruby
new_factor = @client.verify
                    .services('VAXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX')
                    .entities('identity')
                    .new_factors
                    .create(
                       friendly_name: user.name,
                       factor_type: 'totp'
                     )
new_factor.sid #=> YF....
new_factor.binding #=> secret, uri
```

ここで、Entities というものを指定する必要があります。ドキュメントを読むと、ユーザーを特定する Identity であるとあり、8~64文字の文字に意味のなさないランダムな文字列である必要があります。

正直こんなランダムで予測困難な文字列を作るくらいは Twilio 側でやってほしい・・・ということでドキュメントをひたすら読むと、小さく方法がありました！ 'identity' という特別な Entity を指定すると、なんとランダムで作られます。

ここで出てくる Factor SID と、ランダムで作られる Entity SID の2つをどこかに保存しましょう。

YFXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
YEXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

### 4,画像の作成
Google 認証システムやAuthyを使ったことがあれば分かる通り、最初に登録する際に画像の表示が必要です。

どのURLを表示させるのかというと、先ほど作った Factor の binding にある "uri" です。

```ruby
new_factor.binding["uri"]
=> "otpauth://totp/Sample%20Account%20Name?secret=VYRL......&issuer=Sample&algorithm=SHA1&digits=6&period=30"
```

さっと進めたい場合には、Factor の作成時に作る friendly_name は単なるアルファベット文字の並びだけにすると、面倒なことが起きないので、おすすめです。

表示には Google Chart を使うのが一番楽です。

```ruby
let chl = "otpauth://totp/Sample%20Account%20Name?secret=VYRL......&issuer=Sample&algorithm=SHA1&digits=6&period=30";
let chs = "180x180";

let imageLink = "https://chart.googleapis.com/chart?cht=qr&chs=#{chs}&chld=L|0&chl=#{chl}"

"<img src="#{imageLink}" />"
```

これで、よく見る認証の画像をWebページに表示することができます。

※ 自分がハマったのは、 Factor を作るときに、friendly_nameに"@"が含まれていると、正しく2要素認証アプリで認識されなかったことです。普段、Google認証システムを使っていると、認証選択のエリアでメールアドレスが表示されるのに慣れていますよね。
この問題の対応のために、私は https://github.com/mdp/rotp を参考にして自前で otpauth リンクを作ることにしました。(この件は省略)

### 5, 新規登録のための入力確認
一番最初のコードを正しく入力して初めて、今後そのアカウントの2要素認証を有効にさせることができます。

ユーザーが4で掲示した画像をAuthy や Google認証システムでカメラで読み込めば、数字が出力されます。この数字を入力してもらうことになります。

```ruby
factor = @client.verify.services('VAXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX')
                       .entities('***')
                       .factors('YFXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX')
                       .update(auth_payload: '293412')
puts factor.status
```

正しければ verified, 不正なら unverified が返ってきます。
verified になった時点で、2要素認証の登録完了となります。

### 6, ログインするたびに2要素認証を表示
ここまできてようやく Twilio Verify で TOTP 2要素認証を始めることができます。

ユーザーがメールアドレス、パスワードの入力後、TOTPの6桁文字を入力させるフォームを用意し、その入力内容を確認するようにします。

```ruby
challenge = @client.verify
                   .services('VAXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX')
                   .entities('***')
                   .challenges
                   .create(
                      auth_payload: '123456',
                      factor_sid: 'YFXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
                    )
puts challenge.status
```

ここで approved が返ってきたら、見事、認証に成功したことになります！ めでたしめでたし。

## 終わりに
本記事は Twilio Verify の以下のURLを参考にしています。

https://www.twilio.com/docs/verify/quickstarts/totp

これから新しくTwilio Verifyを作る場合は、"これだけ"でいいのはとても楽ですね！

ちなみに私はTwilio Authyという旧Twilio Verifyなサービスにあるデータを移設する作業が別途あって、さらに追加で実装が必要です。。そんなシチュエーションにあるのは国内で自分くらいしかいない？と思うので、記事にはしないでおきます。

新しくなった Twilio Verify で、より安全なWebサービスを目指しましょう！