CSRF漏洞攻击原理及其修复处理

攻击原理:问题网站A利用访问它的用户u,向以u为可信用户的其它网站B上发送请求,B网站认为请求来源于u,积极响应,这就导致了漏洞。
借助于spring框架的修复方式:在B网站的所有请求上都加上隐藏的token,通过请求携带的token是否与session中的token一致来判断是否请求来源是否可信。
实现:
工具类:用于获取session中的和请求携带的Token

public class CSRFTokenManager {

    //Token属性名称
    static final String CSRF_PARAM_NAME = "CSRF_SECURITY_TOKEN";
    private final static String CSRF_TOKEN_FOR_SESSION_ATTR_NAME = CSRFTokenManager.class
            .getName() + ".tokenval";

    private CSRFTokenManager() {
    }
    //从Session中获取Token
    static String getTokenForSession(HttpSession httpSession) {
        String token = null;
        synchronized (httpSession) {
            token = (String) httpSession
                    .getAttribute(CSRF_TOKEN_FOR_SESSION_ATTR_NAME);
            if (null == token) {
                token = UUID.randomUUID().toString();
                httpSession.setAttribute(CSRF_TOKEN_FOR_SESSION_ATTR_NAME,
                        token);
            }
        }
        return token;
    }
    //从request中获取token
    static String getTokenFromRequest(HttpServletRequest request) {
        return request.getParameter(CSRF_PARAM_NAME);
    }
    //从header中获取token
    static String getTokenFromHeader(HttpServletRequest request) {
        return request.getHeader(CSRF_PARAM_NAME);
    }
}

spring框架类,用于在前台使用<form:form/> 的form表单中添加隐藏的input框, 存放请求携带的token值,其name和值都可以在这个类中指定。

public class CSRFRequestDataValueProcessor implements RequestDataValueProcessor {
    @Override
    public String processAction(HttpServletRequest request, String action) {
        return action;
    }
    @Override
    public String processFormFieldValue(HttpServletRequest request,
            String name, String value, String type) {
        return value;
    }
    @Override
    public Map<String, String> getExtraHiddenFields(HttpServletRequest request) {
        Map<String, String> hiddenFields = new HashMap<String, String>();
        hiddenFields.put(CSRFTokenManager.CSRF_PARAM_NAME,
                CSRFTokenManager.getTokenForSession(request.getSession()));
        //这行代码指定了input框的name和value
        return hiddenFields;
    }
    @Override
    public String processUrl(HttpServletRequest request, String url) {
        return url;
    }
}

spring框架类:用于截取请求,判断请求携带的与session中token是否一致

public class CSRFHandlerInterceptor extends HandlerInterceptorAdapter {

    private static final Logger logger = Logger
            .getLogger(CSRFHandlerInterceptor.class);

    @Override
    public boolean preHandle(HttpServletRequest request,
            HttpServletResponse response, Object handler) throws Exception {

        String requestUrl;
        requestUrl = request.getRequestURL().toString();
        logger.info("the request url is :" + requestUrl);
        logger.info("the request method is:" + request.getMethod());

        String sessionToken = CSRFTokenManager
                        .getTokenForSession(request.getSession());

        String tokenSource = (String) request.getHeader("TOKEN_SOURCE");
        String requestToken;

        // from the SpringMVC form
        String requestToken4Form = CSRFTokenManager
                .getTokenFromRequest(request);

        // from the header
        String requestToken4Ajax = CSRFTokenManager
                .getTokenFromHeader(request);

        if (tokenSource != null && tokenSource.equals("AJAX")) {
            requestToken = requestToken4Ajax;
        } else {
            requestToken = requestToken4Form;
        }

        if (sessionToken.equals(requestToken)) {
            return true;
        }
        else{
            return false;
        }
    }
}

配置文件中添加:

<mvc:interceptors>
    <mvc:interceptor>
        <mvc:mapping path="" />
        <mvc:mapping path="" /><!-- 指定拦截路径,支持多个 -->
        <bean class="com.uncle5.pubrub.web.security.CsrfInterceptor" />
    </mvc:interceptor>        
</mvc:interceptors>

最后记得前端要使用spring的<form:form/>

你可能感兴趣的:(CSRF)