在 Spring Security 中启用 CSRF 时,访问被拒绝 403
Posted
技术标签:
【中文标题】在 Spring Security 中启用 CSRF 时,访问被拒绝 403【英文标题】:When CSRF enable in Spring Security, Access denied 403 【发布时间】:2018-03-20 16:03:58 【问题描述】:启用 csrf 时,在我的 Spring 应用程序中的 spring 安全配置文件中
(<security:csrf/>)
并尝试提交登录表单,然后出现访问被拒绝页面 403(或)
(Invalid CSRF Token 'null' was found on the request parameter '_csrf' or header 'X-CSRF-TOKEN'.)
异常(当访问拒绝处理程序不存在时)
“但是如果我没有在 spring 安全配置文件中启用 CSRF,那么一切都会完美运行。”
这是我启用 CSRF 时的代码
pom.xml(所有版本)
<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
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>
输出:
HTTP Status 403 - Access is denied
Username : $username
You do not have permission to access this page!
请帮忙。
解决方案
控制器:
@RequestMapping(value="/","/loginSuccess",method=RequestMethod.GET)
public ModelAndView loginSuccess()
web.xml
<welcome-file-list>
<welcome-file>login.jsp</welcome-file>
</welcome-file-list>
由于默认页面
【问题讨论】:
您使用的是旧的 Spring Security 版本...无论如何您可以在这里查看 docs.spring.io/spring-security/site/docs/4.2.4.BUILD-SNAPSHOT/…。基本上,您启用了 CSRF 安全性,但您没有将令牌值传递给 spring @AngeloImmedia 如何传递token值? docs.spring.io/spring-security/site/docs/current/reference/html/…<input type="hidden" name="$_csrf.parameterName" value="$_csrf.token"/>
@Korashen 我已将此行包含在登录表单(login.jsp)中
你必须将它包含在所有页面和所有 ajax 调用中
【参考方案1】:
我认为您在提交表单后正在执行 ajax 请求。在这种情况下,您必须在标头中传递 csrf 令牌。
类似,
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);
为了只为特定的 url 启用 csrf,你可以这样做
@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");
);
【讨论】:
以上是关于在 Spring Security 中启用 CSRF 时,访问被拒绝 403的主要内容,如果未能解决你的问题,请参考以下文章
如何在 Spring Security 中启用 POST、PUT 和 DELETE 方法
如何在 Spring Boot 中在 Spring Security 级别启用 CORS [关闭]
启用 Spring Security CSRF 的 Sockjs 回退
以编程方式启用 Spring Security pre-post-annotations