前端XSS相關整理

前端安全方面,主要須要關注 XSS(跨站腳本攻擊 Cross-site scripting) 和 CSRF(跨站請求僞造 Cross-site request forgery)javascript

固然了,也不是說要忽略其餘安全問題:後端範疇、DNS劫持、HTTP劫持、加密解密、釣魚等php

CSRF主要是借用已登陸用戶之手發起「正常」的請求,防範措施主要就是對須要設置爲Post的請求,判斷Referer以及token的一致性,本文不展開css

相對來講,XSS的內容就很是龐大了,下面就來整理一下一些XSS的知識點。比較匆忙,可能有點亂哈~html

 

1、XSS

惡意攻擊者向頁面中注入可執行的JS代碼來實現XSS的攻擊。前端

如常見的java

Payload:<script>alert(1)</script>
<div>[輸出]</div>
 
<div><script>alert(1)</script></div>

這個 Payload 能夠從編輯區域而來web

<input type="text" value="[輸入]" />

固然,輸入和輸出的位置還能夠出如今其餘地方,根據輸入輸位置的不一樣,能夠造成不一樣類型的XSS,相應的防範措施也不一樣。express

 

1.1 XSS的分類

通常來講,能夠將XSS分爲三類:反射型XSS、存儲型XSS、DOM-base 型XSSjson

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&param=<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

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,然鵝並無生效,不知真假

根據一些討論,在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 = {
    '&': '&amp;',
    '<': '&lt;',
    '>': '&gt;',
    '"': '&quot;',
    "'": '&#x27;',
    '`': '&#x60;'
};

事實上,僅僅這樣作仍是不夠的

那爲何要進行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解析過程當中,若是要求輸出值爲 < > ,那麼輸入值應該爲其對應的實體 &lt; &gt;

 

字符實體以&開頭 + 預先定義的實體名稱,以分號結束,如「<」的實體名稱爲&lt; 

或以&開頭 + #符號 以及字符的十進制數字,如」<」的實體編號爲&#60;

或以&開頭 + #x符號 以及字符的十六進制數字,如」<」的實體編號爲&#x3c;

字符都是有實體編號的但有些字符沒有實體名稱。

 

普通編碼與實體編碼的在線轉換

1.3.2 Javascript編碼

Unicode 是字符集,而 utf-8,utf-16,utf-32 是編碼規則

最經常使用的如「\uXXXX」這種寫法爲Unicode轉義序列,表示一個字符,其中xxxx表示一個16進制數字

如」<」 Unicode編碼爲「\u003c」,不區分大小寫

普通編碼與Unicode轉義序列的在線轉換

Unicode字符集大全

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&lt;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=1&#37;&#50;&#54;b=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="&#92;&#117;&#48;&#48;&#54;&#49;&#92;&#117;&#48;&#48;&#54;&#99;&#92;&#117;&#48;&#48;&#54;&#53;&#92;&#117;&#48;&#48;&#55;&#50;&#92;&#117;&#48;&#48;&#55;&#52;&#40;&#49;&#41;">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="&#106;&#97;&#118;&#97;&#115;&#99;&#114;&#105;&#112;&#116;&#58;&#97;&#108;&#101;&#114;&#116;&#40;&#49;&#37;&#51;&#67;&#50;&#41;">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('&#x27;);alert(&#x27;11')">test</span>

解碼順序先是進行HTML解碼,此時會將 &#x27解析成 ' 號,接着進行Javascript的解碼,識別到 ' 便可閉合test函數,調用成功

因此,這種狀況下,後端須要先進行Javascript編碼再進行HTML的編碼

 

固然,還有其餘順序的混合。也須要考慮編碼工做能不能正確地進行過濾

<a href="javascript:window.open('[輸入源]')">

解碼順序:

HTML解碼 -> URL解碼 -> Javascript解碼 -> URL解碼

 

引伸出去,還有一些字符集的知識點,腦袋疼,就不在這整理了

 

1.4 常見XSS攻擊方式

XSS的攻擊腳本多種多樣,在使用了模板(前端模板和後端模板)以後,須要格外注意數據的輸入輸出

下面列舉幾個常見的

 

1.4.1 PHP使用Yii框架中的Smarty模板

有時候會使用 $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">

在線 base64編碼解碼

解決方式爲:

不使用 $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的值已經被後端轉義爲實體符&gt; 那麼Handlebars將會轉換成 &amp;gt; 在瀏覽器中將會顯示 &gt; -->
<!-- 因此此時須要先將 &gt; 轉回 > 再傳入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&param=%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&#58;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 插件問題,可能還有相關插件沒有這些意識,平時也要注意

另外,站點自身在讀取文件信息時也要注意,攻擊者在上傳文件前,可能會對文件的信息進行修改,過濾不當極可能就形成嚴重的存儲型漏洞

相關文章
相關標籤/搜索