CSRF 详解:攻击,防御,Spring Security应用等( 四 )

当然也可以这么写,可以看后续对默认的 DefaultRequiresCsrfMatcher 的源码
public class CsrfSecurityRequestMatcher implements RequestMatcher {private Pattern allowedMethods = Pattern.compile("^(GET|HEAD|TRACE|OPTIONS)$");private RegexRequestMatcher unprotectedMatcher = new RegexRequestMatcher("^/rest/.*", null);@Overridepublic boolean matches(HttpServletRequest request) {if(allowedMethods.matcher(request.getMethod()).matches()){return false;}return !unprotectedMatcher.matches(request);}}Spring Security - CookieCsrfTokenRepository如何工作的呢?CookieCsrfTokenRepository.withHttpOnlyFalse() 本质就是 new CookieCsrfTokenRepository()
public static CookieCsrfTokenRepository withHttpOnlyFalse() {CookieCsrfTokenRepository result = new CookieCsrfTokenRepository();result.setCookieHttpOnly(false);return result;}为何默认的存放CSRFToken的cookie是httpOnly呢?如果cookie中设置了HttpOnly属性,那么通过js脚本将无法读取到cookie信息,这样能有效的防止XSS攻击,窃取cookie内容,这样就增加了cookie的安全性,即便是这样,也不要将重要信息存入cookie 。XSS全称Cross SiteScript,跨站脚本攻击,是Web程序中常见的漏洞,XSS属于被动式且用于客户端的攻击方式,所以容易被忽略其危害性 。其原理是攻击者向有XSS漏洞的网站中输入(传入)恶意的HTML代码,当其它用户浏览该网站时,这段HTML代码会自动执行,从而达到攻击的目的 。如,盗取用户Cookie、破坏页面结构、重定向到其它网站等 。
【CSRF 详解:攻击,防御,Spring Security应用等】// 比如,设置https的cookieresponse.addHeader("Set-Cookie", "uid=112; Path=/; Secure; HttpOnly");Cookie CsrfToken 默认的封装static final String DEFAULT_CSRF_COOKIE_NAME = "XSRF-TOKEN";static final String DEFAULT_CSRF_PARAMETER_NAME = "_csrf";static final String DEFAULT_CSRF_HEADER_NAME = "X-XSRF-TOKEN";private String parameterName = DEFAULT_CSRF_PARAMETER_NAME;private String headerName = DEFAULT_CSRF_HEADER_NAME;private String cookieName = DEFAULT_CSRF_COOKIE_NAME;@Overridepublic CsrfToken generateToken(HttpServletRequest request) {return new DefaultCsrfToken(this.headerName, this.parameterName,createNewToken());}CsrfToken的保存@Overridepublic void saveToken(CsrfToken token, HttpServletRequest request,HttpServletResponse response) {String tokenValue = https://www.isolves.com/it/aq/wl/2020-01-08/token == null ? "" : token.getToken();Cookie cookie = new Cookie(this.cookieName, tokenValue);cookie.setSecure(request.isSecure());if (this.cookiePath != null && !this.cookiePath.isEmpty()) {cookie.setPath(this.cookiePath);} else {cookie.setPath(this.getRequestContext(request));}if (token == null) {cookie.setMaxAge(0);}else {cookie.setMaxAge(-1);}if (cookieHttpOnly && setHttpOnlyMethod != null) {ReflectionUtils.invokeMethod(setHttpOnlyMethod, cookie, Boolean.TRUE);}response.addCookie(cookie);}CsrfToken的加载@Overridepublic CsrfToken loadToken(HttpServletRequest request) {Cookie cookie = WebUtils.getCookie(request, this.cookieName);if (cookie == null) {return null;}String token = cookie.getValue();if (!StringUtils.hasLength(token)) {return null;}return new DefaultCsrfToken(this.headerName, this.parameterName, token);}Spring Security - CsrfFilter是如何完成拦截和校验的呢?public final class CsrfFilter extends OncePerRequestFilter {// 负责CsrfToken生成,加载等private final CsrfTokenRepository tokenRepository;// 负责拦截Csrf的匹配private RequestMatcher requireCsrfProtectionMatcher = DEFAULT_CSRF_MATCHER;// 被拦截后的拒绝策略private AccessDeniedHandler accessDeniedHandler = new AccessDeniedHandlerImpl();// CsrfFilter的过滤逻辑@Overrideprotected void doFilterInternal(HttpServletRequest request,HttpServletResponse response, FilterChain filterChain)throws ServletException, IOException {request.setAttribute(HttpServletResponse.class.getName(), response);// 加载token,没有的自动生成一个CsrfToken csrfToken = this.tokenRepository.loadToken(request);final boolean missingToken = csrfToken == null;if (missingToken) {csrfToken = this.tokenRepository.generateToken(request);this.tokenRepository.saveToken(csrfToken, request, response);}request.setAttribute(CsrfToken.class.getName(), csrfToken);request.setAttribute(csrfToken.getParameterName(), csrfToken);// 拦截请求if (!this.requireCsrfProtectionMatcher.matches(request)) {filterChain.doFilter(request, response);return;}// 校验tokenString actualToken = request.getHeader(csrfToken.getHeaderName());if (actualToken == null) {actualToken = request.getParameter(csrfToken.getParameterName());}if (!csrfToken.getToken().equals(actualToken)) {if (this.logger.isDebugEnabled()) {this.logger.debug("Invalid CSRF token found for "+ UrlUtils.buildFullRequestUrl(request));}if (missingToken) {this.accessDeniedHandler.handle(request, response,new MissingCsrfTokenException(actualToken));}else {this.accessDeniedHandler.handle(request, response,new InvalidCsrfTokenException(csrfToken, actualToken));}return;}filterChain.doFilter(request, response);}}


推荐阅读