15

たとえば、データベースに影響を与える (レコードの追加/削除/更新) フォームを送信すると、リクエストは次のようになります。

POST /application/action=更新

たとえば、更新が完了したので、ユーザーをホームページに移動させたいとします。

Response.sendRedirect /application/action=ホーム

これは素晴らしくうまく機能します。ユーザーには POST 後にリダイレクトが送信されるため、ユーザーが F5 キーを押してページを更新しようとしても問題ありません。ただし、これを行った場合、これは機能しません。

requestDispatcher.forward(/application/action=home)

更新が完了した後にさまざまな種類のエラー/成功メッセージを表示する必要があるシナリオがある場合、POST 後に転送を行う可能性が最も高くなります。このようなシナリオでは、更新アクションが 2 回発生しないようにするにはどうすればよいでしょうか?

多くの安全なサイト(銀行)/支払いゲートウェイが、「戻る/更新ボタンを押さないでください」などのテキストを画面に表示してユーザーに通知する傾向があるのは、かなり面白いと思います.

これを処理するより良い方法はありませんか?これらのボタンを押さないようにユーザーに要求する以外に? 最後に確認したところ、「Vertical Response Cache」と呼ばれるものがありました。セッション内のリクエストの一意性を識別し、リクエストが重複している場合はキャッシュされたレスポンスを送信しようとするフィルター。この古典的な問題を解決する簡単な方法はありますか?

私が話していたバーティカル レスポンス キャッシュ ソリューションへのリンクは次のとおりです: http://www.fingo.info/en/articles/_1.html。ただし、これが実際にどの程度うまく機能するかはわかりません。

4

6 に答える 6

12

はい、API リクエストを除いて、POST の後にリダイレクトする必要があると思います。これを行わないと、ユーザーが [戻る] ボタンを使用したときに重複した POST が発生することを心配する必要があるだけでなく、ユーザーが [戻る] ボタンを使用しようとしたときに、ブラウザーから迷惑なダイアログが表示されます。

Response.sendRedirect は実際には機能しますが、技術的に言えば、これはこの目的のために間違った HTTP 応答コードを送信しています。sendRedirect は 302 を送信しますが、POST を GET に変換するために使用する正しいコードは 303 です。

一般に、変更の効果を表示するビューにリダイレクトしてユーザーを送信する必要があります。たとえば、ウィジェットを編集する場合、そのウィジェットのビューにリダイレクトする必要があります。ウィジェットを削除する場合は、ウィジェットが存在していたときに表示されていたビュー (おそらくウィジェット リスト) にリダイレクトする必要があります。

アクションが発生したという事実をさらに理解させるために、ステータス メッセージがあると便利な場合があります。これを行う簡単な方法は、ビューに共通のパラメーターを設定することです。このパラメーターを設定すると、アクションが完了したというメッセージが表示されます。例えば:

/widget?id=12345&msg=Widget+modified.

ここで、「msg」パラメーターには「ウィジェットが変更されました」というメッセージが含まれています。このアプローチの欠点の 1 つは、悪意のあるサイトがユーザーに混乱や誤解を招くメッセージを与える可能性があることです。例えば:

/account?msg=Foo+Corp.+hates+you.

これが本当に心配な場合は、メッセージの有効期限が切れる署名を追加のパラメーターとして含めることができます。署名が無効または有効期限が切れている場合は、単にメッセージを表示しないでください。

于 2009-07-05T04:49:19.633 に答える
2

POSTからGETへのリダイレクト後にユーザーにステータスメッセージが表示される問題を解決する最善の解決策は、ユーザーセッションを使用することです。

どのように

表示するメッセージのセットとして値を使用して、ユーザーセッションに属性を追加します。たとえば。

userSession.put("success_messages", new HashSet<String>(){"Success", "Check your account balance"});
userSession.put("warning_messages", new HashSet<String>(){"Your account balance is low. Recharge immediately"});

そして、これらの特定の属性についてユーザーセッションをスキャンし、メッセージを出力するフィルターを用意します。ステータスメッセージは通常1回しか表示されないため、フィルタは1回読み取った後に属性を削除する必要があります。

于 2011-01-12T08:35:48.367 に答える
1

多くの安全なサイト(銀行)/支払いゲートウェイが、「戻る/更新ボタンを押さないでください」などのテキストを画面に表示してユーザーに通知する傾向があるのは、かなり面白いと思います.

一部の人々は、「この重要なページのすべての Back, Refresh イベントを無効にする」方がよいと考えています。これでいいのかよくわかりません。

しかし、あなたの解決策「垂直応答キャッシュ」はいいですね

于 2009-07-05T05:17:00.410 に答える
1

私が考えたことの 1 つは、一意の ID (おそらくランダムな文字列) を非表示のフォーム フィールドとして、POST 送信されるフォームに埋め込むことです。ID 文字列は「トランザクション ID」としてデータベースに入れることができます。ここで、データベースを更新するときは、まず、送信されたトランザクション ID を持つ既存のレコードがあるかどうかを確認します。存在する場合は、それが重複していると想定し、データベースを変更しないでください。

もちろん、私が言ったように、これはただの考えです。実際にどのような方法が実際に使用されているかはわかりません。(あまり重要でないサイトの多くは問題を無視して、ユーザーが賢明であることを願っているのではないかと思います...私が見たことがあるとしても、命題を失うことになります ;-)

EDIT : コメントで指摘されているように、トランザクション ID をデータベースに保存すると多くのスペースが必要になる場合がありますが、それが問題になる場合は、過去 5 分/1 時間に処理されたすべてのトランザクション ID のメモリ内キャッシュを保持できます。 /1日/なんでも。断固たるハッカーに立ち向かわない限り、それはうまくいくはずです...

于 2009-07-05T02:53:18.353 に答える
1

その少し自明ではありませんが:

  • ユーザー セッションでキー付きオブジェクトを作成します。
  • 値は結果の Request + Java Future です
  • クライアント側のリダイレクトですぐに戻ります。
  • クライアント側のリダイレクトが処理されている間、ワーカー スレッドで応答を生成します。

そのため、クライアント ブラウザがリダイレクトを完了し、新しいページの画像を取得するなどの時点で、結果はユーザーを待っています。

もう 1 つの方法は、データベースにかかる時間をユーザーに痛感させることです。

セキュリティ更新プログラム (2011 年 1 月 24 日) :

キーはクライアントへの応答の一部であるため、攻撃に対して脆弱です。

  1. ランダムキーを生成する
  2. ユーザーのセッション ID をソルトとして使用して SHA-1 を作成します
  3. (, ) を主キーとして、ランダム キーと SHA-1 の両方をデータベースに格納します。(RANDOMKEY での個別のインデックス作成はありません。
  4. RANDOMKEY と SHA-1 の両方をデータベース ルックアップとして使用します。
  5. セッション ID を保存しないでください (同じユーザーに多くのエントリを関連付けることができるプライバシーの問題を回避します)
  6. 結果は 2 ~ 3 日で期限切れになります。(毎日のバッチ ジョブでクリーンアップを実行できるようにし、半長期のユーザー セッションで問題が発生するのを回避します)

この方法では、ハッカーはセッション ID とランダム キーの両方を知っている必要があります。

このアプローチはやり過ぎに思えるかもしれませんが、パスワードのリセットなどの状況では、強化されたリダイレクト メカニズムを使用できます。

于 2009-07-05T07:58:29.930 に答える
0

Java サーバーサイドスクリプトを使用していて、struts 2 も使用している場合は、 token の使用について説明しているこのリンクを参照してください。

http://www.xinotes.org/notes/note/369/

トークンを生成し、最初のページのレンダリングのためにセッションに保持する必要があります。リクエストが初めてトークンとともに送信されると、struts アクションでスレッド名をトークン ID としてスレッドを実行し、クライアントが持っているロジックを実行します。が要求された場合、クライアントが同じ要求を再度送信すると、スレッドがまだ実行されているかどうかを確認し (thread.getcurrentthread().interrupted) まだ実行されている場合は、クライアントにリダイレクト 503 を送信します。

struts 2code の ExecuteAndWaitInterceptor を見てください。トークンと組み合わせたこのロジックは、高速クリックに役立ちます

于 2011-05-05T14:04:14.057 に答える