XSS防御
- 一、簡單了解一下XSS
- 二、如何防御
- SpringBoot配置XSS防御
- 代碼決議
一、簡單了解一下XSS
來,百度先抄一段,
HTML是一種超文本標記語言,通過將一些字符特殊地對待來區別文本和標記,例如,小于符號(<)被看作是HTML標簽的開始,
再用一個通俗易懂的例子介紹一下
在沒有使用防御之前,假設有個用戶管理和用戶注冊的功能,前臺注冊用戶,用戶名中含有,那么在用戶管理渲染這條用戶資訊時就會一直彈框,這就是一個簡單的XSS攻擊,
二、如何防御
傳統的XSS防御在進行攻擊鑒別時多采用特征匹配方式,主要是針對“javascript”這個關鍵字進行檢索,但是這種鑒別不夠靈活,凡是提交的資訊中各有“javascript”時,就被硬性的被判定為XSS攻擊,
基于代碼修改的防御,Web頁面開發者在撰寫程式時往往會出現一些失誤和漏洞,XSS攻擊正是利用了失誤和漏洞,因此一種比較理想的方法就是通過優化Web應用開發來減少漏洞,避免被攻擊:1)用戶向服務器上提交的資訊要對URL和附帶的的HTTP頭、POST資料等進行查詢,對不是規定格式、長度的內容進行過濾,2)實作Session標記(session tokens)、CAPTCHA系統或者HTTP參考頭檢查,以防功能被第三方網站所執行,3)確認接收的的內容被妥善的規范化,僅包含最小的、安全的Tag(沒有javascript),去掉任何對遠程內容的參考(尤其是樣式表和javascript),使用HTTP only的cookie,,
客戶端分層防御策略,客戶端跨站腳本攻擊的分層防御策略是基于獨立分配執行緒和分層防御策略的安全模型,它建立在客戶端(瀏覽器),這是它與其他模型最大的區別,之所以客戶端安全性如此重要,客戶端在接受服務器資訊,選擇性的執行相關內容,這樣就可以使防御XSS攻擊變得容易,該模型主要由三大部分組成:1)對每一個網頁分配獨立執行緒且分析資源消耗的“網頁執行緒分析模塊”;2)包含分層防御策略四個規則的用戶輸入分析模塊;3)保存互聯網上有關XSS惡意網站資訊的XSS資訊資料庫
如果你心情不好,上面的可以不看
如果你心情好,上面的其實也沒什么看的必要,因為都是百度來的
現在
谷歌提供了一套轉義的標準,什么大于號,小于號,都給你轉成其它表示形式,
比如這樣子:這里有全套,我知道你們都喜歡看全套

那么原理就是利用這一套標準,將轉義后的字串存入資料庫,前臺決議時再通過這個規則呈現,
怎么轉,在哪里轉?做法還是蠻有意思,先把代碼放出來,畢竟有的人急著用,代碼放出來,我再解釋解釋,我相信沒有人不懂,不懂就到我床上坐坐,我好好給你講講,
SpringBoot配置XSS防御
首先maven匯入需要的依賴,有已經匯入的就不用重復匯入了,最新版可以自己去maven官網找,
<!--xss防御-->
<dependency>
<groupId>org.jsoup</groupId>
<artifactId>jsoup</artifactId>
<version>1.10.2</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.5</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.73</version>
</dependency>
接下來要做的就是寫個過濾器攔截處理了
寫一個XssFilter過濾所有請求
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
/**
* XSS過濾器
* @author Jozz
*/
@WebFilter(filterName="xssFilter",urlPatterns="/*")
public class XssFilter implements Filter {
@Override
public void init(javax.servlet.FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest)servletRequest;
String path = request.getServletPath();
//由于我的@WebFilter注解配置的是urlPatterns="/*"(過濾所有請求),所以這里對不需要過濾的靜態資源url,作忽略處理(大家可以依照具體需求配置)
String[] exclusionsUrls = {".js",".gif",".jpg",".png",".css",".ico"};
for (String str : exclusionsUrls) {
if (path.contains(str)) {
filterChain.doFilter(servletRequest,servletResponse);
return;
}
}
filterChain.doFilter(new XssHttpServletRequestWrapper(request),servletResponse);
}
@Override
public void destroy() {
}
};
然后再來一個ServletRequest包裝類,這個類可能出現的莫名其妙,等下再來解釋,
import com.alibaba.fastjson.JSON;
import org.apache.commons.lang3.StringEscapeUtils;
import javax.servlet.ReadListener;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.io.*;
import java.nio.charset.Charset;
import java.util.HashMap;
import java.util.Map;
/**
* ServletRequest包裝類,對request做XSS過濾處理
* @author Jozz
*/
public class XssHttpServletRequestWrapper extends HttpServletRequestWrapper {
public XssHttpServletRequestWrapper(HttpServletRequest request) {
super(request);
}
@Override
public String getHeader(String name) {
return StringEscapeUtils.escapeHtml4(super.getHeader(name));
}
@Override
public String getQueryString() {
return StringEscapeUtils.escapeHtml4(super.getQueryString());
}
@Override
public String getParameter(String name) {
return StringEscapeUtils.escapeHtml4(super.getParameter(name));
}
@Override
public String[] getParameterValues(String name) {
String[] values = super.getParameterValues(name);
if(values != null) {
int length = values.length;
String[] escapseValues = new String[length];
for(int i = 0; i < length; i++){
escapseValues[i] = StringEscapeUtils.escapeHtml4(values[i]);
}
return escapseValues;
}
return values;
}
@Override
public ServletInputStream getInputStream() throws IOException {
String str=getRequestBody(super.getInputStream());
Map<String,Object> map= JSON.parseObject(str,Map.class);
Map<String,Object> resultMap=new HashMap<>(map.size());
for(String key:map.keySet()){
Object val=map.get(key);
if(map.get(key) instanceof String){
resultMap.put(key,StringEscapeUtils.escapeHtml4(val.toString()));
}else{
resultMap.put(key,val);
}
}
str=JSON.toJSONString(resultMap);
final ByteArrayInputStream bais = new ByteArrayInputStream(str.getBytes());
return new ServletInputStream() {
@Override
public int read() throws IOException {
return bais.read();
}
@Override
public boolean isFinished() {
return false;
}
@Override
public boolean isReady() {
return false;
}
@Override
public void setReadListener(ReadListener listener) {
}
};
}
private String getRequestBody(InputStream stream) {
String line = "";
StringBuilder body = new StringBuilder();
int counter = 0;
// 讀取POST提交的資料內容
BufferedReader reader = new BufferedReader(new InputStreamReader(stream, Charset.forName("UTF-8")));
try {
while ((line = reader.readLine()) != null) {
body.append(line);
counter++;
}
} catch (IOException e) {
e.printStackTrace();
}
return body.toString();
}
}
最后在啟動類上加上@ServletComponentScan注解,用于掃描過濾器,
@SpringBootApplication
@MapperScan("com.kid.mapper")
//@MapperScan("com.baomidou.mybatisplus.samples.quickstart.mapper")
@ServletComponentScan//掃描過濾器
@EnableCaching
public class Boot {
public static void main(String[] args) {
SpringApplication.run(Boot.class, args);
}
}
那么我現在啟動一下,展示以一下效果

大家可以看到我在賬號輸入了一些非法字符,我在后臺列印我獲取到的資訊是這樣的

那么其實,收到的不是這樣的,只不過是被轉成這樣了,
代碼決議
我相信大家也都知道,這個事情是因為經過過濾器,處理之后才成功防御的,那么過濾器到底做了什么,我們可以看到過濾器似乎什么都沒做就流下了,只是放行了一些圖片其它檔案請求的url,
但是我們仔細看流下是,傳入的request物件
filterChain.doFilter(new XssHttpServletRequestWrapper(request),servletResponse);
這里的request物件被包裹成另一個物件,穿上了一件衣服,
其實這種設計模式叫做裝飾者模式,我在講簡易連接池的篇章也專門講過這個模式,有興趣也可以去了解一下,
簡易連接池及裝飾者模式
我們在FilterChain介面中可以看到,var1引數需要傳入的是ServletRequest型別的物件,因此這里的物件只要是實作ServletRequest 介面的都可以,
public interface FilterChain {
void doFilter(ServletRequest var1, ServletResponse var2) throws IOException, ServletException;
}
我們在查看原始碼也可以看到HttpServletRequest 是一個介面,并且繼承了ServletRequest 介面
public interface HttpServletRequest extends HttpServletRequest
因此這個地方只需要實作傳入實作HttpServletRequest 介面的類或者HttpServletRequest 介面的類即可,
因為我們做過濾器中拿到的request物件它是HttpServletRequest 型別的,我們要把這個包進去,那我們就必須寫一個實作HttpServletRequest 介面的類,將這個request包進來,
但是從上面的代碼上看,我們繼承的是HttpServletRequestWrapper 物件,其實這個HttpServletRequestWrapper 物件,它就是實作HttpServletRequest介面,并且實作所有介面,且每個方法都原封不動抄下來,
public class XssHttpServletRequestWrapper extends HttpServletRequestWrapper
以上的部分其實可知道可不知道,但我覺得作為一個程式員,這些還是有必要懂的
那么我們知道過濾器中只是去替換了HttpServletRequest 物件,很顯然,我們要實作XSS防御,只需要在getParameter等獲取字串的這些方法中,去將原本獲取到的字串,拿到工具類去轉換一下再回傳給呼叫者,
@Override
public String getParameter(String name) {
return StringEscapeUtils.escapeHtml4(super.getParameter(name));
}
下面就是我簡單畫了的一張騷圖,哈哈哈哈哈哈或哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈,蠻看吧,下一章見!

轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/196769.html
標籤:python
