七、在攔截器中進行XSS與SQL注入攔截
- 2019 年 11 月 7 日
- 筆記
本次開發環境為:
系統:Windows 10 10.0
JDK:JRE: 1.8.0_152-release-1136-b43 amd64 JVM: OpenJDK 64-Bit Server VM by JetBrains s.r.o
開發工具:IntelliJ IDEA 2018.1.8
springboot框架:2.2.0
直接上乾貨,不多廢話,相關問題歡迎在評論區指教。
1、首先準備本次會用到的相關jar包,在pom.xml中導入
<!-- xss過濾組件 --> <dependency> <groupId>org.jsoup</groupId> <artifactId>jsoup</artifactId> <version>1.12.1</version> </dependency> <!-- StringUtil工具類--> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-lang3</artifactId> <version>3.9</version> </dependency>
2、開始製作一個字符串過濾工具,使其所有字符串都能按照相同規則進行過濾
import org.apache.commons.lang3.StringUtils; import org.jsoup.Jsoup; import org.jsoup.nodes.Document; import org.jsoup.safety.Whitelist; /** * 類 {@code FilterCoreUtil} 用於Xss非法標籤過濾工具類 <br> 過濾html中的xss字符. * * 本軟件僅對本次教程負責,版權所有 <a href="http://www.cnhuashao.com">中國,華少</a><br> * * @author cnHuaShao * <a href="mailto:[email protected] * <p> * ">cnHuaShao</a> * 修改備註: * @version v1.0.1 2019/11/5 19:42 */ public class FilterCoreUtil { /** * 使用自帶的basicWithImages 白名單 * 允許的便簽有a,b,blockquote,br,cite,code,dd,dl,dt,em,i,li,ol,p,pre,q,small,span, * strike,strong,sub,sup,u,ul,img * 以及a標籤的href,img標籤的src,align,alt,height,width,title屬性 */ private static final Whitelist WHITE_LIST = Whitelist.basicWithImages(); /** 配置過濾化參數,不對代碼進行格式化 */ private static final Document.OutputSettings OUTPUT_SETTINGS = new Document.OutputSettings().prettyPrint(false); static { // 富文本編輯時一些樣式是使用style來進行實現的 // 比如紅色字體 style="color:red;" // 所以需要給所有標籤添加style屬性 WHITE_LIST.addAttributes(":all", "style"); } /** * 過濾主方法入口 * @param content 需要過濾的字符串 * @return 過濾後的字符串 */ public static String clean(String content) { if(StringUtils.isNotBlank(content)){ content = content.trim(); } return Jsoup.clean(content, "", WHITE_LIST, OUTPUT_SETTINGS); } }
3、工具準備完畢,開始進行搭建一個倉庫,用於處理所有的請求相關字符串
import com.cnhuashao.rapiddevelopment.core.demo4.util.FilterCoreUtil; import org.apache.commons.lang3.StringUtils; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequestWrapper; /** * 類 {@code XssHttpServletRequestWrapper} Xss核心匹配類 <br> . * * 本軟件僅對本次教程負責,版權所有 <a href="http://www.cnhuashao.com">中國,華少</a><br> * * @author cnHuaShao * <a href="mailto:[email protected] * <p> * ">cnHuaShao</a> * 修改備註: * @version v1.0.1 2019/11/5 19:30 */ public class XssHttpServletRequestWrapper extends HttpServletRequestWrapper { /** * 需要進行過濾的請求 */ HttpServletRequest orgRequest = null; /** * 是否啟用過濾 */ private boolean isIncludeRichText = false; /** * 深度過濾構造方法 * @param request 需要過濾的請求 * @param isIncludeRichText 是否進行過濾,默認false */ public XssHttpServletRequestWrapper(HttpServletRequest request, boolean isIncludeRichText) { super(request); orgRequest = request; this.isIncludeRichText = isIncludeRichText; } /** * 覆蓋getParameter方法,將參數名和參數值都做xss過濾。<br/> * 如果需要獲得原始的值,則通過super.getParameterValues(name)來獲取<br/> * getParameterNames,getParameterValues和getParameterMap也可能需要覆蓋 */ @Override public String getParameter(String name) { Boolean flag = ("content".equals(name) || name.endsWith("WithHtml")); if( flag && !isIncludeRichText){ return super.getParameter(name); } name = FilterCoreUtil.clean(name); String value = super.getParameter(name); if (StringUtils.isNotBlank(value)) { value = FilterCoreUtil.clean(value); } return value; } @Override public String[] getParameterValues(String name) { String[] arr = super.getParameterValues(name); if(arr != null){ for (int i=0;i<arr.length;i++) { arr[i] = FilterCoreUtil.clean(arr[i]); } } return arr; } /** * 覆蓋getHeader方法,將參數名和參數值都做xss過濾。<br/> * 如果需要獲得原始的值,則通過super.getHeaders(name)來獲取<br/> * getHeaderNames 也可能需要覆蓋 */ @Override public String getHeader(String name) { name = FilterCoreUtil.clean(name); String value = super.getHeader(name); if (StringUtils.isNotBlank(value)) { value = FilterCoreUtil.clean(value); } return value; } /** * 獲取最原始的request * * @return */ public HttpServletRequest getOrgRequest() { return orgRequest; } /** * 獲取最原始的request的靜態方法 * * @return */ public static HttpServletRequest getOrgRequest(HttpServletRequest req) { if (req instanceof XssHttpServletRequestWrapper) { return ((XssHttpServletRequestWrapper) req).getOrgRequest(); } return req; } }
4、Xss處理倉庫均準備妥當,下面就可以開始編寫統一的攔截器了
import org.apache.commons.lang3.BooleanUtils; import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.servlet.*; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.util.ArrayList; import java.util.Date; import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; /** * 類 {@code XssFilter} Xss防止注入攔截器 <br> 用於過濾web請求中關於xss相關攻擊的特定字符. * * 本軟件僅對本次教程負責,版權所有 <a href="http://www.cnhuashao.com">中國,華少</a><br> * * @author cnHuaShao * <a href="mailto:[email protected] * <p> * ">cnHuaShao</a> * 修改備註: * @version v1.0.1 2019/11/5 19:10 */ public class XssFilter implements Filter { private Logger log = LoggerFactory.getLogger(XssFilter.class); /** * 是否過濾富文本內容 */ private static boolean IS_INCLUDE_RICH_TEXT = false; /** * 預設定白名單地址 * 將根據該變量中設置的相關目錄進行直接放行操作。 */ public List<String> excludes = new ArrayList<>(); /** * 攔截器核心處理單元 * 用於處理所有需要過濾的請求,在此進行確認其合法性 * @param request * @param response * @param filterChain * @throws IOException * @throws ServletException */ @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws IOException,ServletException { if(log.isDebugEnabled()){ log.debug("-------------------- get into xss filter --------------------"); } HttpServletRequest req = (HttpServletRequest) request; HttpServletResponse resp = (HttpServletResponse) response; //進行白名單過濾,如符合白名單,則直接放行 if(handleExcludeUrl(req, resp)){ filterChain.doFilter(request, response); return; } //開始進行深度過濾,判定其攜帶參數是否合法 XssHttpServletRequestWrapper xssRequest = new XssHttpServletRequestWrapper((HttpServletRequest) request,IS_INCLUDE_RICH_TEXT); filterChain.doFilter(xssRequest, response); } /** * 白名單過濾器 * @param request 攔截的請求 * @param response 攔截的響應 * @return 是否符合白名單 */ private boolean handleExcludeUrl(HttpServletRequest request, HttpServletResponse response) { //白名單為空時直接返回false,使其向下執行 if (excludes == null || excludes.isEmpty()) { return false; } //提取訪問的URL地址 String url = request.getServletPath(); log.info("開始進行過濾{} {}",new Date(),url); //開始根據白名單地址進行判定,如符合則直接放行 for (String pattern : excludes) { Pattern p = Pattern.compile("^" + pattern); Matcher m = p.matcher(url); if (m.find()) { return true; } } return false; } /** * 初始化攔截器配置 * @param filterConfig * @throws ServletException */ @Override public void init(FilterConfig filterConfig) throws ServletException { if(log.isDebugEnabled()){ log.debug("----------------- xss filter init -----------------"); } //獲取其初始化時預設置的深度過濾開關,根據其預設的true、false進行確定其是否開啟深度攔截 String isIncludeRichText = filterConfig.getInitParameter("isIncludeRichText"); if(StringUtils.isNotBlank(isIncludeRichText)){ IS_INCLUDE_RICH_TEXT = BooleanUtils.toBoolean(isIncludeRichText); } //獲取其初始化時預設置的白名單字符串,根據【,】符號進行截取存儲。 String temp = filterConfig.getInitParameter("excludes"); if (temp != null) { String[] url = temp.split(","); for (int i = 0; url != null && i < url.length; i++) { excludes.add(url[i]); } } } }
5、添加cookie攔截器
import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.servlet.*; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.util.Date; /** * 類 {@code CookieFilter} 會話Cookie攔截 <br> 用於對所有web會話的Cookie進行安全檢查. * * 本軟件僅對本次教程負責,版權所有 <a href="http://www.cnhuashao.com">中國,華少</a><br> * * @author cnHuaShao * <a href="mailto:[email protected] * <p> * ">cnHuaShao</a> * 修改備註: * @version v1.0.1 2019/11/5 20:10 */ public class CookieFilter implements Filter{ private static final Logger log = LoggerFactory.getLogger(CookieFilter.class); /** * 繼承方法,攔截器初始化邏輯 * @param filterConfig * @throws ServletException */ @Override public void init(FilterConfig filterConfig) throws ServletException { } /** * 自定義攔截器,用於Cookie全局設置 * @param request 請求 * @param response 響應 * @param chain filterchain是servlet容器提供給開發人員的對象 * @throws IOException * @throws ServletException */ @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletRequest req = (HttpServletRequest) request; HttpServletResponse resp = (HttpServletResponse) response; //日誌打印 if(log.isDebugEnabled()){ String url = req.getServletPath(); log.debug("-------- get into Cookie filter {} {}",new Date(),url); } //獲取請求中的cookies Cookie[] cookies = req.getCookies(); //如果不為空,則開始對其中的所有cookie進行設置 if (cookies!=null){ for (Cookie cookie : cookies){ if (cookie!=null){ //設置cookie最大有效期,單位秒,當前設置一小時60*60 cookie.setMaxAge(3600); //向瀏覽器指定,只允許https協議下才可以發送cookie cookie.setSecure(true); //設置cookie只能使用 cookie.setHttpOnly(true); resp.addCookie(cookie); } } } //請求下發 chain.doFilter(req,resp); } /** * 繼承方法,在銷毀filter時進行的操作 */ @Override public void destroy() { } }
6、所有攔截器準備就緒,在其SpringBoot啟動時進行加載
import com.cnhuashao.rapiddevelopment.core.demo4.filter.CookieFilter; import com.cnhuashao.rapiddevelopment.core.demo4.filter.XssFilter; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.boot.web.servlet.FilterRegistrationBean; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import java.util.HashMap; import java.util.Map; /** * 類 {@code XssConfig} Xss配置加載類 <br> 用於將Xss攔截器在系統初始時加載至web服務器中. * 本軟件僅對本次教程負責,版權所有 <a href="http://www.cnhuashao.com">中國,華少</a><br> * * @author cnHuaShao * <a href="mailto:[email protected] * <p> * ">cnHuaShao</a> * 修改備註: * @version v1.0.1 2019/11/5 20:12 */ @Configuration public class XssConfig { private Logger log = LoggerFactory.getLogger(XssConfig.class); /** * cookie攔截器 * 用於Cookie全局設置,主要設置有效期、https安全訪問、httpOnly啟用 * @return */ @Bean public FilterRegistrationBean cookieFilterRegistrationBean(){ log.info("------------ Start Cookie Filter ------------"); //1、啟動攔截器 FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean(); //註冊Cookie攔截器 filterRegistrationBean.setFilter(new CookieFilter()); //設置bean加載順序 filterRegistrationBean.setOrder(1); //啟用註冊 filterRegistrationBean.setEnabled(true); //添加URL為全部,使其攔截器全局攔截 filterRegistrationBean.addUrlPatterns("/*"); return filterRegistrationBean; } /** * 配置初始全局攔截器Xss過濾器 * @return FilterRegistrationBean */ @Bean public FilterRegistrationBean xssFilterRegistrationBean() { log.info("------------ Start Xss Filter ------------"); //1、啟動攔截器 FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean(); //註冊Xss攔截器 filterRegistrationBean.setFilter(new XssFilter()); //設置bean加載順序 filterRegistrationBean.setOrder(1); //啟用註冊 filterRegistrationBean.setEnabled(true); //添加URL為全部,使其攔截器全局攔截 filterRegistrationBean.addUrlPatterns("/*"); //2、設置初始化方法 Map<String, String> initParameters = new HashMap<String,String>(2); //設置白名單 initParameters.put("excludes", "/static/*,/img/*,/js/*,/css/*"); //是否啟用深度過濾機制(文本過濾機制),默認fales initParameters.put("isIncludeRichText", "true"); //為此註冊設置init參數。調用此方法將替換任何*現有的init參數。 filterRegistrationBean.setInitParameters(initParameters); return filterRegistrationBean; } }
7、進行測試攔截器效果
繼續訪問上一篇的地址:http://127.0.0.1:8081/hello?name=cnHuaShao

image.png

image.png
攔截器已成功過濾,至此我們所有的web請求均會經過該攔截器進行過濾,日常調配時只需要在攔截器類中進行配置即可
代碼示例
本文的相關例子可以查看倉庫中的RapidDevelopment-demo3
目錄: Gitee 地址
本文聲明:

88×31.png
本作品由 cn華少 採用 知識共享署名-非商業性使用 4.0 國際許可協議 進行許可。