SpringSecurity过滤器-CsrfFilter

CsrfFilter是为了防御CSRF攻击的。CSRF攻击请参考松哥手把手教你在 SpringBoot 中防御 CSRF 攻击!so easy!
CsrfFilter的源码在要学就学透彻!Spring Security 中 CSRF 防御源码解析 说的很清楚了。

 
在这里是对LazyCsrfTokenRepository的使用做个总结。

 

CsrfFilter#doFilterInternal

protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
		throws ServletException, IOException {
	request.setAttribute(HttpServletResponse.class.getName(), response);
	CsrfToken csrfToken = this.tokenRepository.loadToken(request);
	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)) {
		if (this.logger.isTraceEnabled()) {
			this.logger.trace("Did not protect against CSRF since request did not match "
					+ this.requireCsrfProtectionMatcher);
		}
		filterChain.doFilter(request, response);
		return;
	}
	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)));
		AccessDeniedException exception = (!missingToken) ? new InvalidCsrfTokenException(csrfToken, actualToken)
				: new MissingCsrfTokenException(actualToken);
		this.accessDeniedHandler.handle(request, response, exception);
		return;
	}
	filterChain.doFilter(request, response);
}

if (missingToken) {
		csrfToken = this.tokenRepository.generateToken(request);
		this.tokenRepository.saveToken(csrfToken, request, response);
	}

会生成csrf-token并保存,是get请求时,this.requireCsrfProtectionMatcher.matches(request)判断返回false,就不会走下面的csrf-token验证了。所以没有必要保存csrf-token。LazyCsrfTokenRepository对csrf-token做了代理只在需要保存时才保存。
 

LazyCsrfTokenRepository#saveToken

public void saveToken(CsrfToken token, HttpServletRequest request, HttpServletResponse response) {
	if (token == null) {
		this.delegate.saveToken(token, request, response);
	}
}

只有当token为null时才保存。一般情况下token都不会为null。

 

只有CsrfFilter#doFilterInternal调用到equalsConstantTime(csrfToken.getToken(), actualToken)验证csrf-token时,才去保存csrf-token。

SaveOnAccessCsrfToken#getToken()

public String getToken() {
		saveTokenIfNecessary();
		return this.delegate.getToken();
	}

调用saveTokenIfNecessary去保存csrf-token。

posted @ 2023-04-14 22:08  shigp1  阅读(511)  评论(0)    收藏  举报