説明
パスワード、トークン、APIキー、セッション識別子をファイルやブラウザーストレージへ平文で保存すると、ディスク、バックアップ、ローカルストレージ、ログ状のファイルから漏えいする可能性があります。攻撃者がこれらの値を使い、認証を回避したり、セッションを乗っ取ったり、内部APIへアクセスしたりするおそれがあります。
想定される影響
- ファイルシステムやバックアップに残った平文の秘密値が漏えいする可能性があります。
- ブラウザーストレージ内の長期トークンが、XSSやローカルアクセスで盗まれるおそれがあります。
- 平文パスワードの漏えいにより、同じ値を使う他サービスのアカウントも侵害される可能性があります。
対処方法
- パスワードはArgon2id、bcrypt、scryptなどの専用ハッシュで保存してください。
- トークン、APIキー、セッション値は可能なら保存せず、必要な場合はサーバー側のVaultや暗号化ストレージを使ってください。鍵とデータのアクセス権限は分離してください。
- ブラウザーの
localStorageやsessionStorageに長期認証トークンを保存しないでください。 - 機密Cookieが必要な場合は値を最小限にし、少なくとも
Secure、HttpOnly、SameSiteを設定してください。これらの属性は値そのものを暗号化しません。
例
users はアプリケーションの保存層を示し、入力検証とエラー処理は省略しています。bcryptの72バイト制限とコストを確認し、ログイン検証にも同じ入力方針を適用してください。
変更前
javascript
const fs = require("fs");
function save(req, res) {
fs.writeFileSync("/tmp/password.txt", req.body.password);
}
変更後
javascript
const bcrypt = require("bcrypt");
async function save(req, res) {
const passwordHash = await bcrypt.hash(req.body.password, 12);
await users.save({ passwordHash });
}
解説:
- 変更前: 平文パスワードをファイルへ書くため、ディスクやバックアップが漏えいするとそのまま再利用されるおそれがあります。
- 変更後: 専用アルゴリズムでハッシュ化し、元のパスワードを保存しません。
署名したJWTも、内容が暗号化されているとは限りません。Cookieの転送・スクリプトアクセス保護と、保存データの機密性をそれぞれ確認してください。