CSRF攻击防范

 CSRF全称:(Cross-site request forgery)跨域请求伪造
理解CSRF攻击:攻击者盗用了你的身份,以你的名义发送恶意请求
对于CSRF概念的理解:http://www.cnblogs.com/hyddd/archive/2009/04/09/1432744.html
以下是自己的总结与实现方式(拦截器实现):
CSRF攻击必须依次完成以下两个条件:
 1.登录受信任网站A,并在本地生成Cookie。
  2.在不登出A的情况下,访问危险网站B。

关闭浏览器不能结束一个会话,但大多数人都会错误的认为关闭浏览器就等于退出登录/结束会话了

CSRF攻击形成的原因:
1.网站违反了HTTP协议,使用GET请求更新资源(非常危险).
2.使用无校验的表单

CSRF攻击是源于WEB的隐式身份验证机制!(比如你在A网站登录后,在同一个浏览器的tab页打开B网站网页, 而B网站网页有一些脚本链接到A网站并偷偷的发送请求更新你账号的信息.如果没有防CSRF攻击,这样是可以实现的.)
WEB的身份验证机制虽然可以保证一个请求是来自于某个用户的浏览器,但却无法保证该请求是用户批准发送的!

CSRF防范方式:客户端页面增加伪随机数。每次需要修改该用户的数据库信息时必须带上该随机数,否则不受理.

解决办法: 在Form表单加一个hidden field,里面是服务端生成的足够随机数的一个Token(恶意网站猜不到也无法获取到相同的Token), 然后使用一个拦截器interceptor来检查每一个非get请求, 看该token与服务器token是否一致,不一致的不受理该请求.
以下是token 的工具管理类:

package com.xxx.xxx.util;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.util.UUID;


/**
 * CSRFtoken管理类
 *
 * @author 作者  yss
 * @version 版本号 v1.0
 */
public final class CSRFTokenManager {


    /**
     * 约定规范:表单提交时的token的input的name属性必须为该值才能获取到后台返回的token。
     * 下面是使用EL表达式接收从后台返回的token参数
     * 如: <input type="hidden" id="CSRFToken" value="${CSRFToken}">
     */
    public static final String CSRF_PARAM_NAME = "CSRFToken";

    /**
     * 存放在session中的token名称(跟上面的name属性值不一定一样)
     */
    public static final String CSRF_TOKEN_FOR_SESSION_ATTR_NAME = CSRFTokenManager.class.getName() + ".tokenval";

    /**
     *从session中获取token字符串
     * @param session
     * @return
     */
    public static String getTokenForSession(HttpSession session) {
        String token = null;
        //保证session只存在一个token,避免多线程情况下产生冲突。
        synchronized (session) {
            token = (String) session.getAttribute(CSRF_TOKEN_FOR_SESSION_ATTR_NAME);//尝试获取session中的token
            if (null == token) {//如果session中没有token,就重新生成一个token
                token = UUID.randomUUID().toString();
                session.setAttribute(CSRF_TOKEN_FOR_SESSION_ATTR_NAME, token);
            }
        }
        return token;
    }

    /**
     *获取到request中的token值。
     * @param request
     * @return
     */

    public static String getTokenFromRequest(HttpServletRequest request) {
        return request.getParameter(CSRF_PARAM_NAME);
    }
//构造器
    private CSRFTokenManager() {
    }
}

后台返回token参数给页面:

String token = CSRFTokenManager.getTokenForSession(request.getSession());//uuid生成的随机token
modelAndView.addObject(CSRFTokenManager.CSRF_PARAM_NAME, token);//添加token参数

页面使用隐藏域保存起来:

 <input type="hidden" id="CSRFToken" value="${CSRFToken}"><%--token--%>

编写代码要符合HTTP规范,不要使用GET请求更新资源
在非GET请求中带上token 参数(ajax请求也要),然后使用拦截器检查.
(对于受到CSRF攻击我使用的是抛自定义异常,然后使用springmvc全局异常进行处理,您如果想了解springmvc全局异常处理可以看我博客.)

package com.xxx.xxx.interceptor;

import com.xxx.xxx.exception.CSRFException;
import com.xxx.xxx.util.CSRFTokenManager;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

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

/**
 * 对于未登录用户的请求进行拦截,确保用户已经登录,然后进行后续的网页请求
 *
 * @Author yss
 * @Version 1.0
 * @see
 */
public class CSRFInterceptor extends HandlerInterceptorAdapter {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
//        Enumeration parasm = request.getParameterNames();
        if (!"GET".equals(request.getMethod())) {//非get请求
            String CSRFToken = CSRFTokenManager.getTokenFromRequest(request);//页面传过来的csrf参数
            if (CSRFToken == null || !CSRFToken.equals(CSRFTokenManager.getTokenForSession(request.getSession()))) {//token不对应
                throw new CSRFException("CSRF攻击");//抛异常后将会进入springmvc全局异常处理体系
            }
        }
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        super.postHandle(request, response, handler, modelAndView);
    }
}

在spring的配置文件中添加拦截器使其生效

    <mvc:interceptors>
        <!-- 防止CSRF攻击的拦截器 -->
        <mvc:interceptor>
            <mvc:mapping path="/**"/>
            <bean id="CSRFInterceptor" class="com.xxx.xxx.interceptor.CSRFInterceptor"></bean>
        </mvc:interceptor>
    </mvc:interceptors>

有问题欢迎留言. 相互探讨相互学习.

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值