Q1.什么是XSS攻擊?
定義很多,這里我找一個比較詳細的解釋
https://www.cnblogs.com/csnd/p/11807592.html
Q2.為什么會有XSS攻擊
也看上面的鏈接
Q3.Java后端如何防御XSS攻擊
方法:將前端請求(HttpServletRequest)的所有數據,先進行轉義后再存入DB中
Hutools其實已經有實現,這里不重復造車輪。
1.糊塗的Maven依賴
<!-- 數據轉義,防止xss攻擊--> <dependency> <groupId>cn.hutool</groupId> <artifactId>hutool-all</artifactId> <version>5.7.2</version> </dependency>
2.配置XssHttpServletRequestWrapper
/** * @description 對HttpServletRequest 請求的數據進行轉義,防止xss攻擊 * URL: home.html?mothod=space&pid=335511 */ public class XssHttpServletRequestWrapper extends HttpServletRequestWrapper { public XssHttpServletRequestWrapper(HttpServletRequest request) { super(request); } /** * 重寫getParameter方法,用HtmlUtil轉義后再返回 */ @Override public String getParameter(String name) { String value= super.getParameter(name); if(!StrUtil.hasEmpty(value)){ value=HtmlUtil.filter(value); } return value; } /** * 重寫getParameterValues方法, * 遍歷每一個值,用HtmlUtil轉義后再返回 */ @Override public String[] getParameterValues(String name) { String[] values= super.getParameterValues(name); if(values!=null){ for (int i=0;i<values.length;i++){ String value=values[i]; if(!StrUtil.hasEmpty(value)){ value=HtmlUtil.filter(value); } values[i]=value; } } return values; } /** * 重寫getParameterMap方法, * 拿到所有的k-v鍵值對,用LinkedHashMap接收, * key不變,value用HtmlUtil轉義后再返回 */ @Override public Map<String, String[]> getParameterMap() { Map<String, String[]> parameters = super.getParameterMap(); LinkedHashMap<String, String[]> map=new LinkedHashMap(); if(parameters!=null){ for (String key:parameters.keySet()){ String[] values=parameters.get(key); for (int i = 0; i < values.length; i++) { String value = values[i]; if (!StrUtil.hasEmpty(value)) { value = HtmlUtil.filter(value); } values[i] = value; } map.put(key,values); } } return map; } /** * 重寫getHeader方法,用HtmlUtil轉義后再返回 */ @Override public String getHeader(String name) { String value= super.getHeader(name); if (!StrUtil.hasEmpty(value)) { value = HtmlUtil.filter(value); } return value; } @Override public ServletInputStream getInputStream() throws IOException { /** * 拿到數據流,通過StringBuffer拼接, * 讀取到line上,用StringBuffer是因為會有多個線程同時請求,要保證線程的安全 */ InputStream in= super.getInputStream(); InputStreamReader reader=new InputStreamReader(in, Charset.forName("UTF-8")); BufferedReader buffer=new BufferedReader(reader); StringBuffer body=new StringBuffer(); String line=buffer.readLine(); while(line!=null){ body.append(line); line=buffer.readLine(); } buffer.close(); reader.close(); in.close(); /** * 將拿到的map,轉移后存到另一個map中 */ Map<String,Object> map=JSONUtil.parseObj(body.toString()); Map<String,Object> result=new LinkedHashMap<>(); for(String key:map.keySet()){ Object val=map.get(key); if(val instanceof String){ if(!StrUtil.hasEmpty(val.toString())){ result.put(key,HtmlUtil.filter(val.toString())); } }else { result.put(key,val); } } String json=JSONUtil.toJsonStr(result); ByteArrayInputStream bain=new ByteArrayInputStream(json.getBytes()); //匿名內部類,只需要重寫read方法,把轉義后的值,創建成ServletInputStream對象 return new ServletInputStream() { @Override public int read() throws IOException { return bain.read(); } @Override public boolean isFinished() { return false; } @Override public boolean isReady() { return false; } @Override public void setReadListener(ReadListener readListener) { } }; } }
3.配置XssFilter
/** * 攔截所有的請求,對所有請求轉義 */ @WebFilter(urlPatterns = "/*") public class XssFilter implements Filter { @Override public void init(FilterConfig filterConfig) throws ServletException { } /** * 將獲取到的數據,進行轉義后再放行 * home.php?mod=space&uid=952169 servletRequest 請求 * @param servletResponse 響應 * @param filterChain 攔截鏈 * @throws IOException * @throws ServletException */ @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { HttpServletRequest request= (HttpServletRequest) servletRequest; XssHttpServletRequestWrapper wrapper=new XssHttpServletRequestWrapper(request); filterChain.doFilter(wrapper,servletResponse); } @Override public void destroy() { } }