Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

✨: 認証のADRを追加 #531

Merged
merged 13 commits into from
Nov 5, 2021
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions website/docs/react-native/santoku/decisions.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,10 @@ const overviews = [
{
title: 'メッセージ管理の方針',
to: 'react-native/santoku/decisions/adr-005-message',
},
{
title: '認証方式の方針',
to: 'react-native/santoku/decisions/adr-007-auth',
}
]

Expand Down
243 changes: 243 additions & 0 deletions website/docs/react-native/santoku/decisions/adr-007-auth.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,243 @@
---
title: 認証方式の方針
---

Status: Accepted

<!--
Proposed: 提案中
Accepted: 採用
Rejected: 却下
Superseded: 廃止
-->

## 要約

- 認証手段としてCookieベースの認証を採用します。
- アプリ起動時に端末認証を要求することで、モバイル端末の紛失や盗難リスクに対応します。
- 自動サインアップや自動ログインにより、アプリの利便性を向上させます。

## コンテキスト

アプリケーションを安全かつ利便的に使用するためには、ユーザが本人その人であることを確認する必要があります。
認証とは、ユーザがその人自身であることを確認する手段です。
通常はログイン機能として提供されます。

認証は、利用者が提示する認証要素を確認することで実現します。
認証要素には次のものがあります。

- 知識情報。その人自身しか知らない情報。「パスワード」「PINコード」や「秘密の質問」など。
- 所持情報。その人自身が保有する情報。「携帯電話」「ハードウェアトークン」「クライアント証明書」など。
- 生体情報。その人自身の特徴。「指紋」「静脈」「声紋」や「顔の特徴」など。

一般的には、ID・パスワードを用いた認証方式を採用するサービスが多いです。
しかし、昨今の高まるセキュリティリスクに対応するため、安全性が求められるサービスでは多要素認証を採用するケースも増えています。

ここでは、サンプルアプリケーションの認証方式について検討します。
目指す認証方式は次の通りです。

- アプリを安全かつ利便的に使用できること
- 他のプロジェクトでも参考にしやすいこと

サンプルアプリケーションの存在趣旨を踏まえ、他のプロジェクトでの参考のし易さを第一とします。
一般的に認証に関連して必要となるアカウント機能(アカウントのライフサイクルにまつわる機能群)は対象外とし、サインアップ・ログイン・ログアウトといった認証機能にのみ焦点を当てます。
また、プロジェクトによって異なる箇所の多い認証方式は検討対象外とします。

次の観点で認証方式について議論・調査を進めていきます。

- 認証手段
- サインアップ
- ログイン
- ログアウト
- 想定される脅威(攻撃手法)とその対応
- 想定される課題とその対応

## 議論

### 認証手段

#### OIDC vs Cookieベースの認証

OIDC(OpenID Connect)は、OAuth 2.0プロトコルを使用して構築された認証方式です。
Cookieベースの認証とは、ID・パスワードを用いて認証し、CookieでセッションIDを受け取る代表的な認証方式です。

認証手段の検討にあたり、真っ先に検討の場に上がるのはOIDC(OpenID Connect)です。
OIDCは標準化された仕様を持つ優れた認証方式ですが、次の理由により検討対象外としました。

- OIDCを用いる場合、認証サーバ(IdP)に外部サービス(Firebase AuthenticationやAmazon Cognitoなど)を用いる場合が多い。外部サービスから開発ガイドやSDKが提供されており、実装する場合はそちらを参考にできる。
- (代表的な)Cookieベースの認証機能を備えた既存資産の流用を考えた場合、OIDCへの移行はコストがかかる。

よって、他のプロジェクトでの参考のし易さを第一とし、サンプルアプリケーションではCookieベースの認証を採用します。

:::info
React Nativeでは、Cookieはネイティブ側で管理されます。
そのため、アプリではCookieを管理しません。
:::

#### 端末認証

モバイルアプリの場合、Webアプリケーションとは異なり、端末の紛失や盗難といったセキュリティリスクがあります。
そうしたリスクへの対応として端末認証があります。
端末認証は、PINコード(またはパスコード)、指紋や顔の特徴などを用いて、ユーザが端末の所持者であることを認証します。
これにより、所持者以外が不正に端末を利用することを防げます。

このアプリでも、アプリ起動時に端末認証を要求することで、上記リスクに対応します。

### サインアップ

#### 自動サインアップ

アプリへのサインアップ要求は、ユーザの心理的抵抗が大きいです。
「アカウント情報の登録が面倒」という理由からくるユーザの離脱は、大きな機会損失に繋がります。

そこで、このアプリでは自動サインアップ機能を提供します。
ユーザはサインアップなしにアプリを利用できます。
自動サインアップは次の流れで行います。

1. アカウントIDとパスワードをアプリが自動作成
2. 自動生成したアカウントIDとパスワードでサインアップ
3. ログイン資格情報を端末内の安全な場所に保存

ログイン資格情報は、次回ログイン時に必要となる情報です。
ログイン資格情報の詳細については、[ログイン](adr-007-auth#ログイン)で検討します。

:::info
端末内の安全な場所の詳細は、[ログイン資格情報の管理](/reference/auth/manage-credentials)を参照してください。
:::

:::info
パスワードは知識情報(その人自身しか知らない情報)に当たるので、アプリケーションが自動生成するのはおかしいのではという疑問が生じます。
このアプリでは、自動生成されたパスワード(から得たログイン資格情報)を知識情報ではなく所持情報(その人自身が保有する情報)として扱います。
他の例でいうと、パスワード管理サービス(1Passwordのような)を利用することで、ユーザはパスワードを記憶しなくて済みます。
これは実質的に、パスワードを所持情報として扱っていると言えるでしょう。
:::

### ログイン

#### 自動ログイン

頻繁なログイン操作の要求は、ユーザの利便性低下に繋がります。
またこういった要求が、単純な(安全性の低い)パスワードの利用やパスワードの使いまわしにも繋がります。
そもそもこのアプリの場合、ユーザは自身の(自動生成された)パスワードを知らないので、パスワードを入力できません。

そこで、このアプリでは自動ログイン機能を提供します。
アプリ起動時に、端末内に保存されたログイン資格情報を用いて(前回ログインしたアカウントで)自動でログインします。

#### ログイン資格情報

ログイン資格情報の仕様について、次の案を検討しました。

- アカウントID + パスワード
- 認証トークン

ログイン資格情報は、上記いずれの案を用いたとしても、通信経路上および端末内での安全性が保たれています。

「アカウントID + パスワード」をそのままログイン資格情報として扱う場合、既存資産の流用(主にログイン機能)という点で有利です。
しかし、将来的に次の点を考慮した場合、認証トークンのほうが有利です。

- ログイン資格情報に有効期限を持たせたい場合
- パスワードを別の用途(重要操作実行に必要な入力など)で使用したい場合(この場合、ユーザはパスワードを知識情報として保持する必要があります)

今回はアプリの特性、および既存資産の流用のし易さを考慮し、ログイン資格情報に「アカウントID + パスワード」を採用します。

#### 認証状態の保持

セッションの有効期限が切れた場合、アプリが自動で再度ログインしてセッションを更新します。
詳細は、[【補足】有効期限が切れたログイン資格情報の更新方法 - Cookieベースの認証](/react-native/santoku/decisions/adr-003-http-api-error-handling#cookieベースの認証)を参照してください。

### ログアウト

ログアウト後も端末内にログイン資格情報を保持します。
ログアウトする際、アカウントIDをユーザに提示します。
ユーザはそのアカウントIDを用いることで、同じアカウントで再度ログインできます。

### 想定される脅威(攻撃手法)とその対応

#### ログイン機能に対する攻撃

ログイン機能に対する攻撃として、SQLインジェクション攻撃があります。
この攻撃は、SQLインジェクション脆弱性を利用して、認証機能を迂回したり、パスワードを盗み出します。
この脆弱性への対策はバックエンド側となる為、アプリの対応範囲外です。

#### パスワード認証に対する攻撃

パスワード認証に対する攻撃として、次のようなものがあります。

- 辞書攻撃
- ジョーアカウント探索
- ブルートフォース攻撃(総当たり攻撃)
- パスワードスプレー攻撃
- リバースブルートフォース攻撃
- パスワードリスト攻撃

パスワードを自動生成することで結果的に防げている攻撃もありますが、この攻撃への対策はバックエンド側となる為、アプリの対応範囲外です。

#### ソーシャルエンジニアリング

ソーシャルエンジニアリングは、ユーザをだましてパスワードを聞き取る攻撃手法です。
この攻撃はアプリケーションで対策するものではありません。一般的に教育での対応となります。
ただし、このアプリのユーザは自身のパスワードを知らないので、結果的に攻撃を防げています。

#### フィッシング

本物そっくりの画面を備えた偽サイトを仕立てて、利用者の情報を入手する攻撃手法です。
基本的にユーザの注意により防ぐ攻撃です。
一般的にWebアプリケーションを標的とした攻撃であることと、このアプリのユーザはパスワードを手入力しないことから、脅威レベルとしては低いものとなります。

#### クロスサイト・リクエストフォージェリ(CSRF)

CSRFは、Cookieの特性を利用した攻撃手法です。
アプリケーションにCSRF脆弱性が存在すると、ログイン中のユーザは意図せず「重要な処理」を実行させられる場合があります。
一般的にWebアプリケーションを標的とした攻撃であるため、モバイルアプリとしての脅威レベルは低いものとなります。ただし、WebViewやIn-App Browserを利用している場合は脅威となりえます。
このアプリでは、バックエンドから受け取ったCSRFトークンをHTTP通信時にHTTPヘッダへ含めることで、CSRF攻撃に対応します。

#### セッションハイジャック

セッションハイジャック手法としては次のようなものがあります。

- セッションIDの推測
- セッションIDの盗み出し
- セッションIDの強制

この攻撃への対策はバックエンド側となる為、アプリの対応範囲外です。

#### モバイル端末の紛失や盗難

このアプリでは、次の方式でモバイル端末の紛失や盗難リスクに対応します。

- アプリ起動時の端末認証
- 端末内の安全な場所に秘密情報(ログイン資格情報)を保存

モバイル端末の紛失や盗難リスクは、このアプリのみに留まりません。
よって、ユーザが端末のロック機能を有効にするなど、端末レベルでの紛失・盗難対策をしていることを想定しています。

#### 不正サインアップ

サービスの妨害を目的として、外部からの自動操作により不正なサインアップが大量に行われる場合があります。
このような攻撃への対処法として、WAFの導入があります。
また、ユーザのメールアドレスを利用した不正防止やCAPTCHAという仕組みでの対策方法も考えられます。
いずれにしても、アプリケーションのセキュリティ特性により対応レベルが異なりますので、今回は対応範囲外とします。

### 想定される課題とその対応

#### アプリの移行

端末機種の切替などの理由によりアプリを移行する場合、その機能がこのアプリにはありません。
アプリの移行には様々な方法が考えられますが、今回の開発範囲外とします。

#### ログイン資格情報が盗まれた場合の対応

ログイン資格情報が盗まれた場合の対応は、アカウント機能による運用対処とします。
システム管理者によるアカウント停止などを想定していますが、いずれにしても今回の検討対象外とします。

## 決定

認証手段の検討にあたり、OIDCとCookieベースの認証を検討しました。
OIDCは優れた認証方式ですが、他のプロジェクトでの参考のし易さを第一としてCookieベースの認証を採用します。

モバイルアプリの場合、端末の紛失や盗難といったセキュリティリスクがあります。
そこで、アプリ起動時に端末認証を要求することで、モバイル端末の紛失や盗難リスクに対応します。

セキュリティとユーザの利便性は相反しやすい品質特性です。
このアプリではユーザの利便性を優先し、自動サインアップや自動ログインを採用します。
サインアップ時に作成した「アカウントID + パスワード」を、ログイン資格情報として端末内の安全な場所に保存することで、自動ログインを実現します。
1 change: 1 addition & 0 deletions website/docs/sidebars.js
Original file line number Diff line number Diff line change
Expand Up @@ -388,6 +388,7 @@ module.exports = {
'react-native/santoku/decisions/adr-003-http-api-error-handling',
'react-native/santoku/decisions/adr-004-deep-link',
'react-native/santoku/decisions/adr-005-message',
'react-native/santoku/decisions/adr-007-auth',
],
},
],
Expand Down