关于什么是CSRF我这里就不多说了,以前转载的一篇文章(PS:https://www.zifangsky.cn/358.html)已经说得很清楚了。这里只是简单介绍如何在SpringMVC中使用拦截器拦截CSRF***。具体代码如下:

(1)登录页面:

<%@page import="java.security.SecureRandom"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>    



">
SpringMVC Cookie Demo
<%
	SecureRandom random = new SecureRandom();
	random.setSeed(8738);
	double _csrf = random.nextDouble();
	session.setAttribute("_csrf", _csrf);
%>


	
		

SpringMVC Cookie Demo

用户名:
密码:
30天内自动登录
" />

从上面的代码可知,为了防止CSRF***,因此在form表单里添加了一个隐藏字段“_csrf”,其值是生成的一个随机小数

(2)在SpringMVC的配置文件中添加拦截器:



	
	
	
	
			
	
	
	
	
	
	
		
			
			
			
		
		
			
			
			
		
	
	
	
	
		
		
	

从上面的代码知道,在这个文件中添加了一个 mvc:interceptors 标签,表示一系列的拦截器集合,然后下面定义了对登录时form表单提交地址“/check.html”进行拦截。下面一行的bean属性就是定义了自定义拦截器的类所在的路径

注:后面那个拦截器这里不用管,我在写后面的文章时才会用到

(3)自定义拦截器LoginInterceptor:

package cn.zifangsky.interceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.apache.commons.lang3.StringUtils;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

public class LoginInterceptor extends HandlerInterceptorAdapter {
	/**
	 * 用于在登录前验证 _csrf 参数
	 * */
	public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
			throws Exception {
		HttpSession session = request.getSession();
		String _csrfByForm = request.getParameter("_csrf");  //表单中的值
		String _csrfBySession = String.valueOf(session.getAttribute("_csrf"));  //session中的值
		session.removeAttribute("_csrf");  //使用之后从session中删掉

		//验证是否存在CSRF***
		if(StringUtils.isNotBlank(_csrfByForm) && StringUtils.isNotBlank(_csrfBySession) && _csrfByForm.equals(_csrfBySession)){
			return true;
		}else{
			response.setContentType("text/html;charset=utf-8");
			response.setStatus(403);

			//页面友好提示信息
			OutputStream oStream = response.getOutputStream();
			oStream.write("请不要重复提交请求,返回原始页面刷新后再次尝试!!!".getBytes("UTF-8"));
			
			return false;
		}		
	}

	public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
			throws Exception {
		super.afterCompletion(request, response, handler, ex);
	}

}

这个自定义拦截器的逻辑很简单,就是把form表单隐藏域“_csrf”中的值和session中的“_csrf”值进行比较。如果二者相同,则说明该请求是从前台form表单中传进来的,而不是其他网站的伪造请求(PS:因为这种方式没法向session中定义“_csrf”参数);同时也防止form表单的重复提交(PS:因为第一次验证过后session中的“_csrf”就已经被移除了,除非前台刷新页面才会重新生成),避免了爆破撞库等安全隐患。当然,为了进一步降低安全隐患,这里的form表单还应该添加复杂的动态验证码。我这里是由于为了让示例更简洁,因此就把这一步给省略了

(4)验证:

第一次提交表单,发现可以正常到达后台进行验证

第二次点击浏览器的“返回键”,返回到表单页面之后重复提交,可以发现直接被拦截了。效果如下:

在SpringMVC中使用拦截器(interceptor)拦截CSRF***_第1张图片

PS:上面图片中的水印是我个人博客的域名,因此还请管理员手下留情不要给我标为“转载文章”,谢谢!!!