MD5やSHA-256などの汎用ハッシュ関数は、「データの改ざん検知」や「ファイルチェックサム」を目的として作られているため、「とにかく高速に計算処理できること」を重視して設計されています。
しかし、パスワード保存においては、この「高速すぎること」が最大の致命傷となります。
1. MD5やSHA-256が不適切な理由
① 高速すぎて「超高速総当たり」を許してしまう
現代のGPU(グラフィックボード)や専用ハードウェア(ASIC)を使うと、SHA-256であれば1秒間に数億〜数百億回以上のハッシュ計算が可能です。
攻撃者にデータベースを盗まれた場合、ソルト(Salt)を付与していたとしても、オフライン環境でGPUをぶん回すことで、ブルートフォースや辞書攻撃により短時間で元のパスワードを解読されてしまいます。
② MD5は構造的な欠陥(衝突耐性の欠如)がある
MD5は計算速度の問題以前に、暗号学的な脆弱性が発見されており、「異なるデータから同じハッシュ値が生成される現象(衝突)」を意図的に起こせます。セキュリティ用途での使用は完全に禁忌(非推奨)とされています。
2. パスワード保存専用アルゴリズム(Argon2 / bcrypt 等)の仕組み
パスワード保存に適したアルゴリズムは、「あえて計算を重く(遅く)する」という設計思想(ストレッチング)で作られています。
攻撃者が1回のハッシュ値を計算するのに 0.1秒(100ミリ秒) かかるように設定しておけば、正規のログイン処理では1回だけなので人間には気づかない遅延ですが、1億回の総当たりを試す攻撃者には約115日もの時間が強制され、実質的に攻撃を無効化できます。
3. 推奨される主なパスワードハッシュ関数
① Argon2(現在最も推奨される標準)
-
特徴: 2015年の「Password Hashing Competition (PHC)」で優勝した、現在の国際的な業界標準・最推奨アルゴリズムです。
-
強み:
-
CPU時間だけでなく、メモリ使用量(Memory-hard)や並列処理数もパラメータとして調整可能。
-
GPUや専用チップ(ASIC)による「大量の並列計算」を防ぐため、わざと大量のメモリ領域を要求する設計になっています(GPUは並列計算が得意ですが、各コアごとの独立した大容量メモリ操作は苦手)。
-
-
用途: 新しく開発するシステムの第一選択肢。
② bcrypt(長年の信頼と実績)
-
特徴: 1999年に発表された、Blowfish暗号をベースにしたパスワードハッシュ関数。
-
強み:
-
「Cost factor(ストレッチング回数)」を設定でき、ハードウェアの進化に合わせて計算コストを後から引き上げられる。
-
長年の運用実績があり、実装ライブラリがほぼすべての言語で成熟している。
-
-
注意点: 入力できるパスワードの長さに上限(72バイト)があるため、事前処理が必要な場合があります。
③ PBKDF2(標準規格・互換性重視)
-
特徴: NIST(米国標準技術研究所)などでも標準化されている歴史ある方式。
-
強み: 鍵導出関数として標準化されているため、エンタープライズ製品や古いシステムとの互換性・コンプライアンス要件を満たしやすい。
-
注意点: 主に「計算回数」のみで遅くする仕組みのため、メモリ消費を強制するArgon2やscryptに比べると、GPUによる並列解読攻撃に弱い側面があります。
アルゴリズム比較まとめ
| アルゴリズム | 計算遅延 | メモリ負荷 (GPU対策) | 現在の評価 | 主な用途 |
| MD5 | 極めて高速(危険) | なし | ❌ 絶対禁止 | (過去の遺物) |
| SHA-256 | 高速(危険) | なし | ❌ 非推奨 | 改ざん検知・デジタル署名用 |
| PBKDF2 | 調整可能 | なし | ⚠️ 条件付き可 | 互換性重視のシステム |
| bcrypt | 調整可能 | わずか | 🟢 推奨 | 汎用Webアプリケーション |
| Argon2 | 調整可能 | 調整可能 (強力) | 🟢 最推奨 | 新規開発システム全般 |
PythonやNode.jsなどの具体例を交えて、Argon2やbcryptを使って安全にパスワードをハッシュ化・検証する実装コード例を教えてください。
PythonとNode.jsにおいて、標準的なライブラリを用いて bcrypt および Argon2 でパスワードをハッシュ化・検証する実装例です。
いずれのライブラリも、ソルトの自動生成・埋め込みを行ってくれるため、開発者が手動でソルトを管理・結合する必要はありません。
1. Python での実装例
① bcrypt (bcrypt ライブラリ)
事前にインストール: pip install bcrypt
import bcrypt
# --- ハッシュ化(ユーザー登録時) ---
raw_password = "UserSecretPassword123!".encode('utf-8')
# ソルト生成とハッシュ化(gensaltのlog_roundsで計算コストを調整)
hashed_password = bcrypt.hashpw(raw_password, bcrypt.gensalt(rounds=12))
print("保存するハッシュ値:", hashed_password.decode('utf-8'))
# --- 検証(ログイン時) ---
input_password = "UserSecretPassword123!".encode('utf-8')
if bcrypt.checkpw(input_password, hashed_password):
print("ログイン成功")
else:
print("パスワード不一致")
② Argon2 (argon2-cffi ライブラリ)
事前にインストール: pip install argon2-cffi
from argon2 import PasswordHasher
from argon2.exceptions import VerifyMismatchError
ph = PasswordHasher() # デフォルトで推奨パラメータ(Argon2id)がセットされます
# --- ハッシュ化(ユーザー登録時) ---
raw_password = "UserSecretPassword123!"
hashed_password = ph.hash(raw_password)
print("保存するハッシュ値:", hashed_password)
# --- 検証(ログイン時) ---
input_password = "UserSecretPassword123!"
try:
ph.verify(hashed_password, input_password)
print("ログイン成功")
# 必要に応じてパラメータのアップデート確認・再ハッシュ化を行う
if ph.check_needs_rehash(hashed_password):
new_hash = ph.hash(input_password)
# データベースのハッシュ値を更新
except VerifyMismatchError:
print("パスワード不一致")
2. Node.js での実装例
① bcrypt (bcrypt パッケージ)
事前にインストール: npm install bcrypt
const bcrypt = require('bcrypt');
async function main() {
const rawPassword = 'UserSecretPassword123!';
const saltRounds = 12; // ストレッチングコスト
// --- ハッシュ化(ユーザー登録時) ---
const hashedPassword = await bcrypt.hash(rawPassword, saltRounds);
console.log('保存するハッシュ値:', hashedPassword);
// --- 検証(ログイン時) ---
const inputPassword = 'UserSecretPassword123!';
const isMatch = await bcrypt.compare(inputPassword, hashedPassword);
if (isMatch) {
console.log('ログイン成功');
} else {
console.log('パスワード不一致');
}
}
main();
② Argon2 (argon2 パッケージ)
事前にインストール: npm install argon2
const argon2 = require('argon2');
async function main() {
const rawPassword = 'UserSecretPassword123!';
// --- ハッシュ化(ユーザー登録時) ---
// 明示的に Argon2id を指定(規定値でもArgon2idが使われます)
const hashedPassword = await argon2.hash(rawPassword, {
type: argon2.argon2id,
});
console.log('保存するハッシュ値:', hashedPassword);
// --- 検証(ログイン時) ---
const inputPassword = 'UserSecretPassword123!';
if (await argon2.verify(hashedPassword, inputPassword)) {
console.log('ログイン成功');
} else {
console.log('パスワード不一致');
}
}
main();
実装時の主な注意ポイント
-
生成された文字列をそのままDBへ保存する 生成されるハッシュ文字列(例:
$argon2id$v=19$m=65536,t=3,p=4$...や$2b$12$...)には、使用したアルゴリズム、計算コスト、ソルト、ハッシュ本体が全て含まれています。DBにはこの文字列全体をカラム(VARCHARなど)に保存します。 -
Timing Attack(タイミング攻撃)対策 文字列の単純比較(
==)を使うと、一致判定の処理時間差から文字を推測される危険があります。上記ライブラリのcheckpw/verify/compareは内部的に固定時間比較(Constant-time comparison)を行っているため安全です。
情報セキュリティマネジメント試験に出てくるSAMLやOAuthなどのシングルサインオン・連携認証の仕組みを分かりやすく解説してください。
情報セキュリティマネジメント試験(SG)で頻出する「SAML」「OAuth」「OpenID Connect」は、複数サービス間で認証や認可を安全に連携するための仕組みです。
試験対策として、それぞれの役割の違い(認証か認可か)と基本動作を押さえることがポイントです。
1. 概念の違い(最重要)
試験で最も狙われるのが、「認証」と「認可」の区別です。
-
認証(Authentication): 「あなたが誰であるか」を確認すること(身元確認)。
-
認可(Authorization): 「あなたが何をしてよいか」という権限を与えること(権限付与)。
2. SAML (Security Assertion Markup Language)
企業内のクラウドサービス(SaaS)導入に伴い、社内Web SSOの標準規格として出題されます。
登場人物
-
ユーザー(ブラウザ)
-
SP (Service Provider): 利用したいWebサービス(例: Salesforce, Slack)
-
IdP (Identity Provider): ユーザー情報を管理・認証するサーバー(例: Azure AD/Entra ID, Okta)
仕組み(流れ)
-
ユーザーが SP にアクセスする。
-
SP が IdP へ転送(リダイレクト)し、ログイン画面を表示させる。
-
ユーザーが IdP で認証を行う。
-
IdP が認証成功を示すデジタル署名付きデータ(SAMLアサーション / XML形式)を発行する。
-
ユーザーのブラウザ経由で SAMLアサーション が SP に送信され、ログインが完了する。
3. OAuth 2.0
自サービスのデータを、パスワードを渡さずに安全にサードパーティアプリへ利用させるための「認可」プロトコルです。
登場人物
-
ユーザー(データ所有者)
-
クライアント: データを活用したいサードパーティアプリ(例: 連携カレンダーアプリ)
-
認可サーバー: 権限を与えるサーバー(例: Google認可サーバー)
-
リソースサーバー: 実際にデータが保管されている場所(例: GoogleカレンダーAPI)
仕組み(流れ)
-
クライアントが「Googleカレンダーへのアクセスを許可しますか?」とユーザーに確認する。
-
ユーザーが同意すると、認可サーバー からクライアントへ アクセストークン が発行される。
-
クライアントはパスワードの代わりに アクセストークン を提示して リソースサーバー からデータを取得する。
4. OpenID Connect (OIDC)
OAuth 2.0 の「認可」の仕組みを拡張し、「認証(ログイン)」にも使えるようにしたプロトコルです。
-
なぜ必要か: OAuth 2.0 は権限付与(アクセストークン発行)しか規定しておらず、ユーザーの身元確認には不十分でした。
-
仕組み: アクセストークンに加え、ユーザー識別情報が入った IDトークン(JWT形式) を発行することで、「このアカウントでログインした」という身元証明を行えるようにしています。
5. 試験直前チェックリスト
-
[ ] SAML = XML形式のメッセージ(SAMLアサーション)を使う企業向けSSO規格。
-
[ ] OAuth 2.0 = パスワードを共有せずにアクセス権限を与える「認可」の規格(発行物はアクセストークン)。
-
[ ] OpenID Connect = OAuth 2.0 をベースに「認証」を行えるよう拡張した規格(発行物はIDトークン)。
-
[ ] SSOのメリット/デメリット = 利便性向上と管理一元化/単一障害点(SpoF)や1箇所の流出で全滅するリスク。
0 件のコメント:
コメントを投稿