前端XSS相關整理
前端安全方面,主要需要關注 XSS(跨站指令碼攻擊 Cross-site scripting) 和 CSRF(跨站請求偽造 Cross-site request forgery)
當然了,也不是說要忽略 ofollow,noindex" target="_blank">其他 安全問題:後端範疇、DNS劫持、HTTP劫持、加密解密、釣魚等
CSRF主要是借用已登入使用者之手發起“正常”的請求,防範措施主要就是對需要設定為Post的請求,判斷Referer以及token的一致性,本文不展開
相對來說,XSS的內容就非常龐大了,下面就來整理一下一些XSS的知識點。比較匆忙,可能有點亂哈~
一、XSS
惡意攻擊者向頁面中注入可執行的JS程式碼來實現XSS的攻擊。
如常見的
Payload:<script>alert(1)</script> <div>[輸出]</div> <div><script>alert(1)</script></div>
這個 Payload 可以從編輯區域而來
<input type="text" value="[輸入]" />
當然,輸入和輸出的位置還可以出現在其他地方,根據輸入輸位置的不同,可以形成不同型別的XSS,相應的防範措施也不同。
1.1 XSS的分類
一般來說,可以將XSS分為三類:反射型XSS、儲存型XSS、DOM-base 型XSS
1.1.1 反射型XSS
大多通過URL進行傳播,發請求時,XSS程式碼出現在URL中,提交給服務端。服務端未進行處理或處理不當,返回的內容中也帶上了這段XSS程式碼,最後瀏覽器執行XSS程式碼
比如在 php的smarty模板中直接獲取url的引數值
Payload: <script>alert(1)</script> http://local.abc.com/main/?r=abc/index¶m=<script>alert(1)</script> <div><{$smarty.get.param}></div>
X-XSS-Protection
新版Chrome和Safari中,已自動遮蔽了這種XSS,形如
這個遮蔽是由 XSS Auditor操作的,它由HTTP返回頭部進行控制,有四個可選值
X-XSS-Protection : 0關閉瀏覽器的XSS防護機制 X-XSS-Protection : 1刪除檢測到的惡意程式碼(如果不指定,IE將預設使用這個) X-XSS-Protection : 1; mode=block如果檢測到惡意程式碼,將不渲染頁面 (如果不指定,Chrome將預設使用這個) X-XSS-Protection : 1; report=<reporting-uri> 刪除檢測到的惡意程式碼,並通過report-uri發出一個警告。
前三個在IE和Chrome中有效,最後一個只在Chrome中有效
可以手動在設定請求頭看看變化
header('X-XSS-Protection: 1; mode=block');
建議配置為後兩個的結合,禁止頁面渲染並進行上報
header('X-XSS-Protection: 1; mode=block; report=www.xss.report');
不建議僅僅配置為1,因為它刪除惡意程式碼的功能有時比較雞肋,可能會弄巧成拙。
另外,這個配置只能充當輔助作用,不能完全依賴,其也可能會產生 一些問題
不過在Firefox中並未遮蔽
在IE中的XSS Filter也預設也開啟了遮蔽,也可手動關閉試試,或者通過HTTP頭部進行控制
1.1.2 儲存型XSS
提交的XSS程式碼會儲存在伺服器端,服務端未進行處理或處理不當,每個人訪問相應頁面的時候,將會執行XSS程式碼
如本文開始的第一個例子
1.1.3 DOM-base 型XSS
這個型別和反射型的有點類似,區別是它不需要服務端參與
比如在JS中直接獲取URL中的值
Payload: alert('xss') http://local.abc.com/main/?r=abc/index#alert('xss') <script> var hash = eval(location.hash.slice(1)); </script>
另外,有些攻擊方式的型別是單一的,有些是混合的。防範攻擊,不應僅根據型別來防範,而應根據輸入輸出的不同來應對。
在反射型和DOM-base型中,一般會通過設定一些有誘導性質的連結,使用者點選連結後則觸發連結中的XSS
Content Security Policy(CSP)內容安全策略
為了防範XSS, CSP 出現了。
CSP 的實質就是白名單制度,開發者明確告訴客戶端,哪些外部資源可以載入和執行,提供了這種白名單之後,實現和執行則由瀏覽器完成
通過一系列的 自定義配置 ,可以在很大程度上防止惡意指令碼的攻擊,建議進行配置。
不過策略比較新,在各瀏覽器也有一些相容性的問題。另外,似乎還是可以通過 一些手段 繞過 的,這裡就不展開了
Cookie 配置
大多使用cookie來實現對使用者的認證。如果攻擊者拿到了這個認證cookie,就可以登入了使用者的賬號了
XSS的主要目的是為了得到cookie,當然也不僅是為了獲取cookie
Httponly:防止cookie被xss偷 https:防止cookie在網路中被偷 Secure:阻止cookie在非https下傳輸,很多全站https時會漏掉 Path :區分cookie的標識,安全上作用不大,和瀏覽器同源衝突
通過設定 cookie的幾個屬性,可以在一定程度上保障網站的安全
不過並沒有十全十美的東西,雖然攻擊門檻提高了,但HttpOnly在某些特定情況下還是能繞過的,道高一尺魔高一點一尺呀
1.2 執行JS程式碼
XSS的目的一般是盜取cookie,一般需要通過JS 的 document.cookie來獲取這個值。
所以要先思考的是: 在什麼地方可以執行JS相關的程式碼
然後要思考的是: 攻擊者能不能在這些地方構造出能夠執行的指令碼
1.2.1 <script>標籤中
<script>alert(1);</script>
1.2.2 HTML中的某些事件
<img src="1" onerror="alert(1)" > <input type="text" onfocus="alert(1)"> <span onmouseover="alert(1)"></span>
1.2.3 javascript: 偽協議
<a href="javascript:alert(1)">test</a> <iframe src="javascript:alert(1)"></iframe> location.href = 'javascript:alert(1)'
對於事件的執行觸發,是有機會防禦的,圍觀這篇文章
1.2.4 base64編碼的 data: 偽協議
Payload: <script>alert('XSS')</script> ,它的base64編碼為PHNjcmlwdD5hbGVydCgnWFNTJyk8L3NjcmlwdD4K <a href="data:text/html;base64,PHNjcmlwdD5hbGVydCgnWFNTJyk8L3NjcmlwdD4K">test</a>
1.2.5 css中的expression表示式
僅在IE8以下才支援expression,可以忽略這個了
<span style="color:1;zoom:expression(alert(1));"></span>
1.2.6 css中的src
很多文章都說到這個payload,然鵝並沒有生效,不知真假
根據 3607894/cross-site-scripting-in-css-stylesheets" rel="nofollow,noindex" target="_blank">一些討論 ,在css中是很難實現xss的
.abc { background: url(...) }
1.2.7 使用 eval、new Function、setTimeout 執行字串時
setTimeout('alert(1)'); eval('alert(2)'); var f = new Function('alert(3)'); f();
1.3 編碼與解碼
防範XSS,比較通用的做法是:提交儲存前對特殊字元進行過濾轉義,進行HTML實體的編碼
var escape = { '&': '&', '<': '<', '>': '>', '"': '"', "'": ''', '`': '`' };
事實上,僅僅這樣做還是不夠的
那為什麼要進行HTML實體的編碼呢?
這涉及到瀏覽器的解析過程。
瀏覽器在解析HTML文件期間,根據文件中的內容,會經過 HTML解析、JS解析和URL解析幾個過程
首先瀏覽器接收到一個HTML文件時,會觸發HTML解析器對HTML文件進行詞法解析,這完成HTML解碼工作並建立DOM樹。
如果HTML文件中存在JS的上下文環境,JavaScript解析器會介入對內聯指令碼進行解析,完成JS的解碼工作。
如果瀏覽器遇到需要URL的上下文環境,URL解析器也會介入完成URL的解碼工作。
URL解析器的解碼順序會根據URL所在位置不同,可能在JavaScript解析器之前或之後解析
1.3.1 HTML實體編碼
瀏覽器會對一些字元進行特殊識別處理,比如將 < > 識別為標籤的開始結束。
要想在HTML頁面中呈現出特殊字元,就需要用到對應的字元實體。比如在HTML解析過程中,如果要求輸出值為 < > ,那麼輸入值應該為其對應的實體 < >
字元實體以&開頭 + 預先定義的實體名稱,以分號結束,如“<”的實體名稱為<
或以&開頭 + #符號 以及字元的十進位制數字,如”<”的實體編號為<
或以&開頭 + #x符號 以及字元的十六進位制數字,如”<”的實體編號為<
字元都是有實體編號的但有些字元沒有實體名稱。
1.3.2 Javascript編碼
Unicode 是字符集,而 utf-8,utf-16,utf-32 是編碼規則
最常用的如“\uXXXX”這種寫法為Unicode轉義序列,表示一個字元,其中xxxx表示一個16進位制數字
如”<” Unicode編碼為“\u003c”,不區分大小寫
1.3.3 URL編碼
%加字元的ASCII編碼對於的2位16進位制數字,如”/”對應的URL編碼為%2f
轉換可以使用 JS 自帶的 encodeURIComponent 和 decodeURLComponent 方法來對特殊字元進行轉義,也可以對照ASCII表為每個字元進行轉換
1.3.4 編碼解碼分析
<span class="a<b">abc</span> 等價於 <span class="a<b">abc</span>
上述程式碼中
編碼順序:HTML編碼
解碼順序:HTML解碼
<a href="//www.baidu.com?a=1&b=2">abc</a> 等價於 <a href="//www.baidu.com?a=1%26b=2">abc</a> 等價於 <a href="//www.baidu.com?a=1b=2">abc</a>
上述程式碼中
編碼順序:URL編碼 -> HTML編碼
解碼順序:HTML解碼 -> URL解碼
<a href="#" onclick="alert(1)">abc</a> 等價於 <a href="#" onclick="\u0061\u006c\u0065\u0072\u0074(1)">abc</a> 等價於 <a href="#" onclick="">abc</a>
上述程式碼中
編碼順序:Javascript編碼 -> HTML編碼
解碼順序:HTML解碼 -> Javascript解碼
需要注意的是,在JS的解碼中,相關的識別符號才能被正確解析(如這裡的 alert 識別符號),
像圓括號、雙引號、單引號等等這些控制字元,在進行JavaScript解析的時候僅會被解碼為對應的字串文字(比如這裡並未對 (1) 進行編碼,如果對括號及括號裡面內容做JS編碼,將無法執行alert函式 )
<a href="javascript:alert(1<2)">abc</a> 等價於 <a href="javascript:\u0061\u006c\u0065\u0072\u0074(1<2)">abc</a> 等價於(使用JS的方法進行的URL編碼) <a href="javascript:alert(1%3C2)">abc</a> 等價於(使用轉換成對應ASCII編碼對應2位16進位制數字的URL編碼) <a href="javascript:%5c%75%30%30%36%31%5c%75%30%30%36%63%5c%75%30%30%36%35%5c%75%30%30%37%32%5c%75%30%30%37%34%28%31%3C%32%29">abc</a> 等價於 <a href="">abc</a>
上述程式碼中
編碼順序:Javascript編碼 -> URL編碼 -> HTML編碼
解碼順序:HTML解碼 -> URL解碼 -> Javascript解碼
這裡還需要注意的是,在URL的編碼中,不能對協議型別(這裡的 javascript: )進行編碼,否則URL解析器會認為它無型別,導致無法正確識別
應用這個解析順序,看以下這個例子
輸入源 abc為URL中的值,如果後端僅進行了HTML的編碼,還是有問題的
Payload-0: http://local.abc.com/main/?r=abc/index&abc=');alert('11 <span onclick="test('<{$abc}>')">test</span> <span onclick="test('');alert('11')">test</span>
解碼順序先是進行HTML解碼,此時會將 '解析成 ' 號,接著進行Javascript的解碼,識別到 ' 即可閉合test函式,呼叫成功
所以,這種情況下,後端需要先進行Javascript編碼再進行HTML的編碼
當然,還有其他順序的混合。也需要考慮編碼工作能不能正確地進行過濾
<a href="javascript:window.open('[輸入源]')">
解碼順序:
HTML解碼 -> URL解碼 -> Javascript解碼 -> URL解碼
引申出去,還有一些 字符集 的知識點,腦殼疼,就不在這整理了
1.4 常見XSS攻擊方式
XSS的攻擊指令碼多種多樣,在使用了模板(前端模板和後端模板)之後,需要格外注意資料的輸入輸出
下面列舉幾個常見的
有時候會使用 $smarty.get.abc 獲取URL中的引數,未經轉義
Payload-1: http://local.abc.com/main/?r=abc/index&abc=<script>alert(1)</script> <span><{$smarty.get.abc}></span> <span><script>alert(1)</script></span> Payload-2: http://local.abc.com/main/?r=abc/index&abc="><script>alert(1)</script> <a href="/main/?param=<{$smarty.get.abc}>">abc</a> <a href="/main/?param="><script>alert(1)</script>">abc</a> Payload-3: http://local.abc.com/main/?r=abc/index&abc=" onmouseover=alert(1) <a href="/main/?param=<{$smarty.get.abc}>">abc</a> <a href="/main/?param=" onmouseover="alert(1)" ">abc</a> Payload-4: http://local.abc.com/main/?r=abc/index&urlTo=javascript:alert(1) <a href="<{$smarty.get.urlTo}>">urlTo</a> <a href="javascript:alert(1)">urlTo</a> Payload-5: http://local.abc.com/main/?r=abc/index&urlTo=data:text/html;base64,PHNjcmlwdD5hbGVydCgxKTwvc2NyaXB0Pgo= <a href="<{$smarty.get.urlTo}>">urlTo</a> <!-- 對 <script>alert(1)</script> 進行 base64編碼 為 PHNjcmlwdD5hbGVydCgxKTwvc2NyaXB0Pgo= --> <a href="data:text/html;base64,PHNjcmlwdD5hbGVydCgxKTwvc2NyaXB0Pgo=">urlTo</a> Payload-6: http://local.abc.com/main/?r=abc/index&abc=</script><script>alert(1)// <script> var abc = '<{$smarty.get.abc}>'; </script> <script> // 第一個 script標籤被閉合,雖然會報錯,但不會影響第二個script標籤,注意需要閉合後面的引號或註釋,防止報錯 var abc = '</script><script>alert(1)//'; </script> Payload-7: http://local.abc.com/main/?r=abc/index&abc=alert(1) <script> if (<{$smarty.get.abc}> == 'abc') { console.log(1); } </script> <script> // 此處因為沒有用引號,所以可以直接執行 alert(1) if (alert(1) == 'abc') { console.log(1); } </script> Payload-8: http://local.abc.com/main/?r=abc/index&abc='){}if(alert(1)){// <script> if ('<{$smarty.get.abc}>' == 'abc') { console.log(1); } </script> <script> // 用了引號之後,閉合難度增加,不過還是可以閉合起來的 if (''){}if(alert(1)){//' == 'abc') { console.log(1); } </script> Payload-9: http://local.abc.com/main/?r=abc/index&abc=');alert('1 Payload-10: http://local.abc.com/main/?r=abc/index&abc=%26%2339%3B);alert(%26%2339%3B1對引數進行了HTML的實體編碼 <span onclick="test('<{$smarty.get.abc}>')">test</span> <span onclick="test('');alert('1')">test</span> Payload-11: http://local.abc.com/main/?r=abc/index&abc=" onfocus="alert(1)" autofocus="autofocus" <input type="text" id="input" value="<{$smarty.get.abc}>"> <input id="input" value="" onfocus="alert(1)" autofocus="autofocus" "="" type="text">
解決方式為:
不使用 $smarty.get 相關獲取引數,改用後端過濾資料後再返回引數;
Yii框架中相應位置配置:'escape_html' => true
在頁面標籤內嵌的指令碼中直接使用後端返回的資料並不安全,後端可能過濾不完善(見Payload-7和Payload-0)避免直接使用
可以改用將資料儲存在屬性中,再通過指令碼獲取屬性的方式
1.4.2 JS操作DOM的時候是否會有XSS隱患?
使用 jQuery的append相關方法時(比如 html方法)可能會
// 執行 $($0).html('<script>alert(1);</script>'); // 執行 $($0).html('\u003cscript\u003ealert(1);\u003c/script\u003e'); // 執行 $($0).append('<script>alert(1);</script>'); // 不執行 $0.innerHTML = '<script>alert(1);</script>';
原因是在jQuery中使用了eval方法執行相應的指令碼,需要注意的是,Unicode編碼的字元在運算中會被解析出來
所以,要注意的是
使用jQuery設定DOM內容時,記得先對內容進行轉義
對於設定輸入框的值,是安全的
<input type="text" id="input"> <textarea value="12" id="textarea"></textarea> <script> // 不執行 document.getElementById('input').value = '"><script>alert(1);<\/script>'; document.getElementById('textarea').value = '"><script>alert(1);<\/script>'; // 不執行 $('#input').val('" onmouseover="alert(1)"'); $('#textarea').val('" onmouseover="alert(1)"'); </script>
對於設定屬性的值,是安全的
<input type="text" id="input"> <textarea value="12" id="textarea"></textarea> <script> // 不執行 document.getElementById('input').setAttribute('abc', '"><script>alert(1);<\/script>'); document.getElementById('textarea').setAttribute('abc', '"><script>alert(1);<\/script>'); // 不執行 $('#input').attr('abc', '" onmouseover="alert(1)"'); $('#textarea').attr('abc', '" onmouseover="alert(1)"'); </script>
1.4.3 前端Handlebars模板中的安全問題
後端有Smarty模板,前端也可以有Handlebars模板,使用模板有利於開發維護程式碼。不過和後端一樣,使用模板也要考慮到XSS的問題
Handlebars模板中可選擇是否開啟轉義
<!-- 轉義,如果name的值已經被後端轉義為實體符> 那麼Handlebars將會轉換成 > 在瀏覽器中將會顯示 > --> <!-- 所以此時需要先將 > 轉回 > 再傳入Handlebars模板,才能看到正確的 > 符號 --> <span>{{name}}</span> <!-- 不轉義 --> <span>{{{name}}}</span>
所以要注意的第一點是:
如果使用了轉義佔位符,就需要先進行還原;如果不使用轉義,就不要還原,否則將造成XSS
另外,Handlebars模板可以自定義helper,helper有兩種使用方式,直接返回資料或返回子層
<!-- 模板 [A] --> <script type="text/template" id="test-tpl"> <span abc="{{#abc attrData}}{{/abc}}">111{{#abc data}}{{/abc}}</span> <span> <input type="text" value="{{#abc attrData}}{{/abc}}"> </span> </script> <!-- 模板 [B] --> <!-- <script type="text/template" id="test-tpl"> <span abc="{{#abc attrData}}{{attrData}}{{/abc}}">111{{#abc data}}{{data}}{{/abc}}</span> <span> <input type="text" value="{{#abc attrData}}{{attrData}}{{/abc}}"> </span> </script> --> <!-- 容器 --> <span id="test"></span> <script src="........./handlebars/handlebars-v4.0.5.js"></script> <script type="text/javascript"> // 自定義helper Handlebars.registerHelper('abc', function (text, options) { // 對輸入資料進行過濾 [1] // text = Handlebars.Utils.escapeExpression(text) // helper直接返回資料 [2] return text; // helper返回子層 [3] // return options.fn(this); }); // Handlebars獲取資料 function getHtml(html, data) { let source = Handlebars.compile(html); let content = source(data); return content; } var data = '<script>alert(1);<\/script>'; var attrData = '" onmouseover="alert(2)"'; // 渲染 $('#test').html(getHtml($('#test-tpl').html(), { data: data, attrData: attrData })); </script>
進入頁面後,將會執行 alert(1) ,然後滑鼠滑過span或input元素,將會執行 alert(2)
這是因為Handlebars在處理helper時,如果是返回資料,將不進行轉義過濾
解決方案為:
如果使用了自定義的helper直接返回資料,先轉義一遍,即取消註釋[1] 處 程式碼
或者不直接返回資料,即註釋模板[A],[1] 和[2]處,取消註釋模板[B],[3]處 程式碼
另外,前端模板會頻繁和JS進行互動,在前端直接使用JS獲取URL引數並放到模板中時,要格外注意防止產生DOM-base型XSS,如下面這段程式碼
Payload: http://local.abc.com/main/?r=abc/index¶m=%22%20onmouseover=%22alert(2)%22 function getUrlParam(name) { let value = window.location.search.match(new RegExp('[?&]' + name + '=([^&]*)(&?)', 'i')); return value ? decodeURIComponent(value[1]) : ''; } var attrData = getUrlParam('param');
1.4.4 React JSX模板中的 dangerouslySetInnerHTML
<span dangerouslySetInnerHTML={{__html: '<script>alert(1);</script>'}}></div>
這段程式碼會執行麼
事實上,並不會。與模板不同,它使用的是 innerHTML來更新DOM元素的內容,所以不會執行惡意程式碼
不過,這個內容不會顯示在頁面中,如果這時正常的一段內容,就應該轉義之後再放入 __html的值中
1.4.5 在React的服務端渲染中,也要注意安全問題
服務端渲染需要一個初始的state,並與客戶端做對應
可能會長這樣子
<!-- 客戶端 --> <div id="content"> <|- appHtml |> </div> <script id="preload-state"> var PRELOAD_STATE = <|- preloadState |> </script> // 服務端 res.render('xxx.html', { appHtml: appHtml, preloadState: JSON.stringify(preloadState).replace(/</g, '\\u003c') });
類似模板,服務端將資料傳給客戶端時,在模板組裝資料的時候要防止構造出閉合 <script>標籤的情景
這裡可以將 < 替換成對應的Unicode字串,在JS中獲取該字串時,可以直接識別為 <
1.4.6 百度編輯器的編輯原始碼,可能會有安全問題
在編輯器內直接輸入這串內容,不會執行。點選檢視原始碼,可以看到已經經過轉義
我們可以直接在這裡修改原始碼
再切換回去,一個XSS漏洞就產生了,如果稍加不注意就會被利用。
所以,在前端範疇必須將此入口去除,後端也應加強一些特殊字元的轉義
1.4.7 謹防 javascript: 偽協議
連結中帶有 javascript: 偽協議可執行對應的指令碼,常見於 a 的 href 標籤和 iframe的 src 中
<a href="javascript:alert(1)">test</a> <!-- 冒號: 的HTML實體符 --> <a href="javascript alert(1)">test</a> <iframe src="javascript:alert(1)"></iframe>
輸入源多為一個完整的URL路徑,輸出地方多為模板與JS的操作
<a href="<{$urlTo}>">test</a> <a href="{{{urlTo}}}">test</a> location.href = getUrlParam('urlTo');
普通的HTML實體符並不能過濾這個偽協議
需要知道的是,javascript: 能夠正常工作的前提為:開始URL解析時沒有經過編碼
解決方案:
1. 前端後端都要先對 '"><& 這些特殊字元進行過濾轉義,特別是在與模板共用時,它們很有可能會閉合以產生攻擊,或者利用瀏覽器解碼的順序來繞過不嚴格的過濾
2.嚴格要求輸入的URL以 https:// 或 http:// 協議開頭
3.嚴格限制白名單協議雖然可取,但有時會造成限制過頭的問題。還可以單獨限制偽協議,直接對 javascript: 進行過濾
過濾時需要相容多層級的巢狀: javajavajavascript:script:script:alert(1)
同時顯示的時候,將多餘的冒號 : 轉義成URL編碼,注意避免把正常的協議頭也轉義了,要相容正常的URL
轉義冒號要使用 encodeURIComponent , encodeURI轉義不了,另外escape也不建議使用,關於 三者的區別
function replaceJavascriptScheme(str) { if (!str) { return ''; } return str.replace(/:/g, encodeURIComponent(':')); } Handlebars.registerHelper('generateURL', function (url) { url = Handlebars.Utils.escapeExpression(url); if (!url) { return ''; } var schemes = ['//', 'http://', 'https://']; var schemeMatch = false; schemes.forEach(function(scheme) { if (url.slice(0, scheme.length) === scheme) { url = scheme + replaceJavascriptScheme(url.slice(scheme.length)); schemeMatch = true; return false; } }); return schemeMatch ? url : '//' + replaceJavascriptScheme(url);; });
1.4.8 注意符號的閉合 '">< 和其他特殊符號
閉合標籤,閉合屬性是很常見的一種攻擊方式,要重點關注哪裡可能被惡意程式碼閉合。
本文使用了模板Smarty,在使用模板的時候,一般都將模板變數放在了引號中,需要帶符號來閉合來實現攻擊
<span abc="<{$abc}>"></span> " onclick=alert(1)
在設定了特殊符號轉義的情況下,這種攻擊方式將失效
然鵝當輸出的資料不在引號當中時,防範難度將加大。因為分離屬性可以使用很多符號,黑名單過濾可能列舉不全
abc/index?abc=1 onclick=alert(1) <span id="test1" abc=<{$abc}>>test</span>
所以,儘量用引號包裹起變數
另外,也要避免在 <script>標籤中直接使用模板中的變數,可以改用將模板變數快取在HTML屬性中,JS再進行取值
防止該 <script>標籤被惡意程式碼閉合,然後執行惡意程式碼,例子可見上文的 Payload-6
還要注意JS的語法,在某些時候,特殊符號 反斜槓\ 沒有過濾的話,也有安全問題
<script> var aaaa = '?a=<{$a}>' + '&b=<{$b}>'; </script> ?r=abc/index&a=\&b==alert(1);function b(){}// <script> // 構造處可執行的程式碼,如果空格也被轉義了,還可以用註釋佔位 function/**/b(){} var aaaa = '?a=\' + '&b==alert(1);function b(){}//'; </script>
假設只對 ' " > < & 進行了轉義,可以試試從URL拿資料,這裡需要利用到JS程式碼中關鍵的 & 符號與 \ 轉義符
\ 將第一個分號轉義為字串
& 與運算將前後分離
b的引數加上 = 號構造處bool運算
為了防止b未定義,在後面用函式提升特性來定義
最後註釋符防止報錯
為了攻擊也是蠻拼的....所以最好還是要對JS操作的字元用反斜槓進行轉義一下,比如 \ -> \\
1.4.9 圖片 exif 資訊含有惡意程式碼
另一種XSS攻擊的方式是在圖片的exif資訊中注入指令碼,在讀取圖片資訊時要注意過濾
在早期的很多外掛中都沒有進行處理,如之前爆出的 Chrome Exif Viewer 外掛問題,可能還有相關外掛沒有這些意識,平時也要注意
另外,站點自身在讀取檔案資訊時也要注意,攻擊者在上傳檔案前,可能會對檔案的資訊進行修改,過濾不當很可能就造成嚴重的儲存型漏洞