ログインできた人が、すべてのデータを見られてよいわけではありません。自分の注文履歴を開ける人でも、URLに含まれる番号を変えて他人の注文を読めるなら問題です。
この違いを整理する言葉が、認証と認可です。認証はアカウントに結び付いた認証手段を確認する手続き、認可はある対象への操作を許可するかの判断です。この記事では仕組みの役割と、実装・運用で確認する境界を扱います。
30秒で要点
- ログインによる認証と、対象ごとの認可は別です。認可は画面を隠すだけでなく、サーバーで各要求を確認します。
- パスワード、セッション、トークンには、それぞれ保存・検証・失効の設計が必要です。方式名だけで安全性は決まりません。
- 自分の操作が成功することに加え、他人のデータ、期限切れ、権限変更後など、拒否すべき条件を確かめます。
建物の受付と、部屋ごとの入室権限
建物の受付で社員証を確認する場面が認証、会議室や書庫への入室条件を確認する場面が認可に近い例です。ただし、Webのログインが必ず実名や現実の身元を証明するとは限りません。通常は、あるアカウントの認証手段を使えることを確認しています。
表が収まらない場合は、横にスクロールできます
| 観点 | 認証 | 認可 |
|---|---|---|
| 問い | どのアカウントとして扱うか | この対象に、この操作を許可するか |
| 例 | パスワードや認証器による確認 | 自分の注文だけ閲覧できるかの確認 |
| 主な判断材料 | 登録された認証手段と検証結果 | 利用者、役割、所有関係、対象、操作など |
| 見落とし | 認証手段を紛失した後の復旧 | 別のIDに差し替えた要求や権限変更後の操作 |
「認証した後に認可する」は、個人用データへアクセスする場面の分かりやすい順序です。ただし、公開ページの閲覧のように、匿名の人に許可する操作もあります。全機能にログインを足すことが目的ではなく、公開・個人用・管理用の境界を決めます。
認可は役割と対象の両方を見る
RBACは役割に基づいて権限を付ける方法です。記事の閲覧者、編集者、公開担当などに分けると、仕事と権限を対応させやすくなります。ただし、「編集者なら全顧客の記事を編集できる」まで許すかは別の判断です。組織や所有者も確認します。
ABACは利用者、対象、環境などの属性を条件として判断する方法です。「人事担当者が担当範囲の勤怠情報を読む」など、役割だけでは表せない条件を扱えます。柔軟になる一方、条件の組み合わせと例外が増えるため、規則を説明・検証できることが必要です。
表が収まらない場合は、横にスクロールできます
| 操作例 | 許可するための条件例 | 確認したい拒否例 |
|---|---|---|
| 注文を閲覧する | 注文が本人に属する、または担当権限がある | URLの注文IDを他人のものに変更する |
| 記事を公開する | 公開権限があり、対象の組織も一致する | 編集権限だけで公開を要求する |
| 権限を付ける | 権限管理を委ねられた担当者である | 通常の利用者が管理APIを直接呼ぶ |
これは業務設計の例です。すべての管理者に全権限を与える前提にはしていません。OWASPの認可ガイドは、最小権限、既定での拒否、各要求での権限検証を勧めています。画面のボタンを消しても、サーバー側の検証を省けるわけではありません。
パスワードは長さ・照合・保存を分けて考える
パスワードには、利用者が設定する条件と、サービスが保存・検証する条件があります。複雑な記号を必須にするだけでは、使い回しや漏えいへの対応はできません。
NIST SP 800-63B-4では、単一要素のパスワードは最低15文字、多要素認証の一部として使う場合は最低8文字を許容するという条件を区別しています。少なくとも64文字の長さを受け付けることを推奨し、任意の文字種混在や定期変更を要求しません。漏えいの証拠がある場合の変更、よく使われる・漏えいした値との照合、試行制限は別に必要です。これは同文書のデジタル認証の要求・推奨であり、すべての事業への法律上の義務を述べたものではありません。適用する制度とサービスの用途を確認します。
保存するのはパスワードそのものではない
保存時には、ランダムなソルトと、計算に費用がかかるパスワード用の導出処理を使います。ソルトは同じパスワードでも保存値が同じにならないようにする値です。秘密の代用品ではなく、導出値と一緒に保存できます。
高速なSHA-256やHMACだけを使うと、盗まれた保存値に対する大量の候補照合を重くする目的を十分に果たしません。OWASPの保存ガイドはArgon2idを優先し、それが使えない場合の選択肢としてscryptを示しています。
次は、Node.jsの組み込みscryptで「新しいソルトを作る→導出値を保存する→入力を照合する」を学ぶオフライン教材です。password-demo.mjsとして保存し、対応するNode.jsでnode password-demo.mjsを実行する構成です。入力は教材用の文字列で、実在する利用者の秘密を使いません。
import { randomBytes, scrypt as scryptCallback, timingSafeEqual } from 'node:crypto';
import { promisify } from 'node:util';
const scrypt = promisify(scryptCallback);
const options = { N: 2 ** 17, r: 8, p: 1, maxmem: 256 * 1024 * 1024 };
const keyLength = 64;
async function makeRecord(password) {
const salt = randomBytes(16);
const derived = await scrypt(password, salt, keyLength, options);
return { salt, derived };
}
async function matches(password, record) {
const candidate = await scrypt(password, record.salt, keyLength, options);
return timingSafeEqual(candidate, record.derived);
}
const sample = 'offline learning sample only';
const first = await makeRecord(sample);
const second = await makeRecord(sample);
console.log('correct input:', await matches(sample, first));
console.log('wrong input:', await matches('different sample', first));
console.log('different salts:', !first.salt.equals(second.salt));
N、r、pは処理の費用を調整する値です。この例の基本的なメモリ量の目安は128 × N × rで約128MiBとなります。Node.jsのscrypt説明にあるメモリ条件を踏まえ、例では上限を256MiBにしています。これをすべての環境の推奨値として固定せず、同時要求数を含めて負荷を測ります。
この短い例には、入力制限、漏えい候補照合、試行制限、保存形式の検証、パラメータ更新、監査や復旧は含まれません。ログイン機能一式として公開せず、実サービスでは検証された認証機能と運用設計を使います。メモリの指定を増やしても、無制限の同時要求を受けてよいわけではありません。
多要素認証と復旧を一緒に設計する
多要素認証は、知っているもの、持っているもの、身体的な特徴など、異なる種類の要素を組み合わせます。パスワードを二回聞くことは多要素認証になりません。生体情報だけを挙げて「これで多要素」と判断することも避け、どの認証器と要素を組み合わせるかを確認します。
SMS、認証アプリ、セキュリティキーなどでは、脅威や利用条件が異なります。導入時には、端末紛失、機種変更、退職、復旧担当者の確認方法まで考えます。通常のログインを強くしても、復旧手順から容易になりすまされるなら、その境界が弱点になります。
セッションはログイン状態を引き継ぐ仕組み
ブラウザが毎回パスワードを送る代わりに、推測困難なセッションIDをCookieなどで送り、サーバー側で状態を確認する方法があります。Cookieは保存と送信の仕組みであり、認証方式そのものではありません。
認証手段を検証 → サーバーが新しいセッションIDを発行
ブラウザへCookieを設定 → 後の要求でCookieを送信
サーバーが有効期限・失効を確認 → 対象と操作の権限を確認
ログアウト・権限変更・期限切れ → 必要な状態を更新または失効
CookieのSecureはHTTPSでの送信、HttpOnlyはJavaScriptからの読み取りの制限、SameSiteはサイトをまたぐ送信条件に関係します。これらを付けただけで、すべてのXSSやCSRF、認可漏れが消えるわけではありません。OWASPのセッション管理ガイドに沿って、IDの更新、期限、ログアウト時の無効化も確認します。
JWT・OAuth・OIDCの役割を混ぜない
トークンは、ある状態や権限に関する情報を渡すために使われます。JWTはその表現形式の一つです。JWSのcompact形式を使う署名付きの表現では、ヘッダー、ペイロード、署名をドットで連結します。以下は構造の説明で、送信できるトークンや実行できるJSONではありません。
署名付きJWTの概念: Header.Payload.Signature
Header: 使用する署名方式など
Payload: sub(主体), iss(発行者), aud(宛先), exp(有効期限)など
Signature: 許可された方式と信頼する鍵で検証する対象
署名は暗号化と同じではありません。読めて困る情報を安易に入れず、ライブラリで発行者、宛先、有効期限、署名などの必要条件を検証します。トークンに役割が入っていても、発行後に権限を取り消した場合の扱いは別途必要です。
OAuth 2.0は、あるサービスに別のサービスの資源へアクセスする権限を委譲する仕組みです。OpenID Connect(OIDC)は、その上に認証の層を加え、IDトークンなどの扱いを定めています。OIDC Coreの仕様では、IDトークンの検証条件も示されています。
外部アカウントでログインする機能では、OAuthのアクセストークンを受け取っただけで「誰かを確認できた」と決めません。API用アクセストークンとログインのIDトークンを区別し、連携を解除した後や提供元を利用できない場合の扱いも決めます。
成功例と拒否例を一組にして確認する
小さな検証として、テスト用の利用者を二人用意し、同じ操作を自分と他人の対象に対して試す計画を作れます。実在する顧客データは使いません。
表が収まらない場合は、横にスクロールできます
| 確認する境界 | 成功する条件の例 | 拒否・失効を確かめる条件の例 |
|---|---|---|
| 認証 | 正しい登録手段でログインする | 誤った入力、期限切れの確認情報 |
| 認可 | 自分の対象へ許可された操作をする | 他人のID、別組織、不要な管理操作 |
| セッション | 有効な状態で要求する | ログアウト済み、期限切れ、権限変更後 |
| 復旧 | 定めた条件で手段を再登録する | 確認材料が不足している依頼 |
これは実施計画の出発点で、合格すればシステム全体が安全になるという認証ではありません。HTTPSによる通信の保護はSSLとTLSの基礎、導入方法の比較は現代のWeb認証へつながります。方式を選ぶ前に、誰が何をでき、どこで拒否するかを説明できる状態を目指します。