1.什么是Csrf
CSRF(Cross-site request forgery),中文名称:跨站请求伪造,也被称为:one click attack/session riding,缩写为:CSRF/XSRF。
你这可以这么理解CSRF攻击:攻击者盗用了你的身份,以你的名义发送恶意请求。CSRF能够做的事情包括:以你名义发送邮件,发消息,盗取你的账号,甚至于购买商品,虚拟货币转账…造成的问题包括:个人隐私泄露以及财产安全。
通俗的说,就是你用你浏览器缓存的认证信息和用户信息,通过另外一个钓鱼网站去访问你现在浏览器缓存的具有认证信息的网站。然后伪造请求访问那个网站去获取个人信息或者发送危险请求
2.Spring Security的Csrf是如何防御的呢
通过返回一个csrfToken,然后请求发送时需要带上这个token。这个csrfToken可以在头信息中,也可以在参数中。
3.源码解析
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
request.setAttribute(HttpServletResponse.class.getName(), response);
// 从token数据源中获取csrfToken
CsrfToken csrfToken = this.tokenRepository.loadToken(request);
boolean missingToken = (csrfToken == null);
if (missingToken) {
// 如果本地没有token ,生成token
csrfToken = this.tokenRepository.generateToken(request);
// 存起来
this.tokenRepository.saveToken(csrfToken, request, response);
}
// 丢到request属性中
request.setAttribute(CsrfToken.class.getName(), csrfToken);
request.setAttribute(csrfToken.getParameterName(), csrfToken);
if (!this.requireCsrfProtectionMatcher.matches(request)) {
// 如果关闭了Csrf防御或者对某些请求不需要Csrf校验,则跳过校验环节
if (this.logger.isTraceEnabled()) {
this.logger.trace("Did not protect against CSRF since request did not match "
+ this.requireCsrfProtectionMatcher);
}
filterChain.doFilter(request, response);
return;
}
// 从请求头中获取csrfToken
String actualToken = request.getHeader(csrfToken.getHeaderName());
if (actualToken == null) {
// 当请求头中没有的时候,从参数中获取
actualToken = request.getParameter(csrfToken.getParameterName());
}
// 校验参数
if (!equalsConstantTime(csrfToken.getToken(), actualToken)) {
this.logger.debug(
LogMessage.of(() -> "Invalid CSRF token found for " + UrlUtils.buildFullRequestUrl(request)));
// 判断到底是非法的CsrfToken异常还是没有CsrfToken异常
AccessDeniedException exception = (!missingToken) ? new InvalidCsrfTokenException(csrfToken, actualToken)
: new MissingCsrfTokenException(actualToken);
// 访问拒绝处理器
this.accessDeniedHandler.handle(request, response, exception);
return;
}
// 如果验证通过了,那继续往下走
filterChain.doFilter(request, response);
}
4.我们看一看AccessDeniedHandler
默认实现是AccessDeniedHandlerImpl
,当然我们可以通过org.springframework.security.web.csrf.CsrfFilter#setAccessDeniedHandler来设置自定义得到AccessDeniedHandler的实现。
上面我们可以看到,如果异常页面存在,则转发至异常页面。否则返回异常码。
5.小结
这样写好像有点慢,有点凑数的感觉。后面简单的就合起来写吧~虽然SpringSecurity给我们添加了很多的安全机制。但是如果不注意,可能就容易认证授权失败。为什么很多人觉得SpringSecurity难用,就是因为你对这个东西没有深入了解过。他是个黑盒,你不遵循他的规则,那你就无法用它。