HTTP 状态 403 - 在请求参数上发现无效的 CSRF 令牌“null”
Posted
技术标签:
【中文标题】HTTP 状态 403 - 在请求参数上发现无效的 CSRF 令牌“null”【英文标题】:HTTP Status 403 - Invalid CSRF Token 'null' was found on the request parameter 【发布时间】:2015-11-05 20:16:14 【问题描述】:我必须向我的 RESTful 服务发出 HTTP.Post(android 应用程序)来注册新用户!
问题是,当我尝试向注册端点(没有安全性)发出请求时,Spring 一直阻止我!
我的项目依赖项
<properties>
<java-version>1.6</java-version>
<org.springframework-version>4.1.7.RELEASE</org.springframework-version>
<org.aspectj-version>1.6.10</org.aspectj-version>
<org.slf4j-version>1.6.6</org.slf4j-version>
<jackson.version>1.9.10</jackson.version>
<spring.security.version>4.0.2.RELEASE</spring.security.version>
<hibernate.version>4.2.11.Final</hibernate.version>
<jstl.version>1.2</jstl.version>
<mysql.connector.version>5.1.30</mysql.connector.version>
</properties>
春季安全
<beans:beans xmlns="http://www.springframework.org/schema/security"
xmlns:beans="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security.xsd">
<!--this is the register endpoint-->
<http security="none" pattern="/webapi/cadastro**"/>
<http auto-config="true" use-expressions="true">
<intercept-url pattern="/webapi/dados**"
access="hasAnyRole('ROLE_USER','ROLE_SYS')" />
<intercept-url pattern="/webapi/system**"
access="hasRole('ROLE_SYS')" />
<!-- <access-denied-handler error-page="/negado" /> -->
<form-login login-page="/home/" default-target-url="/webapi/"
authentication-failure-url="/home?error" username-parameter="username"
password-parameter="password" />
<logout logout-success-url="/home?logout" />
<csrf token-repository-ref="csrfTokenRepository" />
</http>
<authentication-manager>
<authentication-provider>
<password-encoder hash="md5" />
<jdbc-user-service data-source-ref="dataSource"
users-by-username-query="SELECT username, password, ativo
FROM usuarios
WHERE username = ?"
authorities-by-username-query="SELECT u.username, r.role
FROM usuarios_roles r, usuarios u
WHERE u.id = r.usuario_id
AND u.username = ?" />
</authentication-provider>
</authentication-manager>
<beans:bean id="csrfTokenRepository"
class="org.springframework.security.web.csrf.HttpSessionCsrfTokenRepository">
<beans:property name="headerName" value="X-XSRF-TOKEN" />
</beans:bean>
</beans:beans>
控制器
@RestController
@RequestMapping(value="/webapi/cadastro", produces="application/json")
public class CadastroController
@Autowired
UsuarioService usuarioService;
Usuario u = new Usuario();
@RequestMapping(value="/novo",method=RequestMethod.POST)
public String register()
// this.usuarioService.insert(usuario);
// usuario.setPassword(HashMD5.criptar(usuario.getPassword()));
return "teste";
JS 帖子(角度)
$http.post('/webapi/cadastro/novo').success(function(data)
alert('ok');
).error(function(data)
alert(data);
);
还有错误
HTTP Status 403 - Invalid CSRF Token 'null' was found on the request parameter '_csrf' or header 'X-XSRF-TOKEN'.</h1><HR size="1" noshade="noshade"><p><b>type</b> Status report</p><p><b>message</b> <u>Invalid CSRF Token 'null' was found on the request parameter '_csrf' or header 'X-XSRF-TOKEN'
--- 解决方案---
实现了一个过滤器将我的 X-XSRF-TOKEN 附加到每个请求标头
public class CsrfHeaderFilter extends OncePerRequestFilter
@Override
protected void doFilterInternal(HttpServletRequest request,
HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException
CsrfToken csrf = (CsrfToken) request.getAttribute(CsrfToken.class
.getName());
if (csrf != null)
Cookie cookie = WebUtils.getCookie(request, "XSRF-TOKEN");
String token = csrf.getToken();
if (cookie==null || token!=null && !token.equals(cookie.getValue()))
cookie = new Cookie("XSRF-TOKEN", token);
cookie.setPath("/");
response.addCookie(cookie);
filterChain.doFilter(request, response);
将此过滤器的映射添加到 web.xml 并完成!
【问题讨论】:
【参考方案1】:在您上面的代码中,我看不到将 CSRF 令牌传递给客户端的东西(如果您使用 JSP 等,这是自动的)。
对此的一种流行做法是编写一个过滤器以将 CSRF 令牌作为 cookie 附加。然后,您的客户端首先发送一个 GET 请求以获取该 cookie。对于后续请求,该 cookie 然后作为标头发送回。
而官方Spring Angular guide 详细解释了它,您可以参考Spring Lemon 以获得完整的工作示例。
为了将 cookie 作为标头发回,您可能需要编写一些代码。默认情况下,AngularJS 会这样做(除非您发送跨域请求),但这里有一个示例,如果您的客户端不这样做会有所帮助:
angular.module('appBoot')
.factory('XSRFInterceptor', function ($cookies, $log)
var XSRFInterceptor =
request: function(config)
var token = $cookies.get('XSRF-TOKEN');
if (token)
config.headers['X-XSRF-TOKEN'] = token;
$log.info("X-XSRF-TOKEN: " + token);
return config;
;
return XSRFInterceptor;
);
angular.module('appBoot', ['ngCookies', 'ngMessages', 'ui.bootstrap', 'vcRecaptcha'])
.config(['$httpProvider', function ($httpProvider)
$httpProvider.defaults.withCredentials = true;
$httpProvider.interceptors.push('XSRFInterceptor');
]);
【讨论】:
以上是关于HTTP 状态 403 - 在请求参数上发现无效的 CSRF 令牌“null”的主要内容,如果未能解决你的问题,请参考以下文章
在 Broadleaf 项目中 HTTP 状态 403 - 在请求参数“_csrf”或标头“X-CSRF-TOKEN”上发现无效的 CSRF 令牌“null”
预检响应在角度发布请求上具有无效的 HTTP 状态代码 403
CORS 问题:预检响应具有无效的 HTTP 状态代码 403
Angular 5:预检响应具有无效的 HTTP 状态代码 403