csrf漏洞java防御,Spring3.x通过配置来防范csrf攻击

CsrfTokenManager 用于管理csrfToken相关

package com.web.common;

import java.util.UUID;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpSession;

public final class CsrfTokenManager {

// 隐藏域参数名称

static final String CSRF_PARAM_NAME = "CSRFToken";

// session中csrfToken参数名称

public static final String CSRF_TOKEN_FOR_SESSION_ATTR_NAME = CsrfTokenManager.class

.getName() + ".tokenval";

private CsrfTokenManager() {

};

// 在session中创建csrfToken

public static String createTokenForSession(HttpSession session) {

String token = null;

synchronized (session) {

token = (String) session

.getAttribute(CSRF_TOKEN_FOR_SESSION_ATTR_NAME);

if (null == token) {

token = UUID.randomUUID().toString();

session.setAttribute(CSRF_TOKEN_FOR_SESSION_ATTR_NAME, token);

}

}

return token;

}

public static String getTokenFromRequest(HttpServletRequest request) {

return request.getParameter(CSRF_PARAM_NAME);

}

}

CsrfRequestDataValueProcessor 自动创建hidden的csrfToken域的类 package com.web.common;

import java.util.Map;

import javax.servlet.http.HttpServletRequest;

import org.springframework.stereotype.Component;

import org.springframework.web.servlet.support.RequestDataValueProcessor;

import com.google.common.collect.Maps;

@Component("requestDataValueProcessor")

public class CsrfRequestDataValueProcessor implements RequestDataValueProcessor {

@Override

public String processAction(HttpServletRequest request, String action) {

// TODO 暂时原样返回action

return action;

}

@Override

public String processFormFieldValue(HttpServletRequest request,

String name, String value, String type) {

// TODO 暂时原样返回value

return value;

}

@Override

public Map getExtraHiddenFields(HttpServletRequest request) {

//此处是当使用spring的taglib标签

创建表单时候,增加的隐藏域参数

Map hiddenFields = Maps.newHashMap();

hiddenFields.put(CsrfTokenManager.CSRF_PARAM_NAME,

CsrfTokenManager.createTokenForSession(request.getSession()));

return hiddenFields;

}

@Override

public String processUrl(HttpServletRequest request, String url) {

// TODO 暂时原样返回url

return url;

}

}

CsrfInterceptor 对于post请求进行拦截,检测csrfToken是否匹配

package com.web.security;

import java.net.URLEncoder;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;

import org.slf4j.Logger;

import org.slf4j.LoggerFactory;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.util.StringUtils;

import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

import com.web.common.CsrfTokenManager;

import com.web.common.WebUser;

public class CsrfInterceptor extends HandlerInterceptorAdapter {

private static final Logger logger = LoggerFactory

.getLogger(CsrfInterceptor.class);

@Autowired

WebUser webUser;

@Override

public boolean preHandle(HttpServletRequest request,

HttpServletResponse response, Object handler) throws Exception {

if ("POST".equalsIgnoreCase(request.getMethod())) {

String CsrfToken = CsrfTokenManager.getTokenFromRequest(request);

if (CsrfToken == null

|| !CsrfToken.equals(request.getSession().getAttribute(

CsrfTokenManager.CSRF_TOKEN_FOR_SESSION_ATTR_NAME))) {

String reLoginUrl = "/login?backurl="

+ URLEncoder.encode(getCurrentUrl(request), "utf-8");

response.sendRedirect(reLoginUrl);

return false;

}

}

return true;

}

private String getCurrentUrl(HttpServletRequest request) {

String currentUrl = request.getRequestURL().toString();

if (!StringUtils.isEmpty(request.getQueryString())) {

currentUrl += "?" + request.getQueryString();

}

return currentUrl;

}

}

springMVC 配置文件,增加需要进行拦截的url

jsp页面,需要注意的是必须使用spring的form标签

标题:

jsp页面 查看源码会发现已经添加上了hidden字段

标题:

1.只有当使用spring的form标签时候,才会在渲染jsp页面时候触发

org.springframework.web.servlet.tags.form.FormTag 类中的

@Override

public int doEndTag() throws JspException {

RequestDataValueProcessor processor = getRequestContext().getRequestDataValueProcessor();

ServletRequest request = this.pageContext.getRequest();

if ((processor != null) && (request instanceof HttpServletRequest)) {

writeHiddenFields(processor.getExtraHiddenFields((HttpServletRequest) request));

}

this.tagWriter.endTag();

return EVAL_PAGE;

}

该方法会调用上文中所说的CsrfRequestDataValueProcessor中的创建隐藏域的方法getExtraHiddenFields来创建csrfToken隐藏域。

2.对相关需要进行防范csrf攻击的post请求地址进行拦截,此处是依赖springMVC中提供的拦截器机制来操作的

当用户访问"/forum/post"这个请求时候,会直接进入CsrfInterceptor的preHandle方法,此处针对post请求进行了判断,如果从request中获取的csrfToken不存在或者与session中的csrfToken不相匹配,那么可以不进行后续流程,至于返回404还是返回到登录页面,就随便作者了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值