CSRF / Spring Security-通过AJAX登录后出现403错误

时间:2019-03-26 01:47:47

标签: java spring spring-security csrf-protection

在Spring Security 5.1.4中使用CSRF保护时遇到问题。

我已经为应用程序设置了自定义登录页面。当用户输入他或她的凭据时,将发出AJAX请求。成功处理程序执行其职责,并在响应中返回JSON文档。 AJAX调用成功后,通过删除用户名和密码字段并将其替换为下拉字段和“继续”按钮来动态更新屏幕。

当用户从下拉列表中进行选择并单击“继续”按钮时,将更改表单上的操作,并使用POST方法提交表单。然后将用户定向到主屏幕。不幸的是,应用程序以禁止(403)错误作为响应。

当我修改WebSecurityConfigurerAdapter以禁用CSRF保护时,我的登录屏幕将按预期运行。

提交表单时,我是否缺少某些内容?请注意,我在表单元素内的隐藏字段中包含了CSRF参数和令牌。

WebSecurityConfigurerAdapter

protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .antMatchers("/css/**", "/images/**", "/js/**")
                .permitAll()
                .anyRequest().authenticated()
                .and()
                .formLogin()
                .loginPage("/login")
                .successHandler(customAuthenticationHandler)
                .permitAll()
                .and()
                .logout()
                .invalidateHttpSession(true)
                .deleteCookies("JESSIONID")
                .permitAll();
    }

public void configure(AuthenticationManagerBuilder auth) throws Exception {
    auth.inMemoryAuthentication()
            .withUser("user").password("password").roles("USER");
}

控制器

@RequestMapping(value = "/login", method = RequestMethod.GET)
public String logIn() {
    return "login-custom";
}

@RequestMapping(value = "/home", method = RequestMethod.POST)
public String home() {
    return "home";
}

JSP

<%@ page language="java" contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
    <title></title>

    <script type="text/javascript" src="/workdaybsa/js/jquery-1.10.2.min.js"></script>
    <script language="javascript">

        function login() {
            $.ajax({
                url: $('#loginForm').attr('action'),
                type: 'POST',
                data: $('#loginForm').serialize(),
                dataType: "json",
                success: function(response){
                    $('#loginSection').attr('style', 'display:none');
                    $('#selectionSection').removeAttr('style');
                },
                error: function (xhr, status, error) {
                    alert(status);
                    alert(error);
                }
           });
        }

        function proceed() {
            $('form').attr('action', 'home');
            $('form').submit();
        }
    </script>

</head>

<body>

    <form id="loginForm" action="login" method="post">

        <div id="loginSection">
            <p>
                <label for="username">Username</label>
                <input type="text" id="username" name="username">
            </p>
            <p>
                <label for="password">Password</label>
                <input type="password" id="password" name="password">
            </p>
            <input type="button" value="Sign In" onclick="login()">
        </div>
        <div id="selectionSection" style="display:none">
            <select id="selection">
                <option value="">-- Select The Option --</option>
            </select>
            <input type="button" value="Continue" onclick="proceed()">
        </div>
        <input type="hidden" id="csrf" name="${_csrf.parameterName}" value="${_csrf.token}"/>

    </form>

</body>

</html>

1 个答案:

答案 0 :(得分:0)

CSRF令牌是一种防伪令牌,您需要使用Csrf-Token标头属性在每个请求上将其传递回Spring Security,即使它在隐藏的输入字段中,该属性也不会包含在ajax调用中。这就是CSRF验证失败并抛出403的原因。

此处in this SO question

提供了解决方案

要无耻地复制粘贴答案,这是您需要的:

$.ajax({
  url: route.url,
  ...
  headers: {
    'Csrf-Token': $('#csrf").val()
  }
});