后端Java開發(fā)如何防御XSS攻擊
跨站腳本攻擊(XSS)可以讓攻擊者在受害者的瀏覽器中執(zhí)行惡意腳本來修改網(wǎng)頁內(nèi)容、將用戶重定向到非法網(wǎng)站、偽造用戶登錄態(tài)、竊取用戶的隱私信息、甚至還能給程序開個后門等等,所以不得不防。今天就來分享幾種常用的防范XSS攻擊的措施。
XSS攻擊
可能上面說的不夠直觀,下面我們來看一下XSS攻擊的方式。假設(shè)我們寫了一個注冊用戶接口:
- POST /user
- Host: api.felord.cn
- {
- "userId" : 1001,
- "username" : "felord.cn",
- "type" : "\<script\>alert(document.cookie)\</script\>"
- }
這樣的用戶如果查詢出來并被渲染到前端時,type字段的值很容易被當(dāng)做腳本執(zhí)行,這是就是一種常見的XSS攻擊。胖哥在剛剛?cè)胄械臅r候就遇到過,有人利用XSS掛他自己的廣告到我們的網(wǎng)站中來牟取利益。我們需要在應(yīng)用中做一些防御措施。
防范XSS攻擊的手段
下面就是我比較常用的手段。
X-XSS-Protection請求頭
X-XSS-Protection 響應(yīng)頭是 IE,Edge,Chrome 和 Safari 的一個特性,當(dāng)檢測到跨站腳本攻擊 (XSS) 時,瀏覽器將停止加載頁面。
- # 0 表示禁止XSS過濾 1 表示開啟XSS過濾
- X-XSS-Protection: 0
- X-XSS-Protection: 1
- # 啟用XSS過濾。 如果檢測到攻擊,瀏覽器將不會清除頁面,而是阻止頁面加載。
- X-XSS-Protection: 1; mode=block
- # 啟用XSS過濾 (谷歌瀏覽器專用)。 如果檢測到跨站腳本攻擊,瀏覽器將清除頁面并使用CSP report-uri指令的功能發(fā)送違規(guī)報告。
- X-XSS-Protection: 1; report=<reporting-uri>
大部分瀏覽器都支持這一特性。
瀏覽器兼容性
可以看得出X-XSS-Protection的兼容性還是很好的,不過它的保護(hù)性比較弱。默認(rèn)情況下,Spring security 會自動添加此請求頭。
CSP請求頭
上面已經(jīng)提到了CSP,全稱Content-Security-Policy(內(nèi)容安全策略),它也是以請求頭的形式存在。它允許站點管理者控制用戶代理能夠為指定的頁面加載哪些資源。除了少數(shù)例外情況,設(shè)置的政策主要涉及指定服務(wù)器的源和腳本結(jié)束點。這將幫助防止跨站腳本攻擊(XSS)。它的控制粒度更細(xì),它通過一系列的指令聲明可以決定URL、多媒體資源、字體的加載策略、腳本的執(zhí)行策略。具體可以查看Content-Security-Policy文檔。
例如僅支持執(zhí)行來自https://felord.cn的腳本:
- Content-Security-Policy: script-src https://felord.cn
目前主流的瀏覽器也都支持該特性。
支持CSP的瀏覽器
在Spring Security中我們可以這樣配置它:
- httpSecurity.headers()
- .contentSecurityPolicy(“script-src https://felord.cn”)
編碼過濾轉(zhuǎn)義
除此之外我們還可以使用編碼的形式來轉(zhuǎn)義請求參數(shù)和響應(yīng)體的字符來防止XSS攻擊。這里會用到Spring提供的工具類org.springframework.web.util.HtmlUtils,當(dāng)然Apache Commons也有類似的工具類。
- HtmlUtils.htmlEscape(String value)
利用上面這個方法我們可以針對性的編寫HttpServletRequestWrapper的實現(xiàn)來對請求參數(shù)進(jìn)行轉(zhuǎn)義:
- import org.springframework.web.util.HtmlUtils;
- import javax.servlet.http.HttpServletRequest;
- import javax.servlet.http.HttpServletRequestWrapper;
- import java.util.stream.Stream;
- public class XssHttpServletRequestWrapper extends HttpServletRequestWrapper {
- public XssHttpServletRequestWrapper(HttpServletRequest request) {
- super(request);
- }
- @Override
- public String getHeader(String name) {
- String value = super.getHeader(name);
- return HtmlUtils.htmlEscape(value);
- }
- @Override
- public String getParameter(String name) {
- String value = super.getParameter(name);
- return HtmlUtils.htmlEscape(value);
- }
- @Override
- public String[] getParameterValues(String name) {
- String[] values = super.getParameterValues(name);
- return values != null ? (String[]) Stream.of(values)
- .map(HtmlUtils::htmlEscape).toArray() :
- super.getParameterValues(name);
- }
- }
結(jié)合 Servlet Filter 或者Spring MVC 攔截器。
編寫JSON序列化來實現(xiàn)對JSON返回的轉(zhuǎn)義,例如Jackson中自定義XSS序列化
- public class XssStringJsonSerializer extends JsonSerializer<String> {
- @Override
- public Class<String> handledType() {
- return String.class;
- }
- @Override
- public void serialize(String value, JsonGenerator jsonGenerator,
- SerializerProvider serializerProvider) throws IOException {
- if (value != null) {
- jsonGenerator.writeString(HtmlUtils.htmlEscape(value));
- }
- }
- }
總結(jié)
今天介紹了幾種常用的防止XSS攻擊的方式,主要是涉及后端的。其實像一些現(xiàn)代的前端框架都支持將字符串變量轉(zhuǎn)義,比如React的JSX。不過話又說回來,提高應(yīng)用的安全的根本方法就在于降低攻擊者的收益和提高攻擊者的成本。
本文轉(zhuǎn)載自微信公眾號「碼農(nóng)小胖哥」,可以通過以下二維碼關(guān)注。轉(zhuǎn)載本文請聯(lián)系碼農(nóng)小胖哥公眾號。