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() { } }
