最近项目渗透测试检测出一些安全问题其中一项为csrf攻击隐患,然后开始修复

csrf简介

CSRF(Cross-site request forgery)跨站请求伪造,也被称为“One Click Attack”或者Session Riding,通常缩写为CSRF或者XSRF,是一种对网站的恶意利用。尽管听起来像跨站脚本(XSS),但它与XSS非常不同,XSS利用站点内的信任用户,而CSRF则通过伪装成受信任用户的请求来利用受信任的网站。与XSS攻击相比,CSRF攻击往往不大流行(因此对其进行防范的资源也相当稀少)和难以防范,所以被认为比XSS更具危险性。——百度百科

详细介绍:浅谈CSRF攻击方式 - hyddd - 博客园

一、maven pom.xml 引入jar包

        <dependency><groupId>org.springframework.security</groupId><artifactId>spring-security-web</artifactId><version>5.0.6.RELEASE</version></dependency><dependency><groupId>org.springframework.security</groupId><artifactId>spring-security-config</artifactId><version>5.0.6.RELEASE</version></dependency>

二、web.xml配置filter

mgmtCsrfFilter是我重写的csrfFilter名称

<!-- CSRF filter --><filter><filter-name>mgmtCsrfFilter</filter-name><filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class></filter><filter-mapping><filter-name>mgmtCsrfFilter</filter-name><url-pattern>/*</url-pattern></filter-mapping>

三、spring-application.xml配置

<bean id="mgmtCsrfFilter" class="com.haha.sps.mgmt.core.filter.MgmtCsrfFilter"><constructor-arg><bean class="org.springframework.security.web.csrf.HttpSessionCsrfTokenRepository" /></constructor-arg></bean><bean id="requestDataValueProcessor" class="org.springframework.security.web.servlet.support.csrf.CsrfRequestDataValueProcessor"></bean>

四、重写csrffilter

重写后的csrfFilter为MgmtCsrfFilter代码如下:

package com.haha.sps.mgmt.core.filter;import java.io.IOException;
import java.util.Arrays;
import java.util.HashSet;import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.security.web.access.AccessDeniedHandlerImpl;
import org.springframework.security.web.csrf.CsrfToken;
import org.springframework.security.web.csrf.CsrfTokenRepository;
import org.springframework.security.web.csrf.InvalidCsrfTokenException;
import org.springframework.security.web.csrf.MissingCsrfTokenException;
import org.springframework.security.web.util.UrlUtils;
import org.springframework.security.web.util.matcher.RegexRequestMatcher;
import org.springframework.security.web.util.matcher.RequestMatcher;
import org.springframework.util.Assert;
import org.springframework.web.filter.OncePerRequestFilter;/*** Rewrite  org.springframework.security.web.csrf.CsrfFilter * exclude user/doLogion method filter** @author Pente*/
public final class MgmtCsrfFilter extends OncePerRequestFilter {/*** The default {@link RequestMatcher} that indicates if CSRF protection is required or* not. The default is to ignore GET, HEAD, TRACE, OPTIONS and process all other* requests.*/public static final RequestMatcher DEFAULT_CSRF_MATCHER = new CsrfSecurityRequestMatcher();private final Log logger = LogFactory.getLog(getClass());private final CsrfTokenRepository tokenRepository;private RequestMatcher requireCsrfProtectionMatcher = DEFAULT_CSRF_MATCHER;private AccessDeniedHandler accessDeniedHandler = new AccessDeniedHandlerImpl();public MgmtCsrfFilter(CsrfTokenRepository csrfTokenRepository) {Assert.notNull(csrfTokenRepository, "csrfTokenRepository cannot be null");this.tokenRepository = csrfTokenRepository;}/** (non-Javadoc)** @see* org.springframework.web.filter.OncePerRequestFilter#doFilterInternal(javax.servlet* .http.HttpServletRequest, javax.servlet.http.HttpServletResponse,* javax.servlet.FilterChain)*/@Overrideprotected 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);}/*** Specifies a {@link RequestMatcher} that is used to determine if CSRF protection* should be applied. If the {@link RequestMatcher} returns true for a given request,* then CSRF protection is applied.** <p>* The default is to apply CSRF protection for any HTTP method other than GET, HEAD,* TRACE, OPTIONS.* </p>** @param requireCsrfProtectionMatcher the {@link RequestMatcher} used to determine if* CSRF protection should be applied.*/public void setRequireCsrfProtectionMatcher(RequestMatcher requireCsrfProtectionMatcher) {Assert.notNull(requireCsrfProtectionMatcher,"requireCsrfProtectionMatcher cannot be null");this.requireCsrfProtectionMatcher = requireCsrfProtectionMatcher;}/*** Specifies a {@link AccessDeniedHandler} that should be used when CSRF protection* fails.** <p>* The default is to use AccessDeniedHandlerImpl with no arguments.* </p>** @param accessDeniedHandler the {@link AccessDeniedHandler} to use*/public void setAccessDeniedHandler(AccessDeniedHandler accessDeniedHandler) {Assert.notNull(accessDeniedHandler, "accessDeniedHandler cannot be null");this.accessDeniedHandler = accessDeniedHandler;}/** exclude "user/doLogion"  "GET", "HEAD", "TRACE", "OPTIONS"*/private static final class CsrfSecurityRequestMatcher implements RequestMatcher {private RegexRequestMatcher unprotectedMatcher = new RegexRequestMatcher("^/user/doLogin", null);private final HashSet<String> allowedMethods = new HashSet<String>(Arrays.asList("GET", "HEAD", "TRACE", "OPTIONS"));/** (non-Javadoc)* @see* org.springframework.security.web.util.matcher.RequestMatcher#matches(javax.* servlet.http.HttpServletRequest)*/@Overridepublic boolean matches(HttpServletRequest request) {if(this.allowedMethods.contains(request.getMethod())){return false;}return !unprotectedMatcher.matches(request);}}
}

实现自定义过滤掉登录方法,主要是重写csrfFilter里的DefaultRequiresCsrfMatcher替换成自己写的CsrfSecurityRequestMatcher ,如下:

/** exclude "user/doLogion"  "GET", "HEAD", "TRACE", "OPTIONS"*/private static final class CsrfSecurityRequestMatcher implements RequestMatcher {private RegexRequestMatcher unprotectedMatcher = new RegexRequestMatcher("^/user/doLogin", null);private final HashSet<String> allowedMethods = new HashSet<String>(Arrays.asList("GET", "HEAD", "TRACE", "OPTIONS"));/** (non-Javadoc)* @see* org.springframework.security.web.util.matcher.RequestMatcher#matches(javax.* servlet.http.HttpServletRequest)*/@Overridepublic boolean matches(HttpServletRequest request) {if(this.allowedMethods.contains(request.getMethod())){return false;}return !unprotectedMatcher.matches(request);}}

五、页面配置

在post请求或ajax请求中会遇到问题,在公用jsp文件中加上,例如每个页面都会引用的头文件top.jsp

<meta name="_csrf" content="${_csrf.token}"/>
<meta name="_csrf_header" content="${_csrf.headerName}"/><script>var token = $("meta[name='_csrf']").attr("content");var header = $("meta[name='_csrf_header']").attr("content");$.ajaxSetup({beforeSend: function (xhr) {if(header && token ){xhr.setRequestHeader(header, token);}}});
// $(document).ajaxSend(function(e,xhr,opt){
//  xhr.setRequestHeader(header,token);
// });</script>

$.ajaxSetup的意思就是给我们所有的请求都加上这个header和token,或者放到form表单中。注意,_csrf这个要与spring security的配置文件中的配置相匹配,默认为_csrf

六、源码解析

看一下CsrfFilter中的doFilterInternal源码解析就知道我们为什么这么修改了

@Overrideprotected void doFilterInternal(HttpServletRequest request,HttpServletResponse response, FilterChain filterChain)throws ServletException, IOException {request.setAttribute(HttpServletResponse.class.getName(), response);// 先从tokenRepository中加载tokenCsrfToken csrfToken = this.tokenRepository.loadToken(request);final boolean missingToken = csrfToken == null;// 如果为空,则tokenRepository生成新的token,并保存到tokenRepository中if (missingToken) {csrfToken = this.tokenRepository.generateToken(request);this.tokenRepository.saveToken(csrfToken, request, response);}// 将token写入request的attribute中,方便页面上使用request.setAttribute(CsrfToken.class.getName(), csrfToken);request.setAttribute(csrfToken.getParameterName(), csrfToken);//这个macher就是我们在Spring配置文件中自定义的过滤器,也就是GET,HEAD, TRACE, OPTIONS和我们的rest都不处理// 这个macher就是我们在Spring配置文件中自定义的过滤器,//如果不需要csrf验证的请求,则直接下传请求(requireCsrfProtectionMatcher是默认的对象,对符合^(GET|HEAD|TRACE|OPTIONS)$的请求和我们自定义的请求不验证)if (!this.requireCsrfProtectionMatcher.matches(request)) {filterChain.doFilter(request, response);return;}// 从用户请求中获取token信息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);}

文章结构部分参考:利用spring-security解决CSRF问题_Frankenstein的博客-CSDN博客

《Java实战开发》利用spring-security解决CSRF问题,通过重写CsrfFilter 过滤掉指定方法相关推荐

  1. springsecurity sessionregistry session共享_要学就学透彻!Spring Security 中 CSRF 防御源码解析...

    今日干货 刚刚发表查看:66666回复:666 公众号后台回复 ssm,免费获取松哥纯手敲的 SSM 框架学习干货. 上篇文章松哥和大家聊了什么是 CSRF 攻击,以及 CSRF 攻击要如何防御.主要 ...

  2. 要学就学透彻!Spring Security 中 CSRF 防御源码解析

    上篇文章松哥和大家聊了什么是 CSRF 攻击,以及 CSRF 攻击要如何防御.主要和大家聊了 Spring Security 中处理该问题的几种办法. 今天松哥来和大家简单的看一下 Spring Se ...

  3. Spring Security 的 CSRF 的相关资料

    近期,因为需要研究 Spring Security 的安全机制,因为 Spring Security 说可以帮助避免 CSRF 攻击. 因此特地考古了相关的内容. 简单点解释就是 CSRF 盗用了你的 ...

  4. Spring Boot 项目使用Spring Security防护CSRF攻击实战

    Spring Boot与Spring Security Spring Boot项目结合Spring Security ,可以实现用户认证和用户授权. Spring Security的用户认证可以是配置 ...

  5. CSRF攻击的原理和spring security对CSRF攻击的解决方法

    对于CSRF攻击的原理,直接上图然后解释一下 一个用户通过浏览器成功登录一个网站,登陆成功后,服务器会返回一个该用户的唯一标识放入浏览器Cookie中,以此作为用户之后操作的唯一凭证.假设此时该用户在 ...

  6. 千锋教育威哥学Java——爆破专栏丨Spring Security系列教程之解决Spring Security环境中的跨域问题

    前言 上一章节中,一一哥 给各位讲解了同源策略和跨域问题,以及跨域问题的解决方案,在本篇文章中,我会带大家进行代码实现,看看在Spring Security环境中如何解决跨域问题. 需要更多教程,微信 ...

  7. Spring Boot实践 | 利用Spring Security快速搞定权限控制

    目录 开始之前 快速开始 使用内存签名服务 使用数据库签名服务 使用自定义签名服务 限制请求 强制使用HTTPS 防止跨站点伪造请求 用户认证功能 在java web工程中,一般使用Servlet过滤 ...

  8. Java认证授权框架Spring Security介绍

    Spring Security 是一个非常强大的身份验证和授权控制框架.为了满足企业项目的不同需求,它提供了很多定制化开发的解决方案,通过简单的调整配置,就能为我们的应用提供一套可靠的安全保障.本节课 ...

  9. Spring Boot+Vue/前后端分离/高并发/秒杀实战课程之spring Security快速搭建oauth2 内存版身份认证

    Springboot快速搭建oauth2 内存版身份认证 环境准备 点击[Create New Project]创建一个新的项目 项目环境配置 配置Thymeleaf 搭建oauth2认证,加入两个依 ...

最新文章

  1. python中空格字符是什么_关于Python中空格字符串处理的技巧总结
  2. 使用二进制的方式安装mysql实践纪要
  3. 0-1语言建模当中会遇到的问题
  4. 组合总和(可重复使用)Python解法
  5. python deepcopy报错_python 字典对象赋值之deepcopy遭遇的问题及解决过程(lxml惹的祸)...
  6. 电脑鸿蒙运行Linux程序,Linux下的Hi3861一站式鸿蒙开发烧录(附工具)-鸿蒙开发烧录工具软件电脑版-东坡下载...
  7. 导师推荐 | 第 4 期临床基因组家系分析,同时解决科研和临床问题
  8. 【MyBatis笔记】11-分步查询懒加载
  9. pycharm pip安装_Python从入门到大师教程 | 一、搭建Python环境和安装Pycharm
  10. 【翻译】Robust Lane Detection and Tracking in Challenging Scenarios
  11. 螺旋数字的python实现
  12. AR引擎vuforia源码分析、中文注释(1)
  13. 30种EMC标准电路分享,再不收藏就晚了!
  14. gRPC python封装深度学习算法教程
  15. 图像加密之灰度加密:基于 密钥 × 解钥 ≡ 1 mod 灰度级 的一轮加密算法例子——lena图
  16. python3爬取网易云歌曲,利用python3爬取网易云周杰伦所有专辑,歌曲,评论,并完成可视-站长资讯中心...
  17. 【Python实战项目】做一个 刮刮乐 案例,一不小心....着实惊艳到我了。
  18. 读书笔记10 《蔡康永的说话之道1》 蔡康永
  19. 漫画:大公司病了,这也太形象了吧!!!
  20. [WDS] Disconnected解决方法

热门文章

  1. 告诉你为什么要懂电机控制
  2. linux dwm 中文输入法,我最近在dwm上安装中文输入法fcitx。但是遇到了一些问题。...
  3. 计算机毕业设计ssm电商后台系统c83si系统+程序+源码+lw+远程部署
  4. Cordova 扫码插件整理-cordova-plugin-qrscanner
  5. Android类似于桌面360小球加速效果
  6. 社群运营必备的5大技巧和工具,请收下
  7. 向浙江股友推荐一匹家门口的黑马...................................
  8. 航天器动力学建模笔记
  9. 米拓模板:家电行业网站模板推荐
  10. 软件测试_BadBoy自动化测试工具2_录制脚本