线上项目突然遭到大量的非法参数攻击,由于历史问题,之前的代码从未对请求参数进行校验。 导致大量请求落到了数据访问层,给应用服务器和数据库都带来了很大压力。 针对这个问题,只能对请求真正到Controller方法调用之前直接将非法参数请求拒绝掉,所以在Filter中对参数进行统一校验,非法参数直接返回400。
package com.lenovo.moc.portal.filter; import java.io.IOException; import java.util.ArrayList; import java.util.Enumeration; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.regex.Matcher; import java.util.regex.Pattern; import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.lenovo.moc.portal.util.SessionUtil; import com.lenovo.moc.portal.util.WebUtil; /** * 检查请求参数过滤器<br /> * 从2方面验证请求参数的有效性:检查cookie和请求参数 <br /> * @date 2017年8月9日 */ public class CheckRequestParamFilter implements Filter { private static final Logger logger = LoggerFactory.getLogger(CheckRequestParamFilter.class); private static final List<String> anonUriList = new ArrayList<String>(); // 不需要进行参数和cookie检查额uri列表 { anonUriList.add("/home.do"); anonUriList.add("/home_login_callback.do"); anonUriList.add("/home_login_demo.do"); anonUriList.add("/home_logout.do"); anonUriList.add("/home_admin_logout.do"); } public void init(FilterConfig filterConfig) throws ServletException { if(logger.isDebugEnabled()) { logger.debug("CheckRequestParamFilter init"); } } // 参数和cookie检查 // 1. 先检查uri是否需要拦截 // 2. 再检查请求参数是否合法 // 3. 最后检查cookie是否正确 public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletRequest req = (HttpServletRequest)request; HttpServletResponse resp = (HttpServletResponse)response; String uri = req.getRequestURI(); if(checkUri(req, resp, uri)) { chain.doFilter(request, response); return; } if(!checkParams(req, resp, uri)) { return; } if(!checkCookie(req, resp, uri)) { return; } chain.doFilter(request, response); } /** * 检查uri是否需要检查参数 * @param req * @param resp * @param uri * @return 不需要检查,返回true; 否则返回false. */ private boolean checkUri(HttpServletRequest req, HttpServletResponse resp, String uri) { if(logger.isDebugEnabled()) { logger.debug("request uri: {}", uri.trim()); } uri = uri.substring(req.getContextPath().length()); return anonUriList.contains(uri.trim()); } /** * 请求参数如果不为空,则不能包含特殊字符 * @param req * @param resp * @param uri * @return */ private boolean checkParams(HttpServletRequest req, HttpServletResponse resp, String uri) { Enumeration<?> enumeration = req.getParameterNames(); while(enumeration.hasMoreElements()) { String key = enumeration.nextElement().toString(); Object value = req.getParameter(key); if(value == null || "".equals(value.toString().trim())) { continue; } if(containsInvalidChars(value.toString())) { logger.error("request param value contains invalid chars! param name: {}, param value: {}, uri: {}", key, value, uri); return false; } if(containsInvalidString(value.toString())) { logger.error("request param value contains invalid string! parma name: {}, param value: {}, uri: {}", key, value, uri); return false; } } if(logger.isDebugEnabled()) { logger.debug("check all request parameters are valid, uri: {}", uri); } return true; } /** * 检查是否包含特殊字符 * @param value * @return */ private static boolean containsInvalidChars(String value) { String regex = "[`~!#$%^&()|{}';'\\[\\]<>?~!#¥%……&()——|{}【】‘;:”“’。,、?]"; Pattern pattern = Pattern.compile(regex); Matcher matcher = pattern.matcher(value); return matcher.find(); } /** * 检查是否包含特殊字符串 * @param value * @return */ private static boolean containsInvalidString(String value) { return value.contains("select") || value.contains("nslookup") || value.contains("sleep"); } /** * 指定cookie必须存在 * @param req * @param resp * @param uri * @return * @throws IOException */ private boolean checkCookie(HttpServletRequest req, HttpServletResponse resp, String uri) throws IOException { Map<String, String> cookieMap = new HashMap<String, String>(); Cookie[] cookies = req.getCookies(); for(Cookie c : cookies) { cookieMap.put(c.getName(), c.getValue()); } // 检查SessionUtil.LOGIN_STAFF_ID String loginStaffId = cookieMap.get(WebUtil.md5(SessionUtil.LOGIN_STAFF_ID)); if(loginStaffId == null) { logger.error("login staff id cookie NOT FOUND! uri: {}", uri); deny(req, resp, "invalid param"); return false; } // 检查SessionUtil.LOGIN_COMPANY_ID String loginCompanyId = cookieMap.get(WebUtil.md5(SessionUtil.LOGIN_COMPANY_ID)); if(loginCompanyId == null) { logger.error("login company id cookie NOT FOUND! uri: {}", uri); deny(req, resp, "invalid param"); return false; } // 检查SessionUtil.LOGIN_COMPANY_NAME String loginCompanyName = cookieMap.get(WebUtil.md5(SessionUtil.LOGIN_COMPANY_NAME)); if(loginCompanyName == null) { logger.error("login company name cookie NOT FOUND! uri: {}", uri); deny(req, resp, "invalid param"); return false; } // 检查SessionUtil.LOGIN_USER_NAME String loginUserName = cookieMap.get(WebUtil.md5(SessionUtil.LOGIN_USER_NAME)); if(loginUserName == null) { logger.error("login user name cookie NOT FOUND! uri: {}", uri); deny(req, resp, "invalid param"); return false; } // 检查SessionUtil.LOGIN_USER_ACCOUNT String loginUserAccount = cookieMap.get(WebUtil.md5(SessionUtil.LOGIN_USER_ACCOUNT)); if(loginUserAccount == null) { logger.error("login user account cookie NOT FOUND! uri: {}", uri); deny(req, resp, "invalid param"); return false; } // 检查SessionUtil.LOGIN_USER_ROLE String loginUserRole = cookieMap.get(WebUtil.md5(SessionUtil.LOGIN_USER_ROLE)); if(loginUserRole == null) { logger.error("login user role cookie NOT FOUND! uri: {}", uri); deny(req, resp, "invalid param"); return false; } // 检查SessionUtil.LOGIN_USER_ROLE_CODE String loginUserCode = cookieMap.get(WebUtil.md5(SessionUtil.LOGIN_USER_ROLE_CODE)); if(loginUserCode == null) { logger.error("login user role code cookie NOT FOUND! uri: {}", uri); deny(req, resp, "invalid param"); return false; } if(logger.isDebugEnabled()) { logger.debug("check all cookies are valid, uri: {}", uri); } return true; } /** * 断开与客户端的连接 * @param req * @param resp * @param message * @throws IOException */ private void deny(HttpServletRequest req, HttpServletResponse resp, String message) throws IOException { resp.setStatus(HttpServletResponse.SC_BAD_REQUEST); resp.getWriter().write(message); resp.getWriter().close(); } public void destroy() { } }
本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。
我来说两句