跨站腳本攻擊(XSS)可以讓攻擊者在受害者的瀏覽器中執(zhí)行惡意腳本來(lái)修改網(wǎng)頁(yè)內(nèi)容、將用戶(hù)重定向到非法網(wǎng)站、偽造用戶(hù)登錄態(tài)、竊取用戶(hù)的隱私信息、甚至還能給程序開(kāi)個(gè)后門(mén)等等,所以不得不防。今天就來(lái)分享幾種常用的防范XSS攻擊的措施。
XSS攻擊
可能上面說(shuō)的不夠直觀,下面我們來(lái)看一下XSS攻擊的方式。假設(shè)我們寫(xiě)了一個(gè)注冊(cè)用戶(hù)接口:
- POST /user
- Host: api.felord.cn
- {
- "userId" : 1001,
- "username" : "felord.cn",
- "type" : "\<script\>alert(document.cookie)\</script\>"
- }
這樣的用戶(hù)如果查詢(xún)出來(lái)并被渲染到前端時(shí),type字段的值很容易被當(dāng)做腳本執(zhí)行,這是就是一種常見(jiàn)的XSS攻擊。胖哥在剛剛?cè)胄械臅r(shí)候就遇到過(guò),有人利用XSS掛他自己的廣告到我們的網(wǎng)站中來(lái)牟取利益。我們需要在應(yīng)用中做一些防御措施。
防范XSS攻擊的手段
下面就是我比較常用的手段。
X-XSS-Protection請(qǐng)求頭
X-XSS-Protection 響應(yīng)頭是 IE,Edge,Chrome 和 Safari 的一個(gè)特性,當(dāng)檢測(cè)到跨站腳本攻擊 (XSS) 時(shí),瀏覽器將停止加載頁(yè)面。
- # 0 表示禁止XSS過(guò)濾 1 表示開(kāi)啟XSS過(guò)濾
- X-XSS-Protection: 0
- X-XSS-Protection: 1
- # 啟用XSS過(guò)濾。 如果檢測(cè)到攻擊,瀏覽器將不會(huì)清除頁(yè)面,而是阻止頁(yè)面加載。
- X-XSS-Protection: 1; mode=block
- # 啟用XSS過(guò)濾 (谷歌瀏覽器專(zhuān)用)。 如果檢測(cè)到跨站腳本攻擊,瀏覽器將清除頁(yè)面并使用CSP report-uri指令的功能發(fā)送違規(guī)報(bào)告。
- X-XSS-Protection: 1; report=<reporting-uri>
大部分瀏覽器都支持這一特性。
瀏覽器兼容性
可以看得出X-XSS-Protection的兼容性還是很好的,不過(guò)它的保護(hù)性比較弱。默認(rèn)情況下,Spring security 會(huì)自動(dòng)添加此請(qǐng)求頭。
CSP請(qǐng)求頭
上面已經(jīng)提到了CSP,全稱(chēng)Content-Security-Policy(內(nèi)容安全策略),它也是以請(qǐng)求頭的形式存在。它允許站點(diǎn)管理者控制用戶(hù)代理能夠?yàn)橹付ǖ捻?yè)面加載哪些資源。除了少數(shù)例外情況,設(shè)置的政策主要涉及指定服務(wù)器的源和腳本結(jié)束點(diǎn)。這將幫助防止跨站腳本攻擊(XSS)。它的控制粒度更細(xì),它通過(guò)一系列的指令聲明可以決定URL、多媒體資源、字體的加載策略、腳本的執(zhí)行策略。具體可以查看Content-Security-Policy文檔。
例如僅支持執(zhí)行來(lái)自https://felord.cn的腳本:
- Content-Security-Policy: script-src https://felord.cn
目前主流的瀏覽器也都支持該特性。
支持CSP的瀏覽器
在Spring Security中我們可以這樣配置它:
- httpSecurity.headers()
- .contentSecurityPolicy(“script-src https://felord.cn”)
編碼過(guò)濾轉(zhuǎn)義
除此之外我們還可以使用編碼的形式來(lái)轉(zhuǎn)義請(qǐng)求參數(shù)和響應(yīng)體的字符來(lái)防止XSS攻擊。這里會(huì)用到Spring提供的工具類(lèi)org.springframework.web.util.HtmlUtils,當(dāng)然Apache Commons也有類(lèi)似的工具類(lèi)。
- HtmlUtils.htmlEscape(String value)
利用上面這個(gè)方法我們可以針對(duì)性的編寫(xiě)HttpServletRequestWrapper的實(shí)現(xiàn)來(lái)對(duì)請(qǐng)求參數(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 攔截器。
編寫(xiě)JSON序列化來(lái)實(shí)現(xiàn)對(duì)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攻擊的方式,主要是涉及后端的。其實(shí)像一些現(xiàn)代的前端框架都支持將字符串變量轉(zhuǎn)義,比如React的JSX。不過(guò)話(huà)又說(shuō)回來(lái),提高應(yīng)用的安全的根本方法就在于降低攻擊者的收益和提高攻擊者的成本。
原文鏈接:https://mp.weixin.qq.com/s/J4IFzCQlM5G0IyIFsqZz5g