具有CSRF的游戏框架:“在会话中未找到CSRF令牌"? [英] Playframework with CSRF : "CSRF token not found in session"?

查看:81
本文介绍了具有CSRF的游戏框架:“在会话中未找到CSRF令牌"?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用带有内置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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆