私の会社の CRM システムは、特定の管理機能を利用するために、ログインのたびにキャプチャ システムを利用しています。元の実装では、現在のキャプチャ値がサーバー側のセッション変数に格納されていました。
これを再開発して、必要なすべてのキャプチャ検証情報をハッシュされたクライアント側 Cookie に保存する必要があります。これは、アプリケーションに対してまだ認証されていないユーザーのセッションの使用を許可しないことでオーバーヘッドを削減することを目的とした親 IT ポリシーによるものです。したがって、認証プロセス自体は、サーバー側のストレージまたはセッションを使用できません。
このデザインはちょっとしたグループ作業でしたが、全体的な有効性については疑問があります. 私の質問は、以下に示す実装で明らかなセキュリティ上の問題を誰でも見ることができますか?それは過剰または不十分ですか?
編集: さらなる議論が更新された実装につながったので、元のコードを新しいバージョンに置き換え、このリビジョンに対応するように説明を編集しました。
(以下のコードは一種の疑似コードです。元のコードでは、読みにくい独特のレガシー ライブラリと構造が使用されています。うまくいけば、このスタイルで十分に理解しやすくなります。)
// Generate a "session" cookie unique to a particular machine and timeframe
String generateSessionHash(timestamp) {
return sha256( ""
+ (int)(timestamp / CAPTCHA_VALIDITY_SECONDS)
+ "|" + request.getRemoteAddr()
+ "|" + request.getUserAgent()
+ "|" + BASE64_8192BIT_SECRET_A
);
}
// Generate a hash of the captcha, salted with secret key and session id
String generateCaptchaHash(captchaValue, session_hash) {
return sha256( ""
+ captchaValue
+ "|" + BASE64_8192BIT_SECRET_B
+ "|" + session_hash
);
}
// Set cookie with hash matching the provided captcha image
void setCaptchaCookie(CaptchaGenerator captcha) {
String session_hash = generateSessionHash(time());
String captcha_hash = generateCaptchaHash(captcha.getValue(), session_hash);
response.setCookie(CAPTCHA_COOKIE, captcha_hash + session_hash);
}
// Return true if user's input matches the cookie captcha hash
boolean isCaptchaValid(userInputValue) {
String cookie = request.getCookie(CAPTCHA_COOKIE);
String cookie_captcha_hash = substring(cookie, 0, 64);
String cookie_session_hash = substring(cookie, 64, 64);
String session_hash = generateSessionHash(time());
if (!session_hash.equals(cookie_session_hash)) {
session_hash = generateSessionHash(time() - CAPTCHA_VALIDITY_SECONDS);
}
String captcha_hash = generateCaptchaHash(userInputValue, session_hash);
return captcha_hash.equals(cookie_captcha_hash);
}
概念:
- 「session_hash」は、同じ Cookie が複数のマシンで使用されるのを防ぐことを目的としており、無効になるまでの期間を強制します。
- 「session_hash」と「captcha_hash」の両方に独自の秘密ソルト キーがあります。
- これらの BASE64_8192BIT_SECRET_A および _B ソルト キーは、サーバーに格納されている RSA 秘密キーの一部です。
- 「captcha_hash」は、シークレットと「session_hash」の両方でソルトされます。
- スプライシング攻撃を回避するために、クライアント提供のデータが使用される場所に区切り文字が追加されます。
- 「captcha_hash」と「session_hash」はどちらもクライアント側の Cookie に保存されます。
編集: re:Kobi フィードバックありがとうございます!
(コメントで返信しますが、質問で機能するフォーマットを受け入れないようですか?)
ログイン ページにアクセスするたびに、キャプチャが置き換えられます。ただし、これは、ログイン フォーム ページをリロードせずに単純に再送信しないことを前提としています。セッションベースの実装では、有効期限を使用してこの問題を回避します。ログイン ページに nonce を追加することもできますが、そのためにもサーバー側のセッション ストレージが必要になります。
Kobi の提案によると、ハッシュ化されたデータに有効期限の時間枠が含まれるようになりましたが、セッションにタイムアウトがあることは直感的であるため、代わりにそれを session_hash に追加することがコンセンサスです。
一部のデータをハッシュし、そのデータに別のハッシュを含めるというこの考えは、私には疑わしいようです。それとも、関連するすべてのデータ (時間、IP、ユーザー エージェント、Captcha 値、および秘密鍵) を含む単一のハッシュを使用する方がよいのでしょうか。この実装では、基本的にハッシュ化された平文の一部をユーザーに伝えています。
質問:
- 明らかな欠陥はありますか?
- 微妙な欠点はありますか?
- より堅牢なアプローチはありますか?
- ハッシュを別のハッシュでソルトすることは何かを助けていますか?
- よりシンプルで同等に堅牢なアプローチはありますか?
新しい質問:
個人的には、サーバー側のセッションのままにしておく方がよいと思います。すべての検証データをクライアント側のみに送信することの固有のリスクを証明または反証する論文または記事を誰か教えてもらえますか?