What is the best way in Java to implement a callable that takes constant time to complete

In order to protect against force formatting of passwords and to protect against temporary attacks trying to detect valid user names, I want my registration process to take a constant time, regardless of successful authentication or not. In short, I always want my login process to take 1000 ms (suppose the result takes fractions of that time), regardless of the result. What is the best way to accomplish this in Java? This is my current thinking:

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
source share
4 answers

Obviously, you want to move the dream to a finally block so that it also occurs if the task throws an exception (for example, PasswordExpiredException?).

Another problem is handling the elapsed > duration case. You say it never happens, but are you sure? What if your database query is blocked by a lock? Assuming that you want to refuse authentication in such an event, you can do:

 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; } } 

(Of course, you will need to add the correct exception handling)

I'm not sure, although this is a good way to protect against brute force attacks. Instead, we will cancel the user login after the third unsuccessful login attempt (for a certain period of time or until the administrator unlocks the account). Mention somewhere that you are doing this, and no one has a reason to brute force passwords.

+2
source

If you want each login to try to take some minimal time and at the same time want to process a larger number of users (for example, 1000 logins per second), there is no way to handle this with the simple "let the thread wait for a while" model "- you yourself use DOS, because in Java, each thread consumes several resources, and therefore the total number of threads is limited, even if they actually do nothing.

To stay scalable, you must use asynchronous I / O to accept user requests from users, check the password (possibly also asynchronously), set a timer in order to review this user connection, and then respond (also asynchronously), Java does this quite difficult to write (and then read), unfortunately.

+2
source

How are you going to cut out the call result = task.call (); if it exceeds 1000 ms? All you need is a function that does not return to t1, regardless of whether it is executing or not. A simple solution would be to use sleep or wait in an executable thread after sending the task to the thread pool executor. And then check if future.isDone () will be. If not cancel, if yes, you have already waited 1000 ms.

0
source

A dream inside your thread will mean that the thread cannot do anything. It will not scale.

Use the planned executor and assign a delayed task that will return the result in the future. http://docs.oracle.com/javase/1.5.0/docs/api/java/util/concurrent/ScheduledExecutorService.html

0
source

Source: https://habr.com/ru/post/1395919/


All Articles