Spinrg Security原理 ------CSRF(一)

CsrfConfigurer

  1. 首先创建CsrfFilter,并初始化CSRF持久化类,默认为new LazyCsrfTokenRepository(
    new HttpSessionCsrfTokenRepository())
  2. 初始化拦截路径,包括忽略路径和不需要验证的请求方法具体请看属性requireCsrfProtectionMatcher
  3. 设置拒绝策略
  4. 将CSRF持久化复制给LogoutConfigurer和SessionManagementConfigurer
public final class CsrfConfigurer<H extends HttpSecurityBuilder<H>>
		extends AbstractHttpConfigurer<CsrfConfigurer<H>, H> {
	private CsrfTokenRepository csrfTokenRepository = new LazyCsrfTokenRepository(
			new HttpSessionCsrfTokenRepository());
	private RequestMatcher requireCsrfProtectionMatcher = CsrfFilter.DEFAULT_CSRF_MATCHER;
	private List<RequestMatcher> ignoredCsrfProtectionMatchers = new ArrayList<>();
	private final ApplicationContext context;

	@SuppressWarnings("unchecked")
	@Override
	public void configure(H http) throws Exception {,
		CsrfFilter filter = new CsrfFilter(this.csrfTokenRepository);
		// 初始化拦截路径
		RequestMatcher requireCsrfProtectionMatcher = getRequireCsrfProtectionMatcher();
		if (requireCsrfProtectionMatcher != null) {
			filter.setRequireCsrfProtectionMatcher(requireCsrfProtectionMatcher);
		}
		// 设置拒绝策略
		AccessDeniedHandler accessDeniedHandler = createAccessDeniedHandler(http);
		if (accessDeniedHandler != null) {
			filter.setAccessDeniedHandler(accessDeniedHandler);
		}
		// 设置Logout和Session
		LogoutConfigurer<H> logoutConfigurer = http.getConfigurer(LogoutConfigurer.class);
		if (logoutConfigurer != null) {
			logoutConfigurer
					.addLogoutHandler(new CsrfLogoutHandler(this.csrfTokenRepository));
		}
		SessionManagementConfigurer<H> sessionConfigurer = http
				.getConfigurer(SessionManagementConfigurer.class);
		if (sessionConfigurer != null) {
			sessionConfigurer.addSessionAuthenticationStrategy(
					new CsrfAuthenticationStrategy(this.csrfTokenRepository));
		}
		filter = postProcess(filter);
		http.addFilter(filter);
	}
	
	private RequestMatcher getRequireCsrfProtectionMatcher() {
		if (this.ignoredCsrfProtectionMatchers.isEmpty()) {
			return this.requireCsrfProtectionMatcher;
		}
		// 如果ignoredCsrfProtectionMatchers不为空,则将requireCsrfProtectionMatcher和ignoredCsrfProtectionMatchers合并,requireCsrfProtectionMatcher中定义了不需要拦截的方法"GET", "HEAD", "TRACE", "OPTIONS"
		// NegatedRequestMatcher相当去取反;
		// AndRequestMatcher只要一个为假,则返回false;
		// OrRequestMatcher只要一个为真,则返回true;
		return new AndRequestMatcher(this.requireCsrfProtectionMatcher,
				new NegatedRequestMatcher(
						new OrRequestMatcher(this.ignoredCsrfProtectionMatchers)));
	}
}

CsrfFilter

  1. 先从持久化容器中获取Cookie,如果持久化容器中不包含,则创建一个
  2. 从请求头中获取csrf信息,如果没有则从请求参数中获取
  3. 如果从持久化中和从请求中获取的不一致,则抛出异常信息
public final class CsrfFilter extends OncePerRequestFilter {
	@Override
	protected void doFilterInternal(HttpServletRequest request,
			HttpServletResponse response, FilterChain filterChain)
					throws ServletException, IOException {
		request.setAttribute(HttpServletResponse.class.getName(), response);

		// 先从持久化容器中获取
		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;
		}

		String 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);
	}
}

猜你喜欢

转载自blog.csdn.net/u010811939/article/details/89398033
今日推荐