はじめに
最近 Next.js でフロントエンドとバックエンドのプロジェクトをいくつか書き、その中で better-auth を使ってユーザー認証を行いました。
しかし、実践の中で AI が直接関連コードを書くと、簡単にパスワードが平文で送信されてしまうことがわかりました。本番環境では通常 HTTPS が使用され、トランスポート層ですでに TLS 暗号化されていますが、だからといってパスワードを平文でリクエストボディに入れてもいいというわけではありません。 HTTPS はブラウザから TLS 終端点(nginx など)までの通信の安全性しか保証できません。パスワードはリバースプロキシ、ゲートウェイ、ログ、データベースなどで依然として平文のまま残り、これらのアクセス権限を持つ人なら誰でも全員のアカウントにログインできてしまいます。個人プロジェクトではパスワード暗号化を無視してもいいかもしれませんが、これは明らかに製品として受け入れられるものではありません。
そのため、このブログ記事では better-auth を使用する際にアプリケーション層でパスワードに RSA 非対称暗号化を行う方法について解説します。この記事を AI に学習させれば他のプロジェクトでも同様の実装ができるかもしれませんが、MIT ライセンスに従ってクレジットを表示してください。詳細は記事の最後を参照してください。
全体の流れ
- ユーザーがブラウザでパスワードを入力する。
- フロントエンドが
NEXT_PUBLIC_RSA_PUBLIC_KEYを読み込む。 - RSA-OAEP を使ってパスワードを暗号化する。
- 暗号化パッケージにタイムスタンプ、ランダムソルト、リクエスト ID、HMAC 署名を添付する。
- フロントエンドが暗号化された文字列を better-auth に渡す。
- サーバー側で better-auth の
password.hash/password.verifyで復号する。 - 最終的にデータベースには bcrypt ハッシュのみを保存する。
この流れの中で、平文のパスワードはユーザーがパスワードを入力する時のみ現れます。
クライアント側の暗号化
ここではパスワード自体だけを暗号化するのではなく、いくつかのフィールドを一緒に RSA 暗号文に入れています:
それぞれ:
passwordはユーザーが入力した元のパスワード。timestampはリクエストが期限切れかどうかを判断するために使用。saltは同じパスワードでも毎回異なる暗号文を生成するためのもの。requestIdはリプレイ攻撃を防ぐために使用。
ログインページでは、better-auth に送信する前にまず rsaEncrypt を呼び出します。
登録時も同様です:
これにより、パケットキャプチャで見える password フィールドは元のパスワードではなく、RSA 暗号化されたデータパッケージになります。

サーバー側の復号
まず秘密鍵で復号します:
次に検証を行います:
ここでは主に以下のことを行っています:
- 暗号化パッケージのフォーマットを確認。
- タイムスタンプが期限切れかどうかを確認。
requestIdが既に使用されているかどうかを確認。- RSA 秘密鍵で復号。
- 外側のタイムスタンプと内側のタイムスタンプが一致するかどうかを確認。
- 外側のリクエスト ID と内側のリクエスト ID が一致するかどうかを確認。
- HMAC 署名を検証。
- パスワードの bcrypt ハッシュを返す。
requestId の重複排除には Redis を使用します:
つまり、最初のリクエストだけが書き込みに成功し、同じ requestId を再利用する後続のリクエストは拒否され、リプレイ攻撃を防ぎます。
公開鍵と秘密鍵のペアの生成コマンドは以下の通りです:
もちろん ssh-keygen を直接使うことも可能です。また、秘密鍵の安全性を確保することは必須です。
better-auth の導入
better-auth はデフォルトでメールとパスワードによるログインを処理しますが、ここでは暗号化とハッシュ化を実現するためにパスワード処理ロジックをカスタマイズする必要があります。
ここで一つの詳細があります:better-auth の minPasswordLength は 1 に、maxPasswordLength は 4096 に設定されています。
その理由は、better-auth に渡されるのは元のパスワードではなく、RSA 暗号化されたデータパッケージだからです。デフォルトの長さ制限を使い続けると、better-auth の層で簡単にブロックされてしまいます。
パスワードの長さを制限する必要がある場合は、クライアント側の rsaEncrypt で行うしかありません。
もちろん、better-auth はデフォルトではログインと登録のシナリオでのみパスワード検証が必要です。パスワード変更やアカウント削除などの場所では、rsaEncrypt と rsaDecryptAndValidate を再利用するだけで済みます。
better-auth のその他のセキュリティ設定
パスワード暗号化に加えて、betterAuth の初期化時にいくつかのセキュリティ項目を設定できます:
意味は大まかに以下の通りです:
- CSRF チェックを無効にしない。
- 本番環境で Secure Cookie を使用する。
- Cookie に
httpOnlyを設定する。 - Cookie に
sameSite: "lax"を設定する。
また、ログイン、登録、パスワードリセットのレート制限:
これにより、認証情報の流用、大量登録、メール送信スパムなどの問題を減らすことができます。