4

パスワードのブルートフォースから保護し、有効なユーザー名を検出しようとするタイミング攻撃から保護するために、認証が成功したかどうかに関係なく、ログインプロセスに一定の時間がかかるようにします。要するに、私は常に、結果に関係なく、ログインプロセスに1000msかかることを望んでいます(どちらの結果もその時間の何分の1かかかると仮定します)。Javaでこれを達成するための最良の方法は何ですか?これが私の現在の考え方です。

class ConstantDuration<T> implements Callable<T> {

 ConstantDuration(Callable<T> task,long duration) {
  this.task = task;
  this.duration = duration;
 }

 public T call() throws Exception {
  long start = System.currentTimeMillis();
  long elapsed = 0;
  T result = null;
  try {
   result = task.call();
  } finally {
    elapsed = System.currentTimeMillis() - start;
  }
  if ( elapsed < duration ) {
   Thread.sleep(duration-elapsed);
  }
  return result;
 }
}
4

4 に答える 4

2

各ログインの試行に最小限の時間を必要とし、同時により多くのユーザー (毎秒 1000 回のログインなど) を処理できるようにしたい場合は、単純な "let the thread Java では、各スレッドがいくらかのリソースを消費するため、スレッドが実際には何もしていなくても、スレッドの総数が制限されているためです。

スケーラブルな状態を維持するには、非同期 I/O を使用してユーザーからのログイン要求を取得し、パスワードを確認し (おそらく非同期でも)、このユーザーの接続にいつ再アクセスするかのタイマーを設定してから、応答する必要があります (これも非同期で)。残念ながら、Java を使用すると、これを作成 (および読み取り) するのが非常に複雑になります。

于 2012-02-11T17:00:56.883 に答える
2

明らかに、sleep を finally ブロックに移動して、タスクが例外 (たとえば、PasswordExpiredException?) をスローした場合にも発生するようにする必要があります。

もう 1 つの問題は、ケースの処理elapsed > durationです。そんなことは絶対にないとあなたは言いますが、本当ですか?データベース クエリがロックによって停止した場合はどうなるでしょうか。このようなイベントで認証を拒否すると仮定すると、次のようにすることができます。

ExecutorService exec = Executors.newFixedThreadPool(10);

<T> T doInConstantTime(Callable<T> task, long millis, T defaultResponse) {
    Future<T> future = exec.submit(task);
    Thread.sleep(millis);
    if (future.isDone()) {
        return future.get();
    } else {
        future.cancel(false); // or true? 
        return defaultResponse;
    }
}

(もちろん、適切な例外処理を追加する必要があります)

ただし、これがブルートフォース攻撃を防御するための良い方法であるかどうかはわかりません。代わりに、3 回連続してログイン試行が失敗した後 (一定期間または管理者がアカウントのロックを解除するまで)、ユーザーのログインを無効にします。あなたがこれを行っていることをどこかに言及してください。誰もパスワードをブルートフォースする理由はありません.

于 2012-02-11T14:29:12.533 に答える
0

result = task.call(); への呼び出しをどのようにカットしますか? 1000msを超えたら?必要なのは、実行が完了したかどうかに関係なく、t1 時間前に返らない関数だけです。簡単な解決策は、タスクをスレッド プール エグゼキューターに送信した後、実行中のスレッドでスリープまたは待機を使用することです。そして、future.isDone() かどうかを確認します。はいの場合、キャンセルしない場合は、すでに 1000 ミリ秒待機しています。

于 2012-02-11T13:38:02.623 に答える
0

スレッド内でスリープすると、スレッドは何もできなくなります。それはスケーリングしません。

スケジュールされたエグゼキュータを使用して、将来結果を返す遅延タスクをスケジュールします。 http://docs.oracle.com/javase/1.5.0/docs/api/java/util/concurrent/ScheduledExecutorService.html

于 2012-02-11T13:48:29.483 に答える