XSS原理
xss攻擊的原理是利用前后端校驗不嚴格,用戶將攻擊代碼植入到數據中提交到了后台,當這些數據在網頁上被其他用戶查看的時候觸發攻擊
舉例:用戶提交表單時把地址寫成:山東省濟南市<script>for(var i=0;i<9999;i++){alert(i)}</script>
上面的數據如果沒有在后台做處理,當數據被展示到網頁上的時候,會在網頁上彈出N個alert框,當然實際攻擊肯定是比這個要復雜的多的
SpringBoot防護
給SpringBoot增加這種防護的原理是用戶提交數據之后后台在獲取數據內容時做一層過濾。過濾方式有兩種
第一種
第一種方式是對特殊字符進行轉義操作,例如將 < > /等特殊字符轉換成html支持的 < >等,這樣顯示到頁面的時候還是那些內容但是不會當成腳本執行了
這種方式我們用到了SpringFramework自帶的HtmlUtils.htmlEscape方法進行替換
```org.springframework.web.util.HtmlUtils.htmlEscape```
第二種
第二種是直接把數據過濾一遍徹底去掉不安全的因素,包括隱藏在標簽當中的 onXX=“js代碼” 屬性。
這一種方式用到了一個jar包 jsoup,Maven的依賴如下:
<dependency>
<groupId>org.jsoup</groupId>
<artifactId>jsoup</artifactId>
<version>1.11.3</version>
</dependency>
無論以上那種方式都需要對參數進行過濾處理,具體處理方式如下:
1.添加jsoup包的依賴
2.增加一個Filter類
import com.aliyuncs.utils.StringUtils;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class XssFilter implements Filter {
private List<String> excludes = new ArrayList<>();
private boolean enabled = false;
@Override
public void init(FilterConfig filterConfig) throws ServletException {
String strExcludes = filterConfig.getInitParameter("excludes");
String strEnabled = filterConfig.getInitParameter("enabled");
//將不需要xss過濾的接口添加到列表中
if(StringUtils.isNotEmpty(strExcludes)){
String[] urls = strExcludes.split(",");
for(String url:urls){
excludes.add(url);
}
}
if(StringUtils.isNotEmpty(strEnabled)){
enabled = Boolean.valueOf(strEnabled);
}
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) servletRequest;
//如果該訪問接口在排除列表里面則不攔截
if(isExcludeUrl(request.getServletPath())){
filterChain.doFilter(servletRequest,servletResponse);
return;
}
//攔截該url並進行xss過濾
XssHttpServletRequestWrapper xssHttpServletRequestWrapper = new XssHttpServletRequestWrapper(request);
filterChain.doFilter(xssHttpServletRequestWrapper,servletResponse);
}
@Override
public void destroy() {
}
private boolean isExcludeUrl(String urlPath){
if(!enabled){
//如果xss開關關閉了,則所有url都不攔截
return true;
}
if(excludes==null||excludes.isEmpty()){
return false;
}
String url = urlPath;
for(String pattern:excludes){
Pattern p = Pattern.compile("^"+pattern);
Matcher m = p.matcher(url);
if(m.find()){
return true;
}
}
return false;
}
}
3.增加一個xssHttpServletRequestWrapper類,這個類重寫了獲取參數的方法,在獲取參數時做了xss替換處理
import org.apache.commons.lang.StringUtils;
import org.jsoup.Jsoup;
import org.jsoup.safety.Whitelist;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
/**
* xss過濾包裝類
*/
public class XssHttpServletRequestWrapper extends HttpServletRequestWrapper {
private static final Logger logger = LoggerFactory.getLogger(XssHttpServletRequestWrapper.class);
/**
* Constructs a request object wrapping the given request.
*
* @param request The request to wrap
* @throws IllegalArgumentException if the request is null
*/
public XssHttpServletRequestWrapper(HttpServletRequest request) {
super(request);
}
@Override
public String getHeader(String name) {
String strHeader = super.getHeader(name);
if(StringUtils.isEmpty(strHeader)){
return strHeader;
}
return Jsoup.clean(super.getHeader(name),Whitelist.relaxed());
}
@Override
public String getParameter(String name) {
String strParameter = super.getParameter(name);
if(StringUtils.isEmpty(strParameter)){
return strParameter;
}
return Jsoup.clean(super.getParameter(name),Whitelist.relaxed());
}
@Override
public String[] getParameterValues(String name) {
String[] values = super.getParameterValues(name);
if(values==null){
return values;
}
int length = values.length;
String[] escapseValues = new String[length];
for(int i = 0;i<length;i++){
//過濾一切可能的xss攻擊字符串
escapseValues[i] = Jsoup.clean(values[i], Whitelist.relaxed()).trim();
if(!StringUtils.equals(escapseValues[i],values[i])){
logger.debug("xss字符串過濾前:"+values[i]+"\r\n"+"過濾后:"+escapseValues[i]);
}
}
return escapseValues;
}
}
4.SpringBoot里面增加一個configuration配置,把Filter類配置上去
import cn.gov.zibo.scsupport.xss.XssFilter;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import javax.servlet.DispatcherType;
import java.util.HashMap;
import java.util.Map;
/**
* 設置跨站腳本過濾
*/
@Configuration
public class FilterConfig {
@Value("${xss.enabled}")
private String enabled;
@Value("${xss.excludes}")
private String excludes;
@Value("${xss.urlPatterns}")
private String urlPatterns;
@Bean
public FilterRegistrationBean xssFilterRegistration(){
FilterRegistrationBean registrationBean = new FilterRegistrationBean();
registrationBean.setDispatcherTypes(DispatcherType.REQUEST);
registrationBean.setFilter(new XssFilter());
registrationBean.addUrlPatterns(StringUtils.split(urlPatterns,","));
registrationBean.setName("XssFilter");
registrationBean.setOrder(9999);
Map<String,String> initParameters = new HashMap<>();
initParameters.put("excludes",excludes);
initParameters.put("enabled",enabled);
registrationBean.setInitParameters(initParameters);
return registrationBean;
}
}
5.最后在application.properties或者application.yml里面增加一些開關配置,可以忽略某些接口提交的數據或者關閉xss過濾
#xss攻擊攔截
xss.enabled=true
xss.excludes=
xss.urlPatterns=/*
6.上面使用的是第二種處理方式,如果想使用第一種處理方式 只需要把XssHttpServletRequestWrapper類里面的Jsoup.clean方法替換成HtmlUtils.htmlEscape(xxx,"UTF-8")即可