SS(跨站腳本攻擊),是最普遍的Web應用安全漏洞。這類漏洞使攻擊者能夠嵌入惡意腳本代碼到頁面中,當正常用戶訪問時,就會導致惡意腳本的執行,從而達到攻擊用戶的目的。那有什么辦法能夠防止被攻擊呢?JX-XSS就是你忠實的守護者。
XSS攻擊
JS-XSS,是 leizongmin 在Github 上開源的防御XSS攻擊的JS庫,倉庫地址為 https://github.com/leizongmin/js-xss,目前版本為 1.0.7。JS-XSS 通過對用戶輸入的內容進行過濾來保護網站免受XSS攻擊,支持通過白名單控制允許的HTML標簽及各標簽的屬性,支持通過自定義處理函數對任意標簽及其屬性進行處理,還提供了一系列的接口以便用戶擴展,比其他同類模塊更為靈活。JS-XSS 主要用于論壇、博客、網上商店等等一些可允許用戶錄入頁面排版、 格式控制相關的HTML的場景,能有效過濾惡意XSS攻擊腳本。
JS-XSS庫
JS-XX可以在Node.js中使用,使用 NPM 或 Bower 安裝:
npm install xss
bower install xss
也可以在瀏覽器中使用:
<script src="https://raw.github.com/leizongmin/js-xss/master/dist/xss.js"></script>
在Node.js中使用時,使用函數 xss 進行過濾:
var xss = require("xss");
var html = xss('<script>alert("xss");</script>');
console.log(html);
而在瀏覽器中,則使用 filterXSS 函數,用法一樣:
<script>
var html = filterXSS('<script>alert("xss");</scr' + 'ipt>');
alert(html);
</script>
可以看到,輸入是一個HTML的script標簽,如果未經處理就在頁面上渲染,標簽中的腳本就會運行,發出“xss”的提示,這是一個最簡單的XSS攻擊。而通過JS-XSS的處理后,運行結果如下:
JS-XSS示例運行結果
JS-XSS把script標簽的尖括號進行了轉義,使得XSS攻擊腳本不再執行,阻止了XSS攻擊。
我們也可以對過濾規則進行自定義,通過傳入options參數實現:
html = filterXSS(input, options);
我們也可以創建一個FilterXSS實例來避免每次都傳入參數:
myxss = new xss.FilterXSS(options);
html = myxss.process('<script>alert("xss");</script>');
參數options包括許多配置項:
// 只允許a標簽,該標簽只允許href, title, target這三個屬性
var options = {
whiteList: {
a: ['href', 'title', 'target']
}
};
// 使用以上配置后,下面的HTML
// <a href="#" onclick="hello()"><i>大家好</i></a>
// 將被過濾為
// <a href="#">大家好</a>
// 只保留網頁文本
var source = "<strong>hello</strong><script>alert(/xss/);</script>end";
var html = xss(source, {
whiteList: [],
stripIgnoreTag: true,
stripIgnoreTagBody: ["script"]
});
console.log("text: %s", html);
// 輸出:
// text: helloend
可以通過提供的自定義函數接口進行XSS過濾行為的擴展和自定義。
XSS攻擊
JS-XSS使用簡單,在用戶輸入場景中,可以很方便地進對輸入內容進行過濾處理,在前端就處理掉可能的XSS攻擊腳本。同時JS-XSS可配置性強,可以通過白名單機制,和豐富的自定義處理函數,使JS-XSS可以在不同場景下進行XSS攻擊的防御。
JS-XSS已在實踐中廣泛應用,示例豐富,且提供了在線測試功能,是一個值得使用的JS網絡安全庫。
面幾篇文章我們講到了跨站腳本(XSS)漏洞的幾種類型和驗證方法以及防御措施,有興趣的朋友可以到我的主頁翻看文章《十大常見web漏洞——跨站腳本漏洞》和《實操web漏洞驗證——跨站腳本漏洞》,今天我們繼續由易到難實戰演示一下跨站腳本漏洞的形成,以便更好地了解漏洞的產生原理,進一步做好防御。
上一篇文章我們已經闖過了5關,今天我們繼續。
html事件是在滿足一定條件的用戶行為發生時,所觸發的的事件,例如當單擊鼠標時的“onclick”以及當瀏覽器加載圖像時的“onload”,我們可以將這些特定的html事件發生時,將JavaScript語句作為屬性傳遞給特定的標簽,從而構成一個或多個JavaScript命令或函數。
下圖我們從網上搜索了一些html事件屬性,有興趣的可以自己搜索學習。
html事件屬性
在這一關中,我們可以構造語句:
111" onmouseover="alert(document.domain);"
前邊的“111"”是為了閉合標簽,后邊的“onmouseover”屬性表示當鼠標移動到輸入框時執行后邊的語句,點擊“search”按鈕,將鼠標移動到輸入框時,頁面在彈出內容為當前頁面域名的彈窗后,提示“恭喜!”,就可以順利進入下一關了,如下圖所示:
恭喜通關
這一關我們先來探測一下注入點的情況,我們和之前一樣先閉合標簽,輸入“123456"”來閉合標簽,找到對應的代碼,發現我們輸入的內容被另一對引號括住了,如下圖所示:
頁面代碼
這表明我們輸入的內容直接被實體化了,那我們不使用引號閉合,直接輸入“123456 onmouseover=“alert(document.domain)””,發現只要是等號后邊的參數都被引號括了起來,如下圖所示:
頁面代碼
因此我們都不加引號,構造:
123456 onmouseover=alert(document.domain)
注意中間有個空格,點擊“search”按鈕時,頁面在彈出內容為當前頁面域名的彈窗后,提示“恭喜!”,就可以順利進入下一關了,如下圖所示:
恭喜通關
有時候我們需要將JavaScript代碼添加到客戶端中,這時就需要JavaScript偽協議來幫助,它的格式為JavaScript:url,例如:JavaScript:alert("hello word!"),就是一個簡單的通過JavaScript偽協議來執行alert("hello word!")語句,它表示在頁面顯示“hello word!”。
因此我們可以構造語句
JavaScript:alert(document.domain);
點擊“Make a Link”按鈕時,可見輸入框下邊出現一個URL超鏈接,我們點擊這個鏈接,如下圖所示:
URL超鏈接
頁面在彈出內容為當前頁面域名的彈窗后,提示“恭喜!”,就可以順利進入下一關了,如下圖所示:
恭喜通關
這個比較簡單,因為UTF-7絕大多數瀏覽器都已經不用了,我們很少會遇到,因此我們直接構造語句:
onclick=alert(document.domain);
我們按F12鍵,根據下圖提示找到第三步位置,將以上語句寫入到對應位置,再點擊第二步的位置,如下圖所示:
修改頁面代碼
頁面在彈出內容為當前頁面域名的彈窗后,提示“恭喜!”,就可以順利進入下一關了,如下圖所示:
恭喜通關
首先我們還是老辦法構造閉合語句,如下所示:
"><script>alert(document.domain);</script>
點擊“search”,按F12,找到如下圖紅框中的位置,發現我們上邊構造的語句中“domain”被刪除了,如下圖所示:
頁面代碼
既然被刪除了,這時我們可以通過雙寫來繞過domain被刪除這種情況,我們可以構造:
"><script>alert(document.dodomainmain);</script>
注意我們在單詞domain中間又加了一個單詞domain,這時系統在刪除一個單詞domain后,還會留下一個domain,這樣我們就成功執行了語句了。
點擊“search”按鈕時,頁面在彈出內容為當前頁面域名的彈窗后,提示“恭喜!”,就可以順利進入下一關了,如下圖所示:
恭喜通關
當然我們也可以通過編碼的方法來繞過,我們可以構造:
"><script>eval(atob('YWxlcnQoZG9jdW1lbnQuZG9kb21haW5tYWluKTs='));</script>
其中“eval”是用來執行字符串,其后邊的內容會當成JavaScript語句執行,“atob”表示將加密的base64密文,轉換成原文,而里邊的一串亂碼就是通過base64加密過的的“alert(document.domain)”語句,關于加密,有興趣的可以閱讀我的文章《Web滲透測試——密碼學基礎》,其實和上邊的語句一樣,這樣就可以避免domain被刪除了。
以上就是跨站腳本(XSS)漏洞實戰演示——由易到難第二部分的全部內容,希望對你了解XSS漏洞有所幫助,歡迎關注@科技興了解更多科技尤其是網絡安全方面的資訊和知識。
天呀,我想當一名黑客,去黑別人的網站!我有兩三技能,獨樂不如眾樂樂,今天我也把這個幾個攻擊手段教給你,咱們一起搞事情去。
首先我們來了解一下攻擊手段,也是比較常見的兩種攻擊手段了:
CSRF
全稱:Cross-site request forgery,跨站請求偽造。原理是:通過偽裝成受信任用戶的請求來攻擊受信任的網站。
如何偽裝?如何才算攻擊?
生活中其實我們不缺這種例子,比如說我們經常接收到一些來歷不明的垃圾短信,短信內容里面有個url鏈接,有些人手賤點開了鏈接,然后就發現錢不見了!!
我們從技術角度來復原一下這個過程,首先設定一些基礎:
然后用戶動作是:點開了垃圾網的鏈接,但是存錢網里賬戶的錢不見了。既然是自己賬戶的錢不見了,所以這里其實有個前提:用戶已經登錄了存錢網!所以準確來說用戶的動作是這樣的:點開了垃圾網的鏈接,但是之前登錄過的存錢網里賬戶的錢不見了!
兩個網站毫無關聯,為啥會造成這個讓人意想不到的后果呢?
其實呀,垃圾網的人為了達到攻擊的目的,偷偷在網頁上嵌入了存錢網的鏈接,所以打開垃圾網時候順便也觸發了存錢網的轉賬的鏈接,整體邏輯如下:
說到這里,你發現漏洞在哪里沒有?大家都知道cookie代表用戶身份,每次發起請求,請求頭里都會附上用戶的cookie信息,既然cookie是存在瀏覽器的,我偷不到你的cookie,那么我就讓你在不知道到的情況下讓你自己去操作。
舉個例子:假如一家銀行轉賬操作的URL地址如下:
http: //www.cunqianwang.com/zhuanzhang?account=A&for=B&amount=500
那么,一個垃圾網中可以放置如下代碼
<img src = "http://www.cunqianwang.com/zhuanzhang?account=A&for=B&amount=500" >
好了,原理和攻擊手段我們都懂了,那么我們來說說幾種常見的預防手段:
1、檢查referer字段
HTTP頭中有一個Referer字段,這個字段是用來標明請求來源于哪一個網址。當網站A去訪問網站B的資源時候,鏈接上的請求頭上就會有Referer字段。注意是在不同域名下才有。
我隨意打開hao123.com的首頁,一些圖片不是放在hao123.com域名下的,所以會在header中帶上Referer字段表示請求源是hao123.com。
那么服務器可以通過判斷Referer字段來判斷請求的來源。所以在垃圾網站里訪問存錢網,Referer的值就是垃圾網的域名,就能判斷是不是合法的操作啦。
java代碼里獲取Referer字段值代碼是:
String referer = request.getHeader( "Referer" );
這種方法簡單易行,但也有其局限性。http協議無法保證來訪的瀏覽器的具體實現,可以通過篡改Referer字段的方式來進行攻擊,所以就要看你用的瀏覽器高級不高級了,如果你用的瀏覽剛好是騙子開發的瀏覽器,嘿嘿~~
2、Token 驗證
既然我們要判定用戶行為的合法性,那么我就給用戶頒發一個合法token,除了帶上cookie,還得帶上token才行,token在前一個步驟中獲取。
邏輯如下:
3、添加圖片驗證碼、短信驗證等
重要步驟添加驗證碼認證后才能操作。腦補,略略略略~
學會攻擊
好了,作為一名出色的黑客,必須要知道自己攻擊手段的漏洞在哪,怎么防御,絕不做無用功!既然預防手段我知道了,那么接下來就是我展現真正技術的時候了。
嘿嘿,很多公司在一開始的時候為了節約成本,選擇用開源項目作為基礎,然后再二次開發。雖說開發快,但其實未必安全,一些開源項目如果沒有做csrf的預防,那么漏洞就一直存在。
經過我多天的研究,終于發現了某個商城用的是開源項目二次開發的,沒有csrf預防。商城的積分可以直接贈送給別人,我立馬搞了個網頁,嵌入網站贈送積分的鏈接。
于是有了我和我朋友的對白。
當黑客感覺真好,小明,你是個好人~
XSS
全程:Cross Site Scripting,中文:跨域腳本攻擊。原理:不需要你做任何的登錄認證,通過合法的操作(比如在url中輸入、在評論框中輸入),向你的頁面注入腳本(可能是js、hmtl代碼塊等),類似于SQL注入。
通俗點講就是:惡意攻擊者往Web頁面里插入惡意html代碼,當用戶瀏覽該頁之時,嵌入其中Web里面的html代碼會被執行,從而達到惡意用戶的特殊目的。
講再細點其實就是:利用輸入內容來閉合對應的html標簽,從而執行輸入內容的腳本。
攻擊形態
xss有兩種形態(網友總結):
發出請求時,XSS代碼出現在url中,作為輸入提交到服務器端,服務器端解析后響應,XSS代碼隨響應內容一起傳回給瀏覽器,最后瀏覽器解析執行XSS代碼。這個過程像一次反射,所以叫反射型XSS。
存儲型XSS和反射型XSS的差別在于,提交的代碼會存儲在服務器端(數據庫、內存、文件系統等),下次請求時目標頁面時不用再提交XSS代碼。
攻擊手段
不管是什么類型,你get到關鍵點沒有?關鍵點以及技術難點其實在于如何往頁面中嵌入惡意的代碼。
下面我們來寫個例子模擬一下:首先我頁面寫了個form表單:
<form action = "/submit" method = "post" > 名稱: <input name = "name" value = "${name}" > <input type = "submit" > </form>
controller中有個基本跳轉,還有form表單的提交:
@GetMapping ( "" ) public String index( HttpServletRequest request) { request.setAttribute( "name" , "公眾號:java思維導圖" ); return "index" ; } @PostMapping ( "/submit" ) public String submit( HttpServletRequest request) { String name = request.getParameter( "name" ); System . out .println( "name---------->" + name); // 假裝只有名字為“求關注”才能通過 if (!name.equals( "求關注" )) { request.setAttribute( "name" , name); } return "index" ; }
初始效果如下:
ok,基本邏輯也寫好了,一個簡單的表單提交,提交之后如果數據不對,或格式不對就會返回表單頁面,同時回顯表單數據。
加入我想嵌入腳本如下:
<script> alert( 1 ); </script>
那么我該怎么樣才能往這個頁面上嵌入代碼呢?我打開F12,研究一下
要是這個這個腳本能提到input的外面,value能提前結束就好了。嘿嘿,突然想到,既然我改不了原來的,那么我就創造一個。
于是我改了一下輸入的值成:
"><script>alert(1);</script>
這">不就跑到前面了嘛,哈哈哈,天才,我趕緊試試。谷歌瀏覽器測試結果如下:
腳本的確跑到外面了,但是alert(1)怎么不見了呀,我趕緊調試一下:
不是后端在搞事情,那么真相就只有一個,谷歌瀏覽器在搞事情,谷歌果然強大,還能辨別我的腳本并和諧掉。
我換個Edge瀏覽器再試試:
哇,果然Edge你最帥,我想要的你都給我~ F12看下:
沒毛病,原聲原味的alert(1);
好了上面我們已經弄懂了xss的嵌入腳本的方式,我們輸入是合法的,只是內容有點取巧,這就是xss的攻擊手段。
除了這個input標簽,其實還有很多標簽比較常用,比如title、a、img、script等。
上面這個一般都是反射性的xss攻擊,我們再來看看一個存儲類型的title的例子。
在很多博客中,我們都可以發布文章,我們需要寫文章標題,文章內容等,文章標題一般我們還會放在我們的head的title中,用于標簽展示當前瀏覽文章標題。
加入說,我們的頁面是這樣展示的:
<!DOCTYPE html> <html> <head> <title> ${title} </title> </head> <body> 這是內容 - ${content} </body> </html>
而controller中傳過來的內容如下:
@GetMapping ( "/title" ) public String title( HttpServletRequest request) { request.setAttribute( "title" , "</title><script>alert('公眾號java思維導圖');</script>" ); request.setAttribute( "content" , "內容是關注公眾號:java思維導圖" ); return "title" ; }
最后我們的得到的頁面展示這樣子:加載時候先執行彈窗:alert("公眾號java思維導圖");然后再加載內容。
因為一般我們文章標題內容都是保存到數據庫的,所以每次渲染都會執行腳本,所以是個存儲型xss攻擊。
解決方法
好了,看了我們的例子項目,我們已經意識到了xss攻擊的可怕性,一單發布文章都可以寫腳本,那么所有的用戶打開這篇文章都會被執行腳本,影響可就大了。那么有什么好的解決方法嗎?
這里給大家介紹幾個解決方法。我們先來看renren-fast項目是怎么解決這個問題的:
#識別攻擊腳本、并刪掉對應可執行腳本的標簽 HTMLFilter #全局過濾器,包裝request XssFilter #包裝request,重寫request的幾個重要方法,比如getParameter等 XssHttpServletRequestWrapper
所以renren-fast項目的設計邏輯是加入一個全局過濾器,然后通過包裝請求的request,重寫request的getParameter、getHeader、getInputStream等方法,在這些方法里面都進行一遍過濾,從而去掉所有的攻擊腳本。看看重要代碼:
public class XssFilter implements Filter { public void doFilter( ServletRequest request, ServletResponse response, FilterChain chain) throws IOException , ServletException { XssHttpServletRequestWrapper xssRequest = new XssHttpServletRequestWrapper ( ( HttpServletRequest ) request); chain.doFilter(xssRequest, response); } ... }
public class XssHttpServletRequestWrapper extends HttpServletRequestWrapper { @Override public String getParameter( String name) { String value = super .getParameter(xssEncode(name)); if ( StringUtils .isNotBlank(value)) { value = xssEncode(value); } return value; } ... }
可以看到上面的xssEncode就是進行過濾腳本的方法;xssEncode方法代碼如下:
private String xssEncode( String input) { return htmlFilter.filter(input); }
ok,相信你已經弄明白了。
我們來看看另一個博客項目mblog的解決方法:
#通用控制器 BaseController #自定義編輯器 StringEscapeEditor
mblog項目其實是通過注冊所有controller的自定義編輯器,在提交表單時候對所有字段都進行一層get和set,在set的過程中對輸入內容進行一番檢查,如果有腳本就進行替換等操作。
詳細代碼如下:
@InitBinder public void initBinder( ServletRequestDataBinder binder) { /** * 防止XSS攻擊 */ binder.registerCustomEditor( String . class , new StringEscapeEditor ( true , false )); ... }
@InitBinder用于表單到方法的數據綁定的,這里綁定了一個自定義編輯器StringEscapeEditor。
可以看到setAsText中就是對腳本進行過濾等操作的。
這兩種方法都學會了嗎?其實邏輯都是對腳本進行過濾替換刪除等操作。
學會攻擊
好了,又到了黑客show time,某個知名博客平臺沒防御xss攻擊,這時候我發布了一篇文章,title中包含了腳本
*請認真填寫需求信息,我們會在24小時內與您取得聯系。