Open3

【認証系/Auth系】パスワードをどう保存するかについて📝

まさぴょん🐱まさぴょん🐱

【認証系/Auth系】パスワードをDBにどう保存するかについて📝

パスワードをDBに保存する場合は、以下の記事が参考になります📝

https://zenn.dev/the_exile/articles/user-password

https://note.com/only_tapwater/n/n124a586d6f3d

https://tex2e.github.io/blog/crypto/secure-password-storage

https://qiita.com/ms2sato/items/6005eea50def287090d0

https://zenn.dev/tigrebiz/articles/password-hash-csharp

https://qiita.com/yuta-katayama-23/items/6d3482e3e760807ded3c

まさぴょん🐱まさぴょん🐱

パスワードを DBに保存するか/保存しないか問題について📝

以下のポイントを押さえれば、「パスワードは保存しない」という話の真意――“プレーンテキストを保存しないが、ソルト付きハッシュは DB に保存する”――がクリアになります。
OWASP や NIST はもちろん、近年の GDPR 制裁例や“パスキー”普及の流れもすべてこの方針を裏付けています。
以下では なぜプレーンテキスト保存が危険なのか/何をどう保存すべきか/実装例(Prisma+Argon2id)/そもそもパスワード自体を持たない選択肢 まで、最新動向をまとめました。

1. プレーンテキスト保存は絶対に避ける理由

  • OWASP の Password Storage Cheat Sheet は「プレーンテキスト保存は禁止。少なくとも bcrypt、可能なら Argon2id を使うべき」と明示しています (OWASP Cheat Sheet Series)。
  • NIST SP 800-63B も、認証情報はソルトと適切な反復回数を持つ鍵導出関数で保護するよう義務づけています (NIST Pages)。
  • 2024 年には Meta が平文パスワードを内部ログに残していた件で 9,100 万ユーロの GDPR 罰金を科されました (dataprivacymanager.net)。
  • データ侵害の公開リストを見ると、漏えいのたびに数百万件のパスワードが闇市場に流出しています (IT Governance)。

2. DB に保存すべき「もの」──ソルト付きハッシュ

2-1. 推奨アルゴリズム

ライブラリ 採用理由 位置づけ
Argon2id メモリ負荷を与え ASIC/GPU での総当たりを難化 2025 年時点の事実上の推奨標準 (Reddit)
bcrypt レガシー互換用。新規なら Argon2 系へ移行推奨 (OWASP Cheat Sheet Series)

2-2. Argon2id のパラメータ目安(2025)

  • メモリ: 64 MiB 以上
  • イテレーション: 2~3 回
  • 並列数: 1~2
    上記はコミュニティでも採択が増えている設定例です (Reddit)。

2-3. “ペッパー”も検討

アプリケーション側で追加のシークレットキー(環境変数)をハッシュ入力に混ぜると、DB 単体の漏えいでは解読できなくなります(NIST も推奨)。

3. Prisma + TypeScript での実装例

3-1. Prisma モデル

model User {
  userId   String   @id @db.Uuid @default(dbgenerated("uuid_generate_v7()"))
  email    String   @unique @db.VarChar(320)
  password String                 // ← ハッシュを格納
  createdAt DateTime @default(now())
}

3-2. ハッシュ処理(argon2)

import argon2 from 'argon2';           // npm i argon2  :contentReference[oaicite:7]{index=7}
import { PrismaClient } from '@prisma/client';
const prisma = new PrismaClient();

export const signup = async (email: string, rawPw: string) => {
  const hash = await argon2.hash(rawPw);  // Argon2id がデフォルト
  return prisma.user.create({ data: { email, password: hash } });
};

export const login = async (email: string, rawPw: string) => {
  const user = await prisma.user.findUnique({ where: { email } });
  if (!user || !(await argon2.verify(user.password, rawPw))) throw new Error('Auth failed');
  return user;
};

Stack Overflow や多数の記事でも同様のパターンが紹介されています (Stack Overflow, Medium)。

4. ハッシュすら保存しない選択肢

4-1. 外部 IdP(Google/Facebook/社内 Azure AD など)

  • ユーザ情報は IdP 側が管理。アプリはアクセストークンのみ扱う。
  • パスワード漏えいリスクやリセット業務を委譲できる。

4-2. パスキー/FIDO2

  • デバイス上の TPM/SE が秘密鍵を保持し、サーバーは 公開鍵 のみ保存。漏えいしても認証には使えない。
  • 2025 年時点で「74 % のエンドユーザがパスキーを認知し、実際に利用を開始」と FIDO Alliance が報告 (FIDO Alliance)。
  • 英国政府や Microsoft なども標準ログインをパスキー主体に移行中(直近のニュース) (Latest news & breaking headlines)。

5. 運用セキュリティチェックリスト

  • TLS 強制 – ハッシュでも通信経路が平文なら意味なし。CISA も必須と警告 (CISA)。
  • レートリミット & ブルートフォース防御 – ハッシュが強くても無制限なログイン試行は危険。
  • パスワードポリシー – NIST 800-63B は “8 文字以上、制限は最小限” を推奨。強制変更の頻繁化は逆効果。
  • 漏えい監視と強制リセット – haveibeenpwned API 等で既知漏えいハッシュのブロック。
  • 多要素認証 (MFA) – パスワード単体より遥かに安全。

結論

DB にはパスワードそのものではなく、“強度あるソルト付きハッシュ(推奨 Argon2id)”を保存するのが現在のセキュリティ標準です。
さらに安全を高めるならパスワードレス(パスキー)や外部 IdP に移行し、ユーザ認証情報をアプリ側で一切保持しない設計も検討しましょう。

この流れを押さえておけば、規制・技術動向の両面で「時代遅れにならない認証基盤」を構築できます。