具有CSRF的游戏框架:“在会话中未找到CSRF令牌"? [英] Playframework with CSRF : "CSRF token not found in session"?
问题描述
我正在使用带有内置CSRF过滤器和Security.Authenticator系统的Playframework创建一个简单的身份验证系统,但是我遇到了一个问题:
I'm making a simple authentication system using Playframework with their built-in CSRF filter and Security.Authenticator system, but I'm facing a problem :
当用户填写其登录名/密码并提交回车时,出现以下错误:
When the user fill his login/password and submit enter, I have the following error :
在会话中找不到CSRF令牌
CSRF token not found in session
我检查了表单,发现CSRF令牌确实存在并正确放置(在标签内)
I checked my form and the CSRF token is really present and correctly placed (inside the tag)
这是我的routes
:
GET /login controllers.Authentication.login
POST /login controllers.Authentication.authenticate
还有我的Authentication.java
课:
@play.filters.csrf.AddCSRFToken
public static Result login() {
if (Session.getAccount() != null) {
return redirect(controllers.routes.Instances.list());
}
LoginForm loginForm = new LoginForm();
if (ctx().session().containsKey("email")) {
loginForm.setEmail(ctx().session().get("email"));
}
if (request().queryString().containsKey("disconnected")) {
flash("warning", Messages.get("secure.logout")); // TODO : Warning flash message
}
Form<LoginForm> form = Form.form(LoginForm.class).fill(loginForm);
return ok(views.html.login.render(form));
}
@play.filters.csrf.AddCSRFToken
@play.filters.csrf.RequireCSRFCheck
public static Result authenticate() {
Form<LoginForm> form = Form.form(LoginForm.class).bindFromRequest();
if (form.hasErrors()) {
return badRequest(views.html.login.render(form));
}
LoginForm login = form.get();
Account account = Account.findByEmail(login.getEmail());
if (account == null || !account.checkPassword(login.getPassword())) {
form.reject("email", "secure.invalid.login");
return badRequest(views.html.login.render(form));
}
String next = null;
if (ctx().session().containsKey("next")) {
next = ctx().session().get("next");
if ("".equals(next)) {
next = null;
}
}
session().clear();
session("email", login.getEmail());
if (next != null) {
return redirect(next);
} else {
return redirect(controllers.routes.Instances.list());
}
}
我在application.conf中设置的属性:
The properties I setted in the application.conf :
csrf.token.name="csrf"
csrf.sign.tokens=true
这是我的表格(以显示令牌的正确位置):
Here's my form (to show that the token is correctly positionned) :
<form action="@controllers.routes.Authentication.authenticate" method="post" class="form-vertical" role="form">
<fieldset>
@defining(form("email")) { element =>
<div class="form-group fade-in two@if(element.hasErrors){ has-error}">
<label class="control-label" for="login-form-@element.name">Email:</label>
<input type="email" name="@element.name" id="login-form-@element.name" class="form-control" value="@element.value" placeholder="Enter your email" required />
@element.errors.map { error => <span class="help-block">@play.i18n.Messages.get(error.message)</span>}
</div>}
@defining(form("password")) { element =>
<div class="form-group fade-in three@if(element.hasErrors){ has-error}">
<label class="control-label" for="login-form-@element.name">Password:</label>
<input type="password" name="@element.name" id="login-form-@element.name" class="form-control" value="@element.value" placeholder="Enter your password" required />
@element.errors.map { error => <span class="help-block">@play.i18n.Messages.get(error.message)</span>}
</div>}
<div class="form-group actions fade-in four">
<div class="text-right">
<input type="submit" name="save" value="Sign me in" class="btn btn-primary" />
@helper.CSRF.formField
</div>
</div>
</fieldset>
</form>
更新1 :我删除了所有@addCSRFToken
和@requireCSRFToken
,而是根据@rhj的建议,定义了一个全局CSRF令牌.现在我得到了这个错误:
Update 1: I removed all the @addCSRFToken
and @requireCSRFToken
and defined a global CSRF token instead, per @rhj recommandation. Now I got this error instead :
在表单正文中找到无效的令牌
Invalid token found in form body
但是,正如您在HTML表单中看到的那样,令牌位于表单内并且应该被标识!
But as you can see in the HTML Form, the token is placed inside the form and should be identified!
更新2 :最让我困扰的是,此问题仅出现在登录"页面上,而没有其他地方出现!是否有一些会话要首先启用?我想不是,但是??
Update 2: What bothers me the most, is that this problem only occurs in the Login page, and not elsewhere! Is there some session to enable first? I guess not but maybe ?!
更新3 :更奇怪的是,我刚刚发现,如果更改csrf.token.name
的值并重新加载页面,它将可以正常工作.然后,如果我注销,请打开一个新页面并尝试再次登录,该页面将失败,并显示消息Invalid token found in form body
.如果我再次更改csrf.token.name
的值并再次执行,它将再次起作用.
Update 3: More odd, I just found out that if I change the value of csrf.token.name
and reload the page, it works. Then if I log out, open a new page and try to logs again, it fails with the message Invalid token found in form body
. If I again change the value of csrf.token.name
and do it again, it will works again.
更新4 :我缩小了范围.我还使用了play.mvc.Security.Authenticator,似乎只有在redirect()
之后显示页面时,令牌验证才会失败.如果直接进入登录页面,则不会显示错误消息.
Update 4: I narrowed down the problem. I also use the play.mvc.Security.Authenticator and it seems that the token verification fails ONLY when I display the page after a redirect()
. If I go straight to the login page, I won't have the error message displayed.
最终更新!:我终于找到了问题,那是我不怀疑的另一个类,它被调用并清除了会话,使令牌无用!
Final update! : I finally found the problem, it was in another class that I wasn't suspecting, that was called and cleared the session, making the token useless!
推荐答案
最后,问题出在我代码的另一部分,该部分正在清理login()
方法中的会话,并随之删除了csrf令牌...
Finally the problem was located in an other part of my code that was cleaning the session in the login()
method, removing the csrf token with it ...
这篇关于具有CSRF的游戏框架:“在会话中未找到CSRF令牌"?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!