Googleが提案するユーザアカウント、認証、パスワード管理のベストプラクティス 13選

# Googleが提案するユーザアカウント、認証、パスワード管理のベストプラクティス 13選

2021/5/7 の記事
[原文](https://cloud.google.com/blog/products/identity-security/account-authentication-and-password-management-best-practices)

つたない日本語訳ですが、自動翻訳より読みやすいかなと思うのでよければ参考にしてみてください。

## 1. パスワードをハッシュ化する

  アカウント管理で最も大事にすべきことはユーザ情報を慎重に安全に取り扱うことで、
ユーザの情報は神聖なものとして適切に扱わなければならない。

  どんな場合でもパスワードをプレーンテキストで保存せず、Argon2idやScryptといった
強力なハッシュ関数によって暗号化された状態で保存すべき。
MD5やSHA1などのハッシュ関数はもはや非推奨。また、独自のハッシュアルゴリズムを開発
している場合、必ず復号化されないようなものにしなければならない。
pepperを利用してデータベースに保存しないようにするのもよい。
可能であれば複数回ハッシュ化することもお勧め。

  「まぁこんなもんでいいか」といったレベルの実装をしたとして、「もし、データベースが
外部にさらされたとしたら、ユーザは安全なのか？ウチのサービスやほかのサービスを危険に
さらすことにならないか？」とか、「データベースがリークしたとき、影響を抑えるためには
どんなことをすればいいだろうか？」とかを考えてみて。

  言い方を変えると、ユーザがあたなのシステムにパスワードを登録した直後を除いて、
常に外部から平文で保存されたユーザパスワードを提供しているようなパスワード管理の場合、
あなたの実装には問題がある。

  似たようなパスワード変更の検出を必要とする場合、禁止にしたい文字列のハッシュを保存しておく。
これは新規ユーザ作成時や既存アカウントがログインする際に有効である。ユーザがパスワードを生成
したとき、似た文字列を同時に生成して、過去のパスワードと比較するようにする。
実際のパスワードと同じセキュリティレベルで保存するようにする。

## 2. サードパーティIDプロバイダーを利用する

  Google,Facebook,Twitterといったサードパーティログイン機能を利用するべき。
これらのプロバイダーを利用することで信頼性のあるユーザ認証サービスを利用できる。

  Identity Platformを利用すれば、既存の内部認証機能とサードパーティ製の外部認証機能を同居させることもできる。
認証はよりシンプルになるし、攻撃されることも少なくなる上、SDKの利用も充実している。
これらのメリットは後のリストでも出てくる。

## 3. ユーザのアイデンティティとユーザアカウントは別物と考える

  ユーザというものはEmailアドレスではないし、電話番号でもない。
もちろんユーザ名に登録している名前でもない。
ユーザ名やemailなどの認証によく使われる要素というものは、
アカウント内の個人情報やコンテンツに変更を加えることなく、自由に決められる。
  ユーザというものは、ユニークな個人情報とあなたのサービス内での情報の集大成であって、
認証方法の集合ではない。
  ユーザ管理がよくできたサービスでは、1対1の組み合わせというものは少なくして、
ユーザ情報内のあらゆる要素を多角的に照合していくシステムを持っている。

  ユーザアカウントと認証情報を分離することを意識すると、
サードパーティの認証プロバイダの導入や、ユーザ名の変更の許可、
複数の個人情報の一つのアカウントへの紐づけを非常に簡素化できる。
  実際、すべてを1つのレコードにまとめるよりも、すべてのユーザに
抽象的な内部グローバルIDを付与し、そのユーザのプロファイルと
認証データセットを関連付けたほうが便利。

## 4. 複数の情報を一つのユーザアカウントと結びつけられるようにする

  最初はユーザ名とパスワードで登録したとしても、そのことを忘れて
Googleログインを利用してた順登録にしてしまうユーザというのは結構いる。
他にも、同じサービスに複数のメールアドレスで登録してしまうユーザも結構いる。
  ユーザのアイデンティティと認証を適切に分けて考えると、
複数の認証方法と一つのユーザアカウントを紐づけるのは簡単になる。

  ユーザが新規登録をする際、すでにほかのサードパーティ認証で
ログインを実施してないか知らせてあげる必要がある。
  これはEmail、電話番号、ユーザ名をユーザに聞くだけで解決する。
入力してもらった情報と登録された情報を照会して、すでに登録済みであれば、
登録時のプロバイダーを利用するようにさせればいい。

## 5. 長くて複雑なパスワードを禁止にしない

  強力なハッシュによる暗号化を利用すれば、どんな長さのパスワードも
固定長の暗号として出力されて保存されるので、
ユーザは好きにパスワードを決めることができる。
  もし、パスワードの長さを制限しなければならないとすれば、
それはメモリ利用率だとか、サーバへのPOSTデータサイズ制限であることが多い。
例えば何百KBとか1MBを超えるようなえぐい長さのパスワードを入力されたら
さすがにたまったもんじゃない。
  入力フォームのmax_lengthはしっかりと設定しておいたほうがいい。
個人情報流出防止や、メモリ解放のためにできるだけ早い段階で入力データをハッシュ化するように
バックエンドの設定を行うことで、攻撃を受けにくくなる。

  ハッシュ化されたパスワードがシンプルなASCII文字で構成するようにする。
もしそうでない場合は、Base64を利用することで簡単にハッシュ化できる。
このことを頭に入れ、パスワードに利用する文字はどんな文字であってもユーザにゆだねるべきである。
Klingonや絵文字、AAをパスワードに利用するような輩が現れるかもしれないが、
技術的にそいつらを止める必要性は全くない。
どんな文字が来てもクロスプラットフォームできるようにUnicodeで標準化してあげればよい。

  意味不明な文字列をパスワードにしようとしている人がいるかもしれないが、
それはもしかしたらパスワードマネージャを利用して自動生成したものかもしれないし、
実はパスワードのベストプラクティスに則っている場合もある。
  入力フィールドに入力できる文字列はすべてパスワードとして受け入れられるようにしなければならない。  

## 6. ユーザネームの決定関して意味の無いルールをユーザに課さない

  ユーザ名は2~3文字以上にする、隠し文字(環境依存文字？)を禁止する、ユーザ名の最初と最後の空白を禁止する
これらは最低限必須のルールです。
しかしながら、ユーザ名に8文字以上を要求したり、7BitASCII文字以外の文字を禁止したりするサイトは結構多い。

  ユーザ名に厳しめの制限を設けると、開発者は楽できることは多いけど、
その代わりUXは下がって、最悪の場合ユーザはサービスを使ってくれなくなる。

  ベストプラクティスとしては、ユーザ名を自動で割り当てるというアプローチがある。
もしこのアプローチを利用するとして、ユーザがユーザ名を利用したり、
変更したりする必要がある場合、ユーザフレンドリーなユーザ名を割り当てる必要がある。
  英数字でユーザ名生成する場合は、"Il1O0"みたいな一見似たような文字が並ばないように
しなければならない。また、生成されたユーザ名文字列の中に、不適切な文字列とかが入ってないかとかも
辞書スキャンとか使って確認したほうがいい。これはパスワードの自動生成でも同じことがいえる。

## 7. ユーザの情報を検証する

  ユーザに情報を登録してもらったら、すぐにでもその登録を検証すべき。
認証コードとかリンクをユーザのEmailや電話番号に送り付ける。
そうしないと、ユーザがタイプミスをしてた場合にありもしないユーザでログインしようとして
ログインできずに無駄な時間が過ぎて行ってしまう。
そうやってできたアカウントはパスワードリセットとか再作成みたいな手動の操作が必要になってしまう。
最悪の場合、第三者に登録情報を送ってしまうことになり、アカウント情報を操作されてしまうかもしれない。

## 8. ユーザに自身のユーザ名の変更を許可する

  レガシーシステムではユーザ名の変更不可であるものが当たり前である。
再利用目的でユーザ名を自動で解放させないようにすることはとてもいいことだが、
長い目で見ると、ユーザが別の名前を思いついたとしても、新しいアカウントを作ろうとは思わなくなってしまう。

  エイリアスに従わせることでユーザ名の変更を許可したり、プライマリエイリアスを
選ばせてあげるのがいいでしょう。その際、必要であればビジネスルールを機能に適用することもできます。
例えば、ユーザ名の変更回数を制限したり、プライマリユーザネームを見せないようにするような機能を
実装している企業もあります。
  EmailプロバイダーはEmailアドレスの再発行できない場合が多いが、旧Emailアドレスにエイリアスをつけて
新しいEmailアドレスとすることはできる場合が多い。近年のEmailプロバイダーでは、さらに
自由なドメインをユーザに提供している場合もある。

  もしあなたがレガシーシステムの担当であれば、このベストプラクティスへの移行はかなり難しいとおもわれる。
Googleのような企業でさえ、このアーキテクチャを実装するのには思ったよりも苦労したものだ。
新しいシステムのデザインをする場合、ユーザのアイデンティティとユーザアカウントを分けるという概念、
そして複数のアイデンティティを一つのアカウントに結びつけるようにするという概念をしっかりと考えれば、
移行は少しマシになるかもしれない。既存システムであれ新規開発システムであれ、ユーザに自身の情報を許可する
こと念頭に置きながら、企業の規則に則ったシステムを作成するように努力してほしい。

## 9. ユーザに自身のアカウントの削除を許可する

  驚くことにほとんどのサービスは、個人情報が紐づいたアカウントを自力で削除できない。
サービスの特徴によっては、ユーザの投稿やアップロードした画像や写真などが削除できないまま
になっているかもしれない。ユーザに自身のアカウントの削除を許可することのメリットは大きい。
このメリットはUXやセキュリティ、コンプライアンス順守のバランスを必要とする。
  ほとんどすべてではないにせよ、多くのシステムはPCIやGDPRなどのユーザデータ保存に関する
ガイドラインを遵守している必要がある。コンプライアンス順守やデータの流出回避のために
よく使われる方法は、ユーザの削除をスケジュールして、しばらくしたら自動で削除されるようにする方法だ。

  ユーザのアカウントを直ちに削除しなければならないように要求されている場合もあると思うが、
その場合は、クローズドなユーザで会ったとしてもアカウントのデータ流出の危険性が高いことを考慮すべきである。

## 10. セッションの長さを明確に決める

  セキュリティや認証の観点でよく議論されるのがセッションタイムである。
Googleではユーザの認証の保証にとても力を入れており、特定のイベントや行動に基づいて
ダブルチェックも行う予定だ。ユーザはセキュリティをより強化することができる。

  さほど重要でない分析用途で無期限にセッションタイムを設定しているかもしれないが、
本来セッションタイムには、パスワードの要求、2段階認証、その他の認証の後で
それぞれ閾値を設定するべきである。

  再認証するまでに、ユーザがどれくらい非アクティブであるか考えよう。
パスワードリセットしたときのことを考えて、すべてのアクティブセッション上でユーザのアイデンティティを検証しよう。
ユーザがプロフィールの変更や機密情報に対する捜査の際には、認証や二段階認証を促そう。
短期間でユーザの現在地が極度に変わったりしていたら再認証させよう。
複数のデバイスや、複数の場所からの同時アクセスに関してログを拒否することに意味をなすかどうかを考えよう。

  サービスでユーザのセッションを切り、再認証が必要となる場合、ユーザの情報の入力を補助する機能を盛り込むように工夫しよう。
ログインする際、埋めないといけない入力欄を探してフォームを埋めていく作業はめちゃくちゃイライラするので。

## 11. 2段階認証(多段階認証)を利用する

  2段階認証をシステムに利用する場合、ユーザのアカウントが乗っ取られたときのことを考える必要がある。
ワンタイムパスワードやEmail認証コード、マジックリンクなどは利用者になじみ深く、安全だ。
NISTによると、SMSによる2段階認証はいくつか脆弱性が見つかっているため非推奨となっている。
小さめのシステムではSMS認証を利用することが最も安全な方法でもある。

  もし利用できるならハードウェア2段階認証のTitanSecurityKeyを使ってみてください。
ワンタイムパスワードも利用できない場合、Emailによる認証や、サードパーティプロバイダーによる
2段階認証は、簡単にセキュリティを強化できる。ユーザアカウントは最も弱い2段階認証や
アカウントリカバリ方法と同じレベルの安全性となってしまうことを念頭に置く。

## 12. 大文字と小文字の区別をつけないようにする

  ユーザは設定したusernameの大文字小文字を正確に覚えていないことが多い。
usernameは大文字小文字を完全に区別しないようにするべきだ。DBに保存する前にusernameやEmailをすべて
小文字に変換することは簡単だ。その際、地域の特定と、変換にUnicodeNormalizationを採用することを忘れないように。

  ユーザがシステムにアクセスしてくるデバイスは今やスマートフォンがほとんどである。
スマートフォンのほとんどは入力欄に対して、自動補完や自動入力の機能を備えているため、
UIでこれらの機能を阻害するような設計士しないようにすることが望ましい。
よく考えずに自動入力されたusernameやemailを適切に扱えるほど壮健なシステムにする必要がある。

## 13. 安全な認証システムを作成する

  IdentityPlatformなどのサービスを利用すると、セキュリティに関する心配事はかなり減るが、
脅威からサービスを守るために日々開発を続けていく必要がある。
具体的には、パスワードの再取得ではなくパスワードの再発行する機能、
アカウントのアクティビティログの詳細表示機能、credential stuffを防ぐためのログイン頻度の規制機能、
複数回のログイン失敗したユーザをはじくようにする機能、長期間ログインしていなかったユーザが
別のデバイスを用いてログインしてきたときに2段階認証を必要とする機能などである。
認証機能のセキュリティに関する部分は非常に多いので、以下の文献も参考にされたい。

## あわせて読みたい

- [システムデザイナーのためのモダンパスワードセキュリティ](https://cloud.google.com/solutions/modern-password-security-for-system-designers.pdf)
- [ユーザのためのモダンパスワードセキュリティ](https://cloud.google.com/solutions/modern-password-security-for-users.pdf)
- [NIST_800-063B](https://pages.nist.gov/800-63-3/sp800-63b.html)
- [パスワード保存に関するチートシート - OWASP](https://cheatsheetseries.owasp.org/cheatsheets/Password_Storage_Cheat_Sheet.html)
- [Identity Platform - GoogleCloud](https://cloud.google.com/identity-platform)
- [FirebaseAuthentication - GoogleCloud](https://firebase.google.com/docs/auth/)