When CSRF enable in Spring Security, Access denied 403

给你一囗甜甜゛ 提交于 2020-01-03 04:32:29

问题


In my Spring application in spring security configuration file when csrf is enable (<security:csrf/>)

and try to submit login form then Access denied page 403 appear (or)

(Invalid CSRF Token 'null' was found on the request parameter '_csrf' or header 'X-CSRF-TOKEN'.) exception (when access-denied-handler not present)

"But if I don't enable CSRF in spring security configuration file then everything work perfectly."

Here my codes when CSRF enable

pom.xml (all the versions)

<properties>
    <spring.version>3.2.8.RELEASE</spring.version>
    <spring.security.version>3.2.3.RELEASE</spring.security.version>
    <jstl.version>1.2</jstl.version>
    <mysql.connector.version>5.1.30</mysql.connector.version>
</properties>

spring-security.xml

    <security:http auto-config="true" use-expressions="true">

    <security:intercept-url pattern="/login" access="permitAll"/>
    <security:intercept-url pattern="/**" access="isAuthenticated()"/>

    <!-- access denied page -->
    <security:access-denied-handler error-page="/403"/>

    <security:form-login
        login-page="/login" default-target-url="/loginSuccess" authentication-failure-url="/loginError?error"/>

    <!-- enable csrf protection-->  
    <security:csrf/>    
</security:http>

<!-- Select users and user_roles from database -->
<security:authentication-manager>
    <security:authentication-provider>
        <!--<security:jdbc-user-service data-source-ref="dataSource" 
                    users-by-username-query="select username,password, enabled from registration where username=?"
                    authorities-by-username-query="select username, role from registration where username=?"/> -->
        <security:user-service>
            <security:user name="test" password="test" authorities="ROLE_USER" />
            <security:user name="test1" password="test1" authorities="ROLE_ADMIN" />
        </security:user-service>            
    </security:authentication-provider>
</security:authentication-manager>

Controller

    @Controller
public class MainController {

    @RequestMapping(value={"/login"})
    public ModelAndView loginPage(){

        ModelAndView model = new ModelAndView("login");
        return model;
    }

    @RequestMapping(value={"/loginSuccess"},method=RequestMethod.POST)
    public ModelAndView loginSuccess(Principal principal,HttpServletRequest request,HttpSession session){

        ModelAndView model = new ModelAndView("success");

        //Testing.......
        String name = principal.getName();
        model.addObject("username", name);

        session = request.getSession();
        session.setAttribute("USER", "system");

        return model;
    }

login.jsp

    <%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ page language="java" import="java.util.*" pageEncoding="ISO-8859-1"%>
<%@page session="true"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <base href="<%=basePath%>">

    <title>login Page</title>

    <!-- <meta http-equiv="pragma" content="no-cache">
    <meta http-equiv="cache-control" content="no-cache">
    <meta http-equiv="expires" content="0">    
    <meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
    <meta http-equiv="description" content="This is my page">

    <link rel="stylesheet" type="text/css" href="styles.css">
    -->

  </head>

  <body onload='document.loginForm.username.focus();'>

        <h1>Spring Security Login Form (Database Authentication)</h1>

    <div>   
        <h3>Login with Username and Password</h3>

        <c:if test="${not empty error}">
            <div>${error}</div>
        </c:if>

        <form name="loginForm" action="j_spring_security_check" method="post">

            <table>
                <tr>
                    <td>Username</td>
                    <td><input type="text" name=j_username></td>
                </tr>
                <tr>
                    <td>Password</td>
                    <td><input type="password" name=j_password></td>
                </tr>
                <tr>
                    <td colspan='2'><input name="submit" type="submit"
                        value="submit" /></td>
                </tr>

            </table>
                <input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}"/>
        </form>
    </div>  
  </body>
</html>

403.jsp

    <%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<html>
<body>
    <h1>HTTP Status 403 - Access is denied</h1>

    <c:choose>
        <c:when test="${empty username}">
            <h2>You do not have permission to access this page!</h2>
        </c:when>
        <c:otherwise>
            <h2>Username : ${username} <br/>You do not have permission to access this page!</h2>
        </c:otherwise>
    </c:choose>

</body>
</html>

Output:

    HTTP Status 403 - Access is denied

Username : ${username} 
You do not have permission to access this page!

Please help.

Solution

Controller:

@RequestMapping(value={"/","/loginSuccess"},method=RequestMethod.GET)
public ModelAndView loginSuccess()

web.xml

    <welcome-file-list>
      <welcome-file>login.jsp</welcome-file>
    </welcome-file-list>

Due to of default page


回答1:


I think you are doing an ajax request once you submit the form. In that case, you have to pass csrf token in the header.

something like,

var token = $("meta[name='_csrf']").attr("content");
var header = $("meta[name='_csrf_header']").attr("content");
var headers ={};
headers[header]=token;
var headerObj = {};
headerObj['headers']=headers;
$http.post("http://xyz",request,headerObj);

In order to enable csrf only for a particular url, You can do something like this

@EnableWebSecurity
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().requireCsrfProtectionMatcher(new RequestMatcher() {

            @Override
            public boolean matches(HttpServletRequest request) {
                return request.getServletPath().contains("/xyz");
            }
        });
    }
}


来源:https://stackoverflow.com/questions/46646555/when-csrf-enable-in-spring-security-access-denied-403

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!