播放框架如何故意延迟响应



我们有一个Play应用程序,目前使用2.6版本。当我们的用户提供失败的密码时,我们正试图通过延迟向他们发送"失败登录"消息来防止字典攻击我们的登录。我们目前有所有的最佳实践,但我们不确定我们是否正确地推迟了。因此,我们的控制器中有:

public Result login() { return ok(loginHtml) }

我们有一个:

public Result loginAction()
{ 
// Check for user in database
User user = User.find.query()...
// Was the user found?
if (user == null) {
// Wrong password! Delay and redirect
Thread.sleep(10000);  <<-- how do delay correctly?
return redirect(routes.Controller.login())
}
// User is not null, so all good!
...
}

我们不确定Thread.sleep(10000)是否是延迟响应的最佳方式,因为这可能会挂起其他传入的请求,或者使用默认池中的过多线程。我们注意到,在每秒80次以上的点击率下,Play Framework不会将我们的HTTP调用路由到Routes。也就是说,如果我们收到HTTP POST请求,我们的应用程序甚至要到20多秒后才会将该请求发送到控制器,但是,在同一时间段内,如果我们得到HTTP get请求,我们应用程序将立即处理该get!

目前,我们在默认分叉池的Akka设置中有300个线程作为最小/最大线程。任何见解都将不胜感激。我们运行了一个运行Ubuntu的t2.xlarg AWS EC2实例。

谢谢。

Thread.sleep导致当前线程阻塞,请尽可能避免在生产代码中使用它。

您需要使用的是CompletionStage/CompletableFuture或任何用于异步编程和异步操作的抽象。

请查看有关异步操作的更多详细信息:https://www.playframework.com/documentation/2.8.x/JavaAsync

在你的情况下,解决方案看起来也很像(对不起,这可能有错误——我是Scala的主要工程师(:

import play.libs.concurrent.HttpExecutionContext;
import play.mvc.*;
import javax.inject.Inject;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionStage;
public class LoginController extends Controller {
private HttpExecutionContext httpExecutionContext;
// Create and inject separate ScheduledExecutorService
private ScheduledExecutorService executor; 
@Inject
public LoginController(HttpExecutionContext ec,
ScheduledExecutorService executor) {
this.httpExecutionContext = ec;
this.executor = executor;
}
public CompletionStage<Result> loginAction() {
User user = User.find.query()...
if (user == null) {
return executor.schedule(() -> {redirect(routes.Controller.login());}, 10, TimeUnit.SECONDS);
} else {
// return another response
}
}
}

希望这能有所帮助!

我根本不喜欢这种方法。这会毫无理由地占用线程,如果有人发现你在这样做,并且他们有恶意想法,可能会导致整个系统锁定。让我提出一个更好的方法:

User表中存储上次登录尝试时间的可为空的LocalDateTime

当您从DB获取用户时,请检查上次尝试时间(与LocalDateTime.now((进行比较(,如果自上次尝试以来已经过去了10秒,则执行密码比较。

如果密码不匹配,则将上次尝试时间存储为现在。

如果您提供了良好的错误响应,这也可以在前端优雅地处理。

编辑:如果你想不根据用户延迟登录尝试,你可以创建一个尝试表,并按IP地址存储上次尝试。

如果你真的想按照我不建议的方式行事,你需要先阅读以下内容:https://www.playframework.com/documentation/2.8.x/ThreadPools

延迟响应确实会惩罚意外提供错误密码的合法用户,我认为这不是一个好的应用程序设计。我在我的项目中做了类似的事情,我跟踪ID的失败计数,如果超过最大尝试次数,则禁用ID。在系统方面,我们将看起来可疑的IP列入黑名单。

最新更新