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 ...
随机推荐
- pandas使用的25个技巧
本文翻译自https://nbviewer.jupyter.org/github/justmarkham/pandas-videos/blob/master/top_25_pandas_trick ...
- Tarjan算法——强连通、双连通、割点、桥
Tarjan算法 概念区分 有向图 强连通:在有向图\(G\)中,如果两个顶点\(u, v\ (u \neq v)\)间有一条从\(u\)到\(v\)的有向路径,同时还有一条从\(v\)到\(u\)的 ...
- vcs/verdi filist
. 现在很多verilog 的filelist 文件中用如下形式来指定文件所在的目录就行了,而不必指定具体文件 ./testbench/ppc460_PLB4/p464s_test_top_tb.v ...
- Face-anti-spoofing实验记录(通过val_public_list.txt制作val数据集)
https://sites.google.com/qq.com/chalearnfacespoofingattackdete/contest-details 数据集官方获取网站 网友总结 https: ...
- ELK:收集k8s容器日志最佳实践
简介 关于日志收集这个主题,这已经是第三篇了,为什么一再研究这个课题,因为这个课题实在太重要,而当今优秀的开源解决方案还不是很明朗: 就docker微服务化而言,研发有需求标准输出,也有需求文件输出, ...
- 题解 CSP2019-J2T4【加工零件】
这题我们要求的是啥呢?仔细读题可以发现,工人传送带的关系可以看成一个 \(n\) 个点和 \(m\) 条边的无向图,然后对于每组询问 \((a,L)\),其实就是问: \(1\) 到 \(a\) 有没 ...
- ionic中的http,jsonp的使用
要导入 import { HttpModule,JsonpModule } from '@angular/http'; 到app.module.ts http,jsonp的区别 第一:在U ...
- Redis(九):主从复制的设计与实现解析
前面几篇我们已经完全理解了redis的基本功能的实现了. 但单靠基本功能实现,往往还是称不上优秀的项目的.毕竟,我们现在面对的都是复杂的环境,高并发的场景,大数据量的可能. 简而言之,现在的系统一般都 ...
- 你知道EasyX吗
关于C++控制台上的图形界面,你知道一个东西叫做EasyX吗? 作为一个退役的OI选手(WTF?\(3^2-3^1\)年级退役?),在退役之后总想找点事情做. 开发个游戏?(我只会控制台) 学下人工智 ...
- linux入门系列12--磁盘管理之分区、格式化与挂载
前面系列文章讲解了VI编辑器.常用命令.防火墙及网络服务管理,本篇将讲解磁盘管理相关知识. 本文将会介绍大量的Linux命令,其中有一部分在"linux入门系列5--新手必会的linux命令 ...