Spring mvc拦截器防御CSRF攻击
CSRF(Cross-site request forgery跨站请求伪造,也被称为“One Click Attack”或者Session Riding,通常缩写为CSRF或者XSRF,是一种对网站的恶意利用。尽管听起来像跨站脚本(XSS),但它与XSS非常不同,并且攻击方式几乎相左。XSS利用站点内的信任用户,而CSRF则通过伪装来自受信任用户的请求来利用受信任的网站。与XSS攻击相比,CSRF攻击往往不大流行(因此对其进行防范的资源也相当稀少)和难以防范,所以被认为比XSS更具危险性。
具体思路:
1、跳转页面前生成随机token,并存放在session中
2、form中将token放在隐藏域中,保存时将token放头部一起提交
3、获取头部token,与session中的token比较,一致则通过,否则不予提交
4、生成新的token,并传给前端
1、拦截器配置
<mvc:interceptors>
<!-- csrf攻击防御 -->
<mvc:interceptor>
<!-- 需拦截的地址 -->
<mvc:mapping path="/**" />
<!-- 需排除拦截的地址 -->
<mvc:exclude-mapping path="/resources/**" />
<bean class="com.cnpc.framework.interceptor.CSRFInterceptor" />
</mvc:interceptor>
</mvc:interceptors>
2拦截器实现 CSRFInterceptor.java
package com.cnpc.framework.interceptor; import java.io.OutputStream;
import java.io.PrintWriter;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter; import com.alibaba.fastjson.JSONObject;
import com.cnpc.framework.annotation.RefreshCSRFToken;
import com.cnpc.framework.annotation.VerifyCSRFToken;
import com.cnpc.framework.base.pojo.ResultCode;
import com.cnpc.framework.constant.CodeConstant;
import com.cnpc.framework.utils.CSRFTokenUtil;
import com.cnpc.framework.utils.StrUtil; /**
* CSRFInterceptor 防止跨站请求伪造拦截器
*
* @author billJiang 2016年10月6日 下午8:14:40
*/
public class CSRFInterceptor extends HandlerInterceptorAdapter { @Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { System.out.println("---------->" + request.getRequestURI());
System.out.println(request.getHeader("X-Requested-With"));
// 提交表单token 校验
HandlerMethod handlerMethod = (HandlerMethod) handler;
Method method = handlerMethod.getMethod();
VerifyCSRFToken verifyCSRFToken = method.getAnnotation(VerifyCSRFToken.class);
// 如果配置了校验csrf token校验,则校验
if (verifyCSRFToken != null) {
// 是否为Ajax标志
String xrq = request.getHeader("X-Requested-With");
// 非法的跨站请求校验
if (verifyCSRFToken.verify() && !verifyCSRFToken(request)) {
if (StrUtil.isEmpty(xrq)) {
// form表单提交,url get方式,刷新csrftoken并跳转提示页面
String csrftoken = CSRFTokenUtil.generate(request);
request.getSession().setAttribute("CSRFToken", csrftoken);
response.setContentType("application/json;charset=UTF-8");
PrintWriter out = response.getWriter();
out.print("非法请求");
response.flushBuffer();
return false;
} else {
// 刷新CSRFToken,返回错误码,用于ajax处理,可自定义
String csrftoken = CSRFTokenUtil.generate(request);
request.getSession().setAttribute("CSRFToken", csrftoken);
ResultCode rc = CodeConstant.CSRF_ERROR;
response.setContentType("application/json;charset=UTF-8");
PrintWriter out = response.getWriter();
out.print(JSONObject.toJSONString(rc));
response.flushBuffer();
return false;
}
} }
return true;
} @Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView)
throws Exception { // 第一次生成token
if (modelAndView != null) {
if (request.getSession(false) == null || StrUtil.isEmpty((String) request.getSession(false).getAttribute("CSRFToken"))) {
request.getSession().setAttribute("CSRFToken", CSRFTokenUtil.generate(request));
return;
}
}
// 刷新token
HandlerMethod handlerMethod = (HandlerMethod) handler;
Method method = handlerMethod.getMethod();
RefreshCSRFToken refreshAnnotation = method.getAnnotation(RefreshCSRFToken.class); // 跳转到一个新页面 刷新token
String xrq = request.getHeader("X-Requested-With");
if (refreshAnnotation != null && refreshAnnotation.refresh() && StrUtil.isEmpty(xrq)) {
request.getSession().setAttribute("CSRFToken", CSRFTokenUtil.generate(request));
return;
} // 校验成功 刷新token 可以防止重复提交
VerifyCSRFToken verifyAnnotation = method.getAnnotation(VerifyCSRFToken.class);
if (verifyAnnotation != null) {
if (verifyAnnotation.verify()) {
if (StrUtil.isEmpty(xrq)) {
request.getSession().setAttribute("CSRFToken", CSRFTokenUtil.generate(request));
} else {
Map<String, String> map = new HashMap<String, String>();
map.put("CSRFToken", CSRFTokenUtil.generate(request));
response.setContentType("application/json;charset=UTF-8");
OutputStream out = response.getOutputStream();
out.write((",'csrf':" + JSONObject.toJSONString(map) + "}").getBytes("UTF-8"));
}
}
}
} /**
* 处理跨站请求伪造 针对需要登录后才能处理的请求,验证CSRFToken校验
*
* @param request
*/
protected boolean verifyCSRFToken(HttpServletRequest request) { // 请求中的CSRFToken
String requstCSRFToken = request.getHeader("CSRFToken");
if (StrUtil.isEmpty(requstCSRFToken)) {
return false;
}
String sessionCSRFToken = (String) request.getSession().getAttribute("CSRFToken");
if (StrUtil.isEmpty(sessionCSRFToken)) {
return false;
}
return requstCSRFToken.equals(sessionCSRFToken);
}
}
3.CSRFTokenUtil.java 生成随机系列号
package com.cnpc.framework.utils;
import java.util.UUID;
import javax.servlet.http.HttpServletRequest;
public class CSRFTokenUtil {
public static String generate(HttpServletRequest request) {
return UUID.randomUUID().toString();
}
}
4、ResultCode
package com.cnpc.framework.base.pojo;
public class ResultCode {
private String code;
private String message;
public ResultCode(String code, String message) {
this.code = code;
this.message = message;
}
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}
5、CodeConstant.java
package com.cnpc.framework.constant;
import com.cnpc.framework.base.pojo.ResultCode;
public class CodeConstant {
public final static ResultCode CSRF_ERROR = new ResultCode("101", "CSRF ERROR:无效的token,或者token过期");
}
6、ajax提交方法
function ajaxPost(url, params, callback) {
var result = null;
var headers={};
headers['CSRFToken']=$("#csrftoken").val();
$.ajax({
type : 'post',
async : false,
url : url,
data : params,
dataType : 'json',
headers:headers,
success : function(data, status) {
result = data;
if(data&&data.code&&data.code=='101'){
modals.error("操作失败,请刷新重试,具体错误:"+data.message);
return false;
}
if (callback) {
callback.call(this, data, status);
}
},
error : function(err, err1, err2) {
if(err && err.readyState && err.readyState == '4'){
var responseBody = err.responseText;
if(responseBody){
responseBody = "{'retData':"+responseBody;
var resJson = eval('(' + responseBody + ')');
$("#csrftoken").val(resJson.csrf.CSRFToken);
this.success(resJson.retData, 200);
}
return ;
}
modals.error({
text : JSON.stringify(err) + '<br/>err1:' + JSON.stringify(err1) + '<br/>err2:' + JSON.stringify(err2),
large : true
});
}
});
return result;
}
7、form表单配置
<input type='hidden' value='${CSRFToken}' id='csrftoken'>
8、注解定义
package com.cnpc.framework.annotation; import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target; /**
* 跨站请求仿照注解 刷新CSRFToken
*
*/
@Target({ java.lang.annotation.ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
public @interface RefreshCSRFToken { /**
* 刷新token
*
* @return
*/
public abstract boolean refresh() default true;
}
9、注解配置
@RefreshCSRFToken
@RequestMapping(method = RequestMethod.GET, value = "/edit")
private String edit(String id, HttpServletRequest request) { request.setAttribute("id", id);
return "base/user/user_edit";
} @RequestMapping(method = RequestMethod.POST, value = "/get")
@ResponseBody
private User getUser(String id) { return userService.get(User.class, id);
}
Spring mvc拦截器防御CSRF攻击的更多相关文章
- SSM(spring mvc+spring+mybatis)学习路径——2-2、spring MVC拦截器
目录 2-2 Spring MVC拦截器 第一章 概述 第二章 Spring mvc拦截器的实现 2-1 拦截器的工作原理 2-2 拦截器的实现 2-3 拦截器的方法介绍 2-4 多个拦截器应用 2- ...
- spring mvc 拦截器的使用
Spring MVC 拦截器的使用 拦截器简介 Spring MVC 中的拦截器(Interceptor)类似于 Servler 中的过滤器(Filter).用于对处理器进行预处理和后处理.常用于日志 ...
- 【Java Web开发学习】Spring MVC 拦截器HandlerInterceptor
[Java Web开发学习]Spring MVC 拦截器HandlerInterceptor 转载:https://www.cnblogs.com/yangchongxing/p/9324119.ht ...
- Spring Boot 2.X(九):Spring MVC - 拦截器(Interceptor)
拦截器 1.简介 Spring MVC 中的拦截器(Interceptor)类似于 Servlet 开发中的过滤器 Filter,它主要用于拦截用户请求并作相应的处理,它也是 AOP 编程思想的体现, ...
- Spring MVC拦截器配置
Spring MVC拦截器配置 (1)自定义拦截器 package learnspringboot.xiao.other; import org.springframework.web.servlet ...
- 写的太细了!Spring MVC拦截器的应用,建议收藏再看!
Spring MVC拦截器 拦截器是Spring MVC中强大的控件,它可以在进入处理器之前做一些操作,或者在处理器完成后进行操作,甚至是在渲染视图后进行操作. 拦截器概述 对于任何优秀的MVC框架, ...
- 对于Spring MVC 拦截器的一些了解
Spring MVC 拦截器的执行顺序 应用场景 假设请求 localhost:8080/ 则要求直接重定向到 localhost:8080/login ; 定义拦截器顺序 permission lo ...
- Spring MVC拦截器浅析
Spring MVC拦截器 重点:Spring MVC的拦截器只会拦截控制器的请求,如果是jsp.js.image.html则会放行. 什么是拦截器 运行在服务器的程序,先于Servlet或JSP之前 ...
- spring MVC拦截器01
spring MVC拦截 作用:身份校验,权限检查,防止非法訪问. 场景:一个bbs系统,用户没有登录就无法发帖或者删除评论; 一个博客系统,没有登录就无法发表博文,无法添加分类,无法删除博文. sp ...
随机推荐
- NLP(二十)利用BERT实现文本二分类
在我们进行事件抽取的时候,我们需要触发词来确定是否属于某个特定的事件类型,比如我们以政治上的出访类事件为例,这类事件往往会出现"访问"这个词语,但是仅仅通过"访问&q ...
- CLion在项目里编译不同文件
1. 在完整的项目下找到CMakeList.txt(项目配置文件) 2. Build 和 Run的目标在add_executable参数中 3. 将其修改为如下格式:add_executable(pr ...
- Codeforces_723_D
http://codeforces.com/problemset/problem/723/D dfs找出每个湖,保存坐标和大小,按大小排序,填充湖即可,注意湖的数量最多会有1250个. #includ ...
- HDU_2446_打表
http://acm.hdu.edu.cn/showproblem.php?pid=2446 打表,二分查找,注意查找最后的判断. #include<cstdio> #define N 2 ...
- Codeforces 977B Two-gram(stl之string掉进坑)
Two-gram is an ordered pair (i.e. string of length two) of capital Latin letters. For example, " ...
- 初学maven的一些配置
初学Maven的一些配置 1.maven的安装 2.从官网下载3.6.1版本后,高级版本可能会出现不兼容 jdk1.8 3.配置maven 在 settings.xml <settings> ...
- java服务器端线程体会
一个完整的项目包括服务器和客服端 服务器端初步编写: (1) 服务器端应用窗口的编写 (服务器类Server): 包括窗口和组件的一些设置, 添加一些客服端的元素,如客服端在线用户表(Vector), ...
- 二狗子 、初恋及HTTPS
最近二狗子宅在老家,最悠闲的就是泡壶茶看着院子的风景发呆一下午.今天,二狗子看到了对面自己暗恋的小翠花,看着美好的小翠花二狗子不禁想起了自己美好的初恋. 二狗子的初恋在初中,那个时候学校禁止带手机.上 ...
- java虚拟机jvm启动后java代码层面发生了什么?
java虚拟机jvm启动后java代码层面发生了什么? 0000 我想验证的事情 java代码在被编译后可以被jdk提供的java命令进行加载和运行, 在我们的程序被运行起来的时候,都发生了什么事情, ...
- 跨域的两种解决方法jsonp和CORS
1.跨域 什么是跨域? 当你请求的url是不同源的数据的时候,浏览器一般会抛出请求跨域的错误,如下图: 造成跨域的原因? 即你违反了浏览器的同源策略的限制=>阻止一个域的js脚本和另外一个域的内 ...