アクセス制御や認可制御の欠落について調べたメモ

# 参考情報
[link-1]:https://www.ipa.go.jp/security/vuln/websecurity.html
[link-2]:https://gihyo.jp/magazine/SD/archive/2020/202011
[link-3]:https://www.sbcr.jp/product/4797361193/
[link-4]:https://www.sbcr.jp/product/4797393163/

「1.11 アクセス制御や認可制御の欠落」に記載があります。
[安全なウェブサイトの作り方：IPA 独立行政法人 情報処理推進機構][link-1]

「今さら聞けない認証・認可」特集が認証認可について知るのにとても役立ちました。
とてもおすすめです。
[Software Design 2020年11月号][link-2]

「5.1 認証」「5.2 アカウント管理」「5.3 認可」あたりに記載があります。
私は第1版しか持っていないのでそちらを参照しました。
[体系的に学ぶ 安全なWebアプリケーションの作り方][link-3]
[体系的に学ぶ 安全なWebアプリケーションの作り方 第2版][link-4]

以下、上記の参考情報＋αをまとめたものです。

# 用語
- 識別 Identification
    - 利用者のIDが、存在する一意のユーザーであると確認すること
- 認証 Authentication
    - 利用者が、本当にその人であると確認すること
- 認可 Authorization
    - 利用者に対して権限を割り当てること(なにをどこまでやってもいいか)

# アクセス制御、認証制御の欠落

下記のような、そもそも認証がなされていないと言える状態のことです。

（例）

- 周知の情報だけで認証できてしまう
    - メールアドレスだけ
    - 受験番号＋誕生日もここに含まれると思います

## 不正ログインを防ぐ
認証機構はあっても、SQLインジェクションなどの他の脆弱性があるために、攻撃者がログインできてしまったり、パスワードを入手され不正にログインしてしまうこともありえます。

### ログイン情報の推測を防ぐ
推測可能なIDとパスワードを利用している場合、不正にログインされてしまう可能性があります。

**1) 推測されにくいIDを使う**
SNSのようにオープンになるアカウントIDは、推測されやすいIDです。
メールアドレスも他で使っている場合は、他者に知られているものなので、推測しやすいIDといえるのではないでしょうか。

サービスによっては、メールアドレスで登録後、別のログインIDと表示名をそれぞれ設定できることもあります。
この場合は、ログインIDは自分だけが知っている情報となるので、安全性が高まります。
ログや管理画面でも、不要であればログインIDも出さない方が、漏れる可能性が減ってよさそうです。

**2) 推測されにくいパスワードを使う**
システム的に制限したり、利用者が気を付けることになります。

パスワードに使える文字種や長さを規定したり、IDや誕生日などの他の情報と一致するような文字列を排除するなどすることでも、一定の効果があります。
IPAもパスワード強化キャンペーンしてましたね…[^1]

安全なパスワードについては、一般向けだとここがまとまっているのかなと思います。
[チョコっとプラスパスワード｜IPA 独立行政法人 情報処理推進機構](https://www.ipa.go.jp/chocotto/pw.html)

ありがちなパスワードを避けるのも有効です。
[List of the most common passwords - Wikipedia](https://en.wikipedia.org/wiki/List_of_the_most_common_passwords)

**3) 推測を試されないようにする**
アカウントロック機構を備えることで一部対処できます。

また、ログインに失敗したときのメッセージを何が間違っていたのか特定をされにくくすることも有効です。

- 良くない例
    - ログインIDは8桁です
    - パスワードの長さが足りません
- 良い例
    - ログインIDまたはパスワードが間違っています

※参考
[IPA ISEC　セキュア・プログラミング講座：C/C++言語編　第7章 データ漏えい対策：親切すぎるエラーメッセージの回避](https://www.ipa.go.jp/security/awareness/vendor/programmingv2/contents/c605.html)

### 多段階認証と多要素認証で認証を強化する
[link-2] の特集がまとまっています。

多要素認証とは、下記のうち複数を使って認証を行うことです。
2回認証を行っていても、パスワード認証＋秘密の質問のように記憶によるものだけであれば一要素認証です。

- Something you know: パスワードなど記憶によるもの
- Something you have: SMSによるワンタイムパスワードなど所持しているもの
- Something you are: 指紋認証など身体属性

ログインでよく見かける「ログインID＋パスワード」の認証は、一段階一要素認証となります。
SSH接続を鍵ファイル＋パスワードで認証していれば、Something you have(鍵ファイル)とSomething you know(パスワード)の二段階二要素認証となります。

認証ではないですが、アカウント作成でときどき見かける「メールアドレス」→「ワンタイムパスワード発行」でパスワード設定するフローは、Something you have(メールアドレス)とSomething you know(パスワード)の二要素ということでしょうか？

## そもそも

認証処理は自前で作るのは結構大変です。パスワードなどの情報を保持することにも気を使います。
なので、SSO認証など外部機構を使うのも手です。
（もちろん利用するサービスのセキュリティ面の確認は必要）

# 認可制御の欠落

下記のような状態のことです。

- メニューの制御を表示/非表示だけで行っているため、URLを知っていればその機能を使えてしまう
- クエリパラメータを使って表示内容を変更するので、IDが分かれば他のユーザーの情報も参照できてしまう

認証情報をもとに、「機能」「操作」「情報」のそれぞれについてなにを認可するかを管理する必要があります。
AWSやGCPではIAM(Identity and Access Management)で管理していますね。

## 機能の認可
ユーザーごとに機能を割り当てる場合もあります。
ロールごとに機能を割り当て、ユーザーにはロールを割り当てるパターンもよく見かけます。

（例）

- ロール
    - 一般 = { 自分のプロフィール, 自分のショッピングカート }
    - ショップメンバ = { 自分のショップの商品, 自分のショップのお知らせ }
    - ショップ管理者 = { 自分のショップのアカウント }
- アカウント
    - Aさん = { 一般 }
    - Bさん = { ショップメンバ } -> アカウント機能は使えない
    - Cさん = { ショップメンバ, ショップ管理者 }

## 操作の認可
同じ機能でも、参照はできるが作成や更新はできなかったり、一覧検索はできるがCSVダウンロードはできないなど、細かい制御が必要になることもあります。
これもロールで設定しておくと良いです。

APIであれば、パス階層でロールを変えると、操作の制御もやりやすいと思います。
昔、MPA(Multi-page application)で作っていたときは、ボタンの表示/非表示を分けたり、更新と参照を別機能として切り分けたり、面倒なことをしていた記憶があります。

## 情報の認可
認可された機能の中でも、参照できる範囲、更新できる範囲が異なることがあると思います。

（例）

- 自分の所属する組織内の情報だけにアクセスできる
- 一般ユーザーは自分の情報のみ、管理者はすべての情報にアクセスできる

API設計の話になりますが、[「Web API: The Good Parts」](https://www.oreilly.co.jp/books/9784873116860/)のコラム『自分の情報へのエイリアス』に`ユーザーIDを指定するのではなく認証情報をもとにユーザー本人の情報を取得する処理にすることで間違って他人の情報を取得するようなバグを防ぐことができる`ということが書いてあります。
このような設計をすることで、上記のような問題はある程度防ぐことができるはずです。

# 感想
[Software Design 2020年11月号][link-2] がまとまっていてとても良かったです。
一口に「ログイン」や「ロール」くらいでしか認識していなかったのですが、識別・認証・認可という段階を踏み、それぞれに気にすべきことがあるのだと分かりました。

[^1]: コラみたいなポスターで話題になった
 [パスワード－もっと強くキミを守りたい－ ： IPA情報処理推進機構](https://www.ipa.go.jp/security/keihatsu/munekyun-pw/)