「秘密の質問」のベストプラクティス

認証要素の一つとして時折使われる「秘密の質問」、皆さんは使っていますか？

以前よりは見かけなくなってきたように思いますが、まだ様々なところで使われているこの認証要素、開発者としても利用者としても大変な曲者です。

本記事ではその危険性と向き合い対策するためのベストプラクティスをご紹介します。

※ 本記事は [OWASP Testing Project](https://www.owasp.org/index.php/OWASP_Testing_Project) の一節、[Testing for Weak security question/answer (OTG-AUTHN-008)](https://www.owasp.org/index.php/Testing_for_Weak_security_question/answer_(OTG-AUTHN-008)) を参考にしています。

# 「秘密の質問」とは

>秘密の質問（ひみつのしつもん、英語: secret question）またはセキュリティ質問（セキュリティしつもん、英語: security question）は、認証者によって用いられる共有秘密鍵の一形式である。 「あなたのペットの名前は？」「あなたの母親の旧姓は？」「初めて見た映画のタイトルは？」などの質問が秘密の質問として挙げられる。銀行（例えばりそな銀行）、通信会社、インターネット事業者（ウェブサイト）が更なるセキュリティとして導入しているが、その効果については非難の声も多く、実装によっては逆にセキュリティホールになってしまっている場合もある。
[Wikipedia](https://ja.wikipedia.org/wiki/%E7%A7%98%E5%AF%86%E3%81%AE%E8%B3%AA%E5%95%8F)


「秘密の質問」、「セキュリティの質問」と言われるこの認証要素は大きく分けて
　1. アプリケーションが事前に準備した質問
　2. ユーザーが作成する質問
の２種類があります。順にその概要と危険性、それらに対するベストプラクティスを説明していきます。

## アプリケーションが事前に準備した質問

事前に生成された質問は、多くの場合単純化されていて安全ではない回答につながる可能性があります。
本当にその質問はエンドユーザー自身しか知り得ないのか、他者が類推し得ないのか十分に検討した上で質問を考える必要があります。
### Bad Questions
- 「{お母さん、お父さん}の旧姓は？」
    - 親戚一同がご存知
- 「誕生日は？」「出身校は？」
    - 客観的な事実
    - SNS のプロフィールに書いてある
- 「好きな色は？」「好きな野球チームは？」
    - 仲の良い人なら推測可能
- 「あなたの好きな映画は？」
    - SNS に感想を投稿していた

また、誰にも知られていない本当の秘密であっても、回答が限定される場合はブルートフォース攻撃や統計的な推測によって看破される可能性があります。

- 「好きな芸能人は？」
    - 人気芸能人の名前のリストを順に入力されたら？
- 「欲しい車は？」
    - プリウス？（統計学的に）
- 「小学生の頃に好きだった人の名前は？」
    - 佐藤さん？（統計学的に）

同様に、インターネットで容易に知り得る情報が設定される場合も危険です。

- 「[ポートピア連続殺人事件の犯人は？](https://www.google.com/search?q=%E3%83%9D%E3%83%BC%E3%83%88%E3%83%94%E3%82%A2%E9%80%A3%E7%B6%9A%E6%AE%BA%E4%BA%BA%E4%BA%8B%E4%BB%B6%E3%81%AE%E7%8A%AF%E4%BA%BA%E3%81%AF%EF%BC%9F&rlz=1C5CHFA_enJP837JP837&oq=%E3%83%9D%E3%83%BC%E3%83%88%E3%83%94%E3%82%A2%E9%80%A3%E7%B6%9A%E6%AE%BA%E4%BA%BA%E4%BA%8B%E4%BB%B6%E3%81%AE%E7%8A%AF%E4%BA%BA%E3%81%AF%EF%BC%9F&aqs=chrome..69i57.357j0j4&sourceid=chrome&ie=UTF-8)」

これらのケースはアプリケーション自身が脆弱性を誘発しているものと認識していただければ幸いです。

## ユーザーが作成する質問

ユーザーが独自に作成した質問の認証要素として認める場合、安全ではない質問が設定されることによってシステムの脆弱性を生み出す危険性があります。

### Bad Questions

- 「あなたのユーザーネームは？」
    - 攻撃者がここに到るまでに看破している可能性が高い
- 「1 + 1 =」
    - 普遍的真理
- 「私のパスワードは S3cur|ty」
    - 攻撃者歓喜

エンドユーザーに認証メカニズムを担わせるのであれば、これぐらいの危険性は認識する必要があります。
自己責任であることを許容したシステムにも責任があると思っていただけると嬉しいです。

なお、本当にプライベートな秘密をここで設定される可能性もあるので、データベースにその答えを平文で保存するのは危険です。
「マイナンバーは？」という質問を設定された場合を想像してみてください。

---

# 「秘密の質問」のベストプラクティス

上記を踏まえ、認証要素として「秘密の質問」を採用する場合のベストプラクティスを考えました。

### 回答しなければいけない質問の数を増やす

リスクを緩和できます！しかし脆弱性を脆弱性で上塗りしないようご注意ください。

### ロックアウト・メカニズムを実装する

一定の回数以上回答に失敗したらアカウントを一定期間凍結することで、ブルートフォース攻撃に対するリスクを緩和することができます。
ただし善良なユーザーが誤ってロックアウトされる不便性や、ロックアウトによるサービス不能攻撃を期待する攻撃者に注意してください（これを懸念する場合、脆弱な質問が設定されることを回避する他に「秘密の質問」へと到る導線にも注意が必要です）。

### 「秘密の質問」を認証要素として採用しない

解決です！しかし多要素認証の重要性を理解した上で、適切な認証メカニズムを構築してください。
UX を損なわない多要素認証は様々な可能性を検討する必要があります。

### 「秘密の質問」だけに依存しない

秘密の質問に回答した者を即座に認証せず、これに回答したユーザーの E-mail アドレスや SMS に認証用のリンクやパスワードリセットのためのリンクを送るのであれば、「秘密の質問」は複数ある認証要素の一つとして機能します。

---

# 「秘密の質問」における本当の脆弱性

本質的な意味での「秘密の質問」の脆弱性は、アプリケーションがこの認証に通常のプライマリ認証と同じように強い権限を与える一方で、パスワード等のプライマリ認証と同等の堅牢性を担保しないケースにあると思っています。上述のように、設問を検討した上で複数ある多要素認証の一つとして利用するのであれば堅牢性の向上に寄与すると思っています。

IPA も2015年にこの危険性を[エンドユーザーに喚起していますが](https://www.ipa.go.jp/security/txt/2015/07outline.html)、本来これらはエンドユーザーではなくアプリケーションの開発者が懸案、検討する事項だと思います。
秘密の質問以外の二要素認証を導入するのが良いんじゃないか、とも思いますが、ユーザーがスマホを持っていないことを想定するサービスや、スマホそのものを守る場合など、秘密の質問は手軽な認証要素としてこの先も生き残っていくかもしれません。

アプリケーションを実装するエンジニアにとって認証のメカニズムは設計や実装のハードルが高い分野ではありますが、その責任をエンドユーザーに託したりせず、堅牢性の高いアプリケーションを作っていきましょう。