csrfToken校验机制

最近集团进行安全检查,自己接手的老应用被扫出了很多安全隐患,最主要的安全隐患是csrfToken校验隐患。趁着这次机会,熟悉一下webx的csrfToken校验机制。 新的csrfToken(com.alibaba.webx3.migration.china.csrf.pull.ChinaCsrfToken)校验的做法是:

1、从HttpServletRequest中拿到TurbineRunData

    public static TurbineRunData getTurbineRunData(HttpServletRequest request, boolean create) {
        TurbineRunData rundata = (TurbineRunData) request.getAttribute(TURBINE_RUNDATA_KEY);
        if (rundata == null && create) {
            rundata = new TurbineRunDataImpl(request);
            request.setAttribute(TURBINE_RUNDATA_KEY, rundata);
        }
        return assertNotNull(rundata, "TurbineRunData not found in request attributes");
    }

2、拿到TurbineRunData之后,先根据DEFAULT_TOKEN_KEY从request中获取的csrfToken(fromRequest),并判空,如果为空,则csrfToken失效,返回false。

    HttpSession session = httpServletRequest.getSession();
        String fromSession = StringUtil.trimToNull((String) session.getAttribute(DEFAULT_TOKEN_KEY));
        if (fromSession == null) {
            printLogger(securityLogger, LoggerType.SESSION_IS_NULL,     httpServletRequest.getRemoteAddr(), null, null);
            return false;
        }

3、接下来从session中获取csrfToken,判断session中的csrfToken是否存在切是否过期,超过24小时则过期,返回false。

   private static boolean isExpire(Logger logger, String tokenOfSession) {
        long longValue = 0L;
        try {
            longValue = Long.parseLong(tokenOfSession);
        } catch (NumberFormatException e) {
            if (logger.isInfoEnabled()) {
                logger.info("parse long error! tokenOfSession=" + tokenOfSession);
            }
            return true;
        }
        long nowValue = System.currentTimeMillis();
        long tmp = nowValue - longValue;
        //当前时间小于token的时间,过期
        if (tmp < 0L) {
            return true;
        }
        //当前时间大于token 24小时,过期
        return tmp > 24L * 60 * 60 * 1000;
    }

4、接下来对session中获取的csrfToken(fromSession)进行MD5加密

    private static String hex(String value) {
        if (value == null) {
            return null;
        }
        try {
            MessageDigest md5 = MessageDigest.getInstance("MD5");
            byte[] bytes = md5.digest(value.getBytes());
            return new String(Hex.encodeHex(bytes));
        } catch (NoSuchAlgorithmException e) {
            return value;
        }
    }

5、接下来比较从session中获取的加密后的csrfToken与从requst中获取的csrfToken的值,如果相等,则返回true,反之则返回false。

boolean result = fromRequest.equals(fromSession);

总结:这种csrfToken机制,是在页面渲染时,将时间戳md5加密,渲染到页面,同样的时间戳在session中保存一份。请求时,带上csrfToken,跟session中的csrfToken比较,session中保存的是时间戳,在验证session中的时间戳没有过期的前提下,md5加密session中的时间戳,对比request中的csrfToken和session中的csrfToken,并返回结果。 这种属于longlive token,还有一个种unique token。