瀏覽器工作原理與XSS-HTML編碼

?簡介

編碼問題一直是個痛點,尤其是當(dāng)我們對XSS攻擊原理不是很熟悉的話,防護(hù)起來很容易造成遺漏佛玄。要想很好的防護(hù)住XSS攻擊,需要對瀏覽器解析HTML累澡、JS梦抢、CSS的原理弄清楚,了解瀏覽器的工作原理愧哟,才能做好防護(hù)工作奥吩。小編也是搜集網(wǎng)上資料進(jìn)行學(xué)習(xí),并整理分享下該篇文檔翅雏。


(一)瀏覽器的結(jié)構(gòu)?

瀏覽器的主要組件,包含用戶界面人芽、瀏覽器引擎望几、呈現(xiàn)引擎、網(wǎng)絡(luò)萤厅、用戶界面后端橄抹、JavaScript解釋器、數(shù)據(jù)存儲惕味。這里我們主要需要了解呈現(xiàn)引擎楼誓,其主要負(fù)責(zé)顯示請求內(nèi)容,如果請求的內(nèi)容是HTML名挥,它就負(fù)責(zé)解析HTML和CSS內(nèi)容疟羹,并將解析后的內(nèi)容顯示在屏幕上。

值得注意的是禀倔,Chrome瀏覽器的每個標(biāo)簽頁都分別對應(yīng)一個呈現(xiàn)引擎實例榄融,每個標(biāo)簽頁都是獨立的進(jìn)程。

呈現(xiàn)引擎一開始會從網(wǎng)絡(luò)層獲取請求文檔的內(nèi)容救湖,內(nèi)容的大小一般限制在 8000 個塊以內(nèi)愧杯。

呈現(xiàn)引擎解析HTML文檔,將標(biāo)記轉(zhuǎn)換成內(nèi)容樹上的DOM節(jié)點鞋既,將CSS元素樣式轉(zhuǎn)換成另外的樹結(jié)構(gòu):呈現(xiàn)樹力九。構(gòu)建完成后,進(jìn)入布局階段邑闺,每個節(jié)點都會分配一個應(yīng)該出現(xiàn)在屏幕上的坐標(biāo)跌前,由用戶界面后端層將每個節(jié)點繪制出來。

解析的過程其實就是編譯原理那一套東西陡舅,由解析器和詞法分析器將文檔內(nèi)容構(gòu)造成一個有效的解析樹舒萎,最后由翻譯器,將解析樹翻譯成瀏覽器可執(zhí)行的機(jī)器指令,最后我們看到的就是一個可視化的web頁面臂寝。

HTML解析器的任務(wù)是將HTML標(biāo)記解析成解析樹章鲤,常規(guī)解析器是不適用與HTML的,因為我們知道HTML具有很強(qiáng)的容錯性咆贬,并不是與上下文無關(guān)的語法败徊,我們會通過document.write添加額外的標(biāo)記。HTML的定義采用了DTD格式掏缎,包括允許使用的元素及其屬性和層次結(jié)構(gòu)皱蹦。HTML的解析是瀏覽器通過標(biāo)記化、樹結(jié)構(gòu)的形式完成解析構(gòu)建的眷蜈。

CSS是上下文無關(guān)的語法沪哺,可以使用常規(guī)的解析器進(jìn)行解析。??關(guān)于具體如何解析酌儒,便不在這里闡述辜妓,大家只需要有個大致的了解即可。

處理腳本和樣式表的順序

HTMl==》CSS==》JavaScript 針對這個順序我是報遲疑態(tài)度的忌怎,因為上述我們也提到過籍滴,在遇到<script>腳本時會立即解析并執(zhí)行腳本,文檔解析將停止榴啸,直到腳本執(zhí)行完畢孽惰。如果腳本是外部的,解析過程會停止鸥印,直到從網(wǎng)絡(luò)同步抓取資源完成后再繼續(xù)勋功。在HTML5中增加了一個選項,可將腳本標(biāo)記為異步库说,以便由其它線程解析和執(zhí)行酝润。

?(二)瀏覽器解碼過程?

HTMl==》CSS==》JavaScript ,針對這個解析順序璃弄,我們這里可以先不討論要销,我們的目的是關(guān)心如何正確的編碼,那么我只需要關(guān)注夏块,對于常用的HTML頁面疏咐,瀏覽器是如何解碼的即可。

1脐供、HTML實體

<p>${content}</p>

如上述代碼所示浑塞,在P標(biāo)簽中存在一個輸出變量${content},瀏覽器解析的過程政己,首先是HTML解析酌壕,解析到P標(biāo)簽時,解析Content的內(nèi)容,然后將其在頁面顯示出來卵牍。

<p><script>alert("實體XSS");</script></p>

如果我們把Content的內(nèi)容換成上面內(nèi)容果港,即script腳本,那么瀏覽器解析的時候糊昙,當(dāng)解析到P標(biāo)簽時辛掠,發(fā)現(xiàn)里面的內(nèi)容存在script標(biāo)簽,便會把其當(dāng)做JavaScript腳本進(jìn)行解析释牺,從而達(dá)到XSS攻擊的目的萝衩。

?所以針對此類HTML實體間的輸出,我們希望輸出的是HTML文本內(nèi)容没咙,而不是HTML標(biāo)簽猩谊、JS代碼等,所以我們在輸出時祭刚,需要對Content進(jìn)行HTML編碼,可使用OWASP ESAPI的ESAPI.encoder().encodeForHTML()牌捷。 HTML編碼一般將如下幾個字符進(jìn)行編碼替換:

1. & —> &amp;

2. < —> &lt;

3. > —> &gt;

4. " —> &quot;

5. ' —> &#x27;

6. / —> &#x2F;

在編碼的字符中,其中&袁梗、<宜鸯、>憔古、"遮怜、' 五個字符是XML中定義的實體,所以我們需要對其進(jìn)行編碼鸿市,因為HTML也算作XML的一種锯梁,/ 字符作為HTML標(biāo)簽的結(jié)束協(xié)助符,避免破壞標(biāo)簽焰情。

HTML編碼的作用就是將原本能被HTML解析成標(biāo)簽的東西陌凳,轉(zhuǎn)換成字符串文本,以文本的形式展現(xiàn)

2内舟、HTML通用屬性

<input name="${firstname}" ></input>

name是input的屬性合敦,所以HTML解析時,會對name屬性的內(nèi)容進(jìn)行HTML解碼验游,假如此時${firstname}的值為如下內(nèi)容時充岛,HTML屬性被截斷插入了onclick事件。

<input name=" " onclick="alert('屬性XSS')" " "></input>

所以針對這種常規(guī)的HTML屬性耕蝉,都需要對其進(jìn)行HTML屬性編碼崔梗,其實和HTML實體編碼類似,只不過編碼字符范圍可能多些垒在,除了字母數(shù)字外蒜魄,所有ASCII碼小于256的字符均進(jìn)行&#XXX;編碼,具體的參見ESAPI.encoder().encodeForHTMLAttribute的實現(xiàn)。其實屬性XSS中最主要的是拆分屬性標(biāo)簽谈为,注入可執(zhí)行JS的屬性旅挤,并對其添加而已代碼。

對于通用屬性的編碼方式不適用于href峦阁、src谦铃、style、事件處理函數(shù)(onclick榔昔、onmouseover等)驹闰,因為本身這些屬性是支持偽協(xié)議的,該編碼無效撒会。

3嘹朗、支持協(xié)議解析的HTML屬性

在上述的2中場景中我們都可以使用HTML編碼,基本都能夠很好的防御住XSS攻擊诵肛,在第二點中我們強(qiáng)調(diào)的是HTML通用屬性屹培,而并非全部屬性,因為在HTML中H還存在許多支持協(xié)議解析的HTML屬性怔檩,如onclick褪秀,onerror,href薛训,src等媒吗,類似這種屬性是無法通過HTML編碼防范XSS攻擊,因為瀏覽器會先解析HTML編碼的字符乙埃,將其轉(zhuǎn)換為該屬性的值闸英,但是該屬性本身支持JS代碼執(zhí)行,所以瀏覽器在HTML解碼后介袜,對該屬性的值進(jìn)行JS解析甫何,故會執(zhí)行相應(yīng)的代碼。

3.1 href屬性引入的XSS

<a href="javascript:alert('href xss')" target="_blank">href xss</a>

<a href="javascript&#x3a;alert&#x28;&#x27;href&#x20;xss&#x20;HTML編碼無效&#x27;&#x29;" target="_blank">href xss HTML屬性編碼無效</a>

href屬性的值應(yīng)該是一個有效的URL鏈接遇伞,如果我們對整個href屬性值進(jìn)行URL編碼辙喂,則會導(dǎo)致URL無法跳轉(zhuǎn),應(yīng)為瀏覽器在解析href時鸠珠,會通過分號巍耗、/字符解析出協(xié)議或目錄,當(dāng)對全部的值進(jìn)行URL編碼后跳芳,則無法進(jìn)行正常解析芍锦;如果對協(xié)議后的內(nèi)容進(jìn)行URL編碼則也無法防御XSS攻擊,如下例所示:

<a href="javascript:%61%6c%65%72%74%28%27%68%72%65%66%20%78%73%73%20URL部分編碼無效%27%29" target="_blank">Href xss 部分URL編碼無效</a>

此時假如我們對alert('href xss')進(jìn)行JavaScript編碼飞盆,結(jié)果又會如何娄琉?(JavaScript編碼將字符編碼成\x+16進(jìn)制的形式次乓,對款字節(jié)編碼成Unicode)

<a href="javascript:alert\x28\x27href xss\x27\x29" target="_blank" >Href XSS JavaScript編碼</a>

測試點擊沒有任何反應(yīng),XSS執(zhí)行失斈跛票腰;

問什么會存在上述的結(jié)果?我們看一下href屬性的解碼解析過程女气,頁面渲染杏慰,首先進(jìn)行HTML解碼解析,解析出是href屬性后(點擊)炼鞠,會對href的值進(jìn)行URL解碼解析缘滥,獲取到URL的實際值,當(dāng)發(fā)現(xiàn)不是HTTP/HTTPS谒主,而是JavaScript協(xié)議后朝扼,就會執(zhí)行JavaScript解碼解析,從而執(zhí)行了alert()函數(shù)霎肯。

3.2 onclick屬性XSS

現(xiàn)在我們來看一下on事件屬性:<p id="addlinecontent" onclick="addlinecontent($value)">點擊增加一行顯示</p> (此處的$value往往一般都是后臺模板替換的變量)

<p id="addlinecontent" onclick="addlinecontent('$value')">點擊增加一行顯示</p>

<script>

function addlinecontent(value){

? ? document.getElementById("addlinecontent").innerText=value;

}

</script>

當(dāng)$value的值 hello world'),alert('onclick xss 時擎颖,出發(fā)XSS攻擊:

<p id="addlinecontent" onclick="addlinecontent('hell0 world'),alert('onclick xss')" >

對$value進(jìn)行HTML編碼:hello world&#x27;&#x29;&#x2c;alert&#x28;&#x27;onclick xss htmlencode ,結(jié)果顯示如下观游,存在XSS

此時如果將$value進(jìn)行JavaScript編碼:顯示正常搂捧,不存在XSS

onclick屬性解析的過程:先進(jìn)行HTML解析,再進(jìn)行JavaScript解析懂缕,所以僅僅進(jìn)行HTML編碼是無法防御XSS的允跑,需要對值進(jìn)行JavaScript編碼。

如果當(dāng)存在 <input name="username" onclick="$event" />這種情況時提佣,是很難進(jìn)行防護(hù)的吮蛹,因為無法直接對$event進(jìn)行JavaScript編碼荤崇,如果編碼了拌屏,則無法解析出需要執(zhí)行的函數(shù)代碼。如果整個內(nèi)容是來自客戶端輸入的术荤,那么需要對event需要進(jìn)行黑白名單的校驗倚喂,防止出現(xiàn)危險字符,防止調(diào)用危險的JS函數(shù)。通常不建議出現(xiàn)這種寫法瓣戚,建議對event進(jìn)行拆分端圈,通過控制參數(shù)達(dá)到相應(yīng)的目的:

<input name="" onclick="event(encodeForJS(${eventType}))" />

關(guān)于如何編碼,需要抓住一個重點子库,就是傳進(jìn)的值最終是誰消費(fèi)(期望執(zhí)行者)舱权,誰消費(fèi)誰負(fù)責(zé);對于支持偽協(xié)議的屬性仑嗅,僅僅通過編碼是不行的宴倍,需要匹配過濾協(xié)議頭张症,最好后臺拆分拼接返回期望的值。(不能對協(xié)議類型進(jìn)行任何的編碼操作鸵贬,否則URL解析器會認(rèn)為它無類型)

編碼的順序和解碼解析的順序正好相反:

<p onclick="alert('\x26\x23\x78\x32\x32\x3b')">jsencode(htmlencode("))</p>

<p onclick="alert('&#x5c;&#x78;&#x32;&#x32;')">htmlencode(jsencode("))</p>

4俗他、DOM XSS類型

DOM XSS是基于文檔對象模型的XSS,屬于反射型XSS阔逼。

1. 使用document.write直接輸出

2. 使用innerHTML直接輸出

3. 使用location兆衅、location.href、location.replace嗜浮、iframe.src羡亩、document.referer、window.name等

.......

造成DOM XSS的原因主要是在重新修改頁面時危融,沒有考慮到對變量的編碼和校驗過濾夕春;

<script>

? ? document.body.innerHTML="url:<a href=' "+url+" '>" +url+"</a> ";

</script>

其中對于變量url則是注入點:javascript:alert('dom xss');??

對于DOM XSS主要是由于本地客戶端獲取DOM數(shù)據(jù)在本地執(zhí)行導(dǎo)致的,所以在編碼中专挪,要避免客戶端文檔重寫及志,重定向或其它修改DOM元素操縱,對于輸出至HTML中的值進(jìn)行HTML編碼寨腔,輸出至JS中的值進(jìn)行JS編碼速侈。

5、setTimeout/setInterval/eval等XSS

針對這類的XSS迫卢,我們單獨拿出來說倚搬,因為這類XSS隱藏的相對比較深,尤其經(jīng)過JS層層封裝的函數(shù)乾蛤,我們不知道底層是否使用了這些函數(shù)每界,是否存在變量傳入?

這類函數(shù)有一個共性家卖,函數(shù)本身就是JS函數(shù)眨层,但是能夠?qū)魅氲膮?shù)當(dāng)做JS代碼執(zhí)行。

<textarea id="settimeoutxss" onclick="updatecontent('$value')" rows="8" cols="40"></textarea>

<script>

function updatecontent(url){

????setTimeout("showURL('"+url+"')");

}

function showURL(url){

????document.getElementById("settimeoutxss").value=url;

}

</script>

當(dāng)$value的值為:hello world\'\);alert\(0\);eval(\' 上荡,XSS攻擊成功

當(dāng)你在onclick="updatecontent('$value')"處趴樱,對$value進(jìn)行HTML編碼后,XSS攻擊依舊存在酪捡;

<p onclick="updatecontent('hello world HTML編碼叁征,依舊存在XSS&#x27;&#x29;&#x3b;alert&#x28;1&#x29;&#x3b;eval&#x28;&#x27;')">Click setTimeOut HTMLEncode</p>

當(dāng)你在onclick="updatecontent('$value')"處,對$value進(jìn)行JavaScript編碼后逛薇,XSS攻擊依舊存在捺疼;(有興趣的可以試一試)

<p onclick="updatecontent('hello world JavaScript編碼,依舊存在XSS\x27\x29\x3balert\x282\x29\x3beval\x28\x27')">Click setTimeout JavaScriptEncode</p>

如果要想對$Value進(jìn)行編碼防范xss永罚,需要對其進(jìn)行doublejsencode啤呼,一次JavaScript編碼是不夠议薪,需要2次,才能保證傳入setTimeout中的參數(shù)url只是個字符串媳友。如果僅僅進(jìn)行一次javascript編碼斯议,能夠保證updatecontent函數(shù)傳入的是字符串,但是setTimeout會將該字符串當(dāng)做代碼執(zhí)行醇锚,如果進(jìn)行2次JS編碼哼御,在setTimeout接收到的參數(shù)是一次JS編碼的值,只會對其進(jìn)行一次JS解碼焊唬,當(dāng)做字符串處理恋昼。

<p onclick="updatecontent('hello world \x5cx27\x5cx29\x5cx3balert\x5cx282\x5cx29\x5cx3beval\x5cx28\x5cx27')">Click setTimeout Double JavaScriptEncode</p>

相關(guān)參考:

新式網(wǎng)絡(luò)瀏覽器幕后揭秘:

www.html5rocks.com/zh/tutorials/internals/howbrowserswork/#The_browser_main_functionality

XSS的原理分析與解剖:XSS的原理分析與解剖 - FreeBuf.COM

瀏覽器Lexer與XSS-HTML編碼:瀏覽器Lexer與XSS-HTML編碼 - FreeBuf.COM

XSS (Cross Site Scripting) Prevention Cheat Sheet:

www.owasp.org/index.php/XSS_(Cross_Site_Scripting)_Prevention_Cheat_Sheet

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市赶促,隨后出現(xiàn)的幾起案子液肌,更是在濱河造成了極大的恐慌,老刑警劉巖鸥滨,帶你破解...
    沈念sama閱讀 222,590評論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件嗦哆,死亡現(xiàn)場離奇詭異,居然都是意外死亡婿滓,警方通過查閱死者的電腦和手機(jī)老速,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,157評論 3 399
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來凸主,“玉大人橘券,你說我怎么就攤上這事∏渫拢” “怎么了旁舰?”我有些...
    開封第一講書人閱讀 169,301評論 0 362
  • 文/不壞的土叔 我叫張陵,是天一觀的道長嗡官。 經(jīng)常有香客問我箭窜,道長,這世上最難降的妖魔是什么谨湘? 我笑而不...
    開封第一講書人閱讀 60,078評論 1 300
  • 正文 為了忘掉前任绽快,我火速辦了婚禮芥丧,結(jié)果婚禮上紧阔,老公的妹妹穿的比我還像新娘。我一直安慰自己续担,他們只是感情好擅耽,可當(dāng)我...
    茶點故事閱讀 69,082評論 6 398
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著物遇,像睡著了一般乖仇。 火紅的嫁衣襯著肌膚如雪憾儒。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,682評論 1 312
  • 那天乃沙,我揣著相機(jī)與錄音起趾,去河邊找鬼。 笑死警儒,一個胖子當(dāng)著我的面吹牛训裆,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播蜀铲,決...
    沈念sama閱讀 41,155評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼边琉,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了记劝?” 一聲冷哼從身側(cè)響起变姨,我...
    開封第一講書人閱讀 40,098評論 0 277
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎厌丑,沒想到半個月后定欧,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,638評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡怒竿,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,701評論 3 342
  • 正文 我和宋清朗相戀三年忧额,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片愧口。...
    茶點故事閱讀 40,852評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡睦番,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出耍属,到底是詐尸還是另有隱情托嚣,我是刑警寧澤,帶...
    沈念sama閱讀 36,520評論 5 351
  • 正文 年R本政府宣布厚骗,位于F島的核電站示启,受9級特大地震影響多搀,放射性物質(zhì)發(fā)生泄漏概漱。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 42,181評論 3 335
  • 文/蒙蒙 一篙挽、第九天 我趴在偏房一處隱蔽的房頂上張望冲秽。 院中可真熱鬧舍咖,春花似錦、人聲如沸锉桑。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,674評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽民轴。三九已至攻柠,卻和暖如春球订,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背瑰钮。 一陣腳步聲響...
    開封第一講書人閱讀 33,788評論 1 274
  • 我被黑心中介騙來泰國打工冒滩, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人浪谴。 一個月前我還...
    沈念sama閱讀 49,279評論 3 379
  • 正文 我出身青樓旦部,卻偏偏與公主長得像,于是被迫代替她去往敵國和親较店。 傳聞我的和親對象是個殘疾皇子士八,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,851評論 2 361

推薦閱讀更多精彩內(nèi)容