一直以來,各大論壇和郵箱都允許使用外鏈圖片。一方面解決了上傳和保存帶來的資源消耗,更重要的是方便用戶轉載圖片。
然而,簡單的背后是否暗藏着什么風險呢?大多或許認為,不就是插入了一張外部圖片而已,又不是什么腳本或插件,能有多大的安全隱患。
曾經也有過外鏈圖片泄漏cookie那樣的重大隱患,不過那都是很久以前的事了。在如今瀏覽器日新月異的年代里,這樣的bug已經很難遇到了。不過利用正常的游戲規則,我們仍能玩出一些安全上的小花招。
No.1 —— HTTP401
(嚴重程度:低)
大家都見過,打開路由器的時候會彈出個登錄框。
如果了解HTTP協議的話,這是服務器返回401,要求用戶名密碼認證。
不過,如果是一個圖片的請求,返回401又會怎樣呢?很簡單,我們就用路由器的URL測試下:
<img src="http://192.168.1.1/">
居然依舊跳出了一個對話框!
如果將一個HTTP401的圖片插入到論壇里,是不是也會如此呢?我們用ASP寫個簡單的腳本,並且能自定義提示文字:
<% Response.Status = "401" Response.AddHeader "WWW-Authenticate", "Basic realm=IP IC IQ卡,統統告訴我密碼!" %>
然后將URL插入到論壇或空間(如果拒絕.asp結尾的url圖片,那就在后面加上個?.png)。
先在QQ空間里測試下:
不出所料,彈出了對話框。不過在ie外的瀏覽器下,漢字成了亂碼,即使設置了ASP以及HTTP的編碼也不管用。
我們只好換成英文字符,再百度貼吧里用各種瀏覽器測試下:
ie678:
ie9:
firefox:
safari:
除了Opera和Chrome沒有彈出來,其他的瀏覽器都出現。不過部分瀏覽器截斷了空格后的字符。
當然,你也可以擴展這個功能,記錄用戶輸入了什么內容。尤其是帶上些官方式的文字提示,很容易用來捕捉到一些賬號信息。曾經用這招在論壇抓到不少可用的賬號密碼,不過如今安全意識普遍提高,加上一些安全軟件的攔截,這招實用性大打折扣了。
因為是強制彈出的,往往給人一驚,所以在論壇,貼吧或空間里,倒是可以娛樂娛樂。
No.2 ———— GZip壓縮炸彈
( 嚴重程序:中)
在之前的一篇文章里,談到使用兩次deflate壓縮,將數百兆的圖片文件壓縮到幾百字節。
http://www.cnblogs.com/index-html/archive/2012/06/22/2558469.html
原理很簡單,大量重復數據有很高的壓縮率。之前不清楚的deflate算法的最大壓縮率有多少,一直不敢確定是不是最優的。后來大致了解了下算法,由於受到lz77算法的最大匹配長度限制,deflate的最大壓縮率確實只有1:1000多點。雖然和rar相比相差甚遠,不過1000倍也意味着,1M的數據可以翻到1G了。
所以我們可以利用一個超高的壓縮的HTTP報文,做幾件事:
1.消耗內存
2.消耗CPU
3.消耗緩存
對於現在的硬件配置,內存已經足夠支撐瀏覽器,多核的CPU也沒法完全耗盡,唯獨硬盤是個瓶頸。
我們用C程序創建個1G的內存數組,將圖片數據放在其首,后面用'\0'填充。然后使用zlib進行壓縮,得到1M左右的結果,保存為x.jpg.gz
接着用ASP讀取壓縮文件,並給返回的頭部加上Content-Encoding字段。
簡單的測試下:

Dim stream Set stream = Server.CreateObject("ADODB.Stream") With stream .Type = 1 .Open .LoadFromFile _ Server.MapPath(Request.QueryString("File") & ".gz") End With Dim agent agent = Request.Servervariables("HTTP_USER_AGENT") With Response If Instr(agent, "Firefox") > 0 Or Instr(agent, "AppleWebKit") > 0 Then .AddHeader "Content-Encoding", "deflate" Else .AddHeader "Content-Encoding", "gzip" End If .AddHeader "Content-Length", stream.Size .BinaryWrite stream.Read End With
由於部分瀏覽器的Content-Encoding只支持deflate.所以特意做了判斷,以免失效。
先用ie測試。打開GZip.ASP?file=x.jpg(測試地址:http://www.etherdream.com/Test/bomb.html),正常顯示出圖片,緊接着硬盤燈狂閃。。。關閉網頁之后,打開瀏覽器緩存文件夾。果然,1G大小緩存已產生!
接着用火狐測試。不過沒等圖片出來,瀏覽器已經卡死了。等了數分鍾仍然沒有響應,只得結束任務。
用Chrome測試。內存暴漲,最終圖片倒是正常顯示出來了,不過頁面經常崩潰。
Opera一切正常,也沒產生特別大的緩存文件。當然,不同版本的瀏覽器大不相同,可以自己測試。
不過,幾個最常用的瀏覽器有效果就行了。
我們可以將圖片插入到郵件里,或論壇貼圖,如果不幸被火狐用戶點中,那將當場炸死;webkit內核的瀏覽器則嚴重拖慢了系統速度;最杯具當屬ie用戶了,不知不覺被吞走了1G的硬盤空間,如果插入多個的話則更多倍,只要url參數不同!如果配合HTTP重定向,定向到帶有隨機參數的url,那么每次訪問頁面又會加載並緩存一次!
No.3 ———— 收郵件時暴露IP
(嚴重程序:高)
這一招其實沒有任何技術含量,也不是什么BUG,連缺陷也算不上。僅僅是一種小技巧而已。
既然網頁里的圖片可以外鏈,那就意味着可以訪問任何服務器,包括我們自己的。在服務器上稍作記錄,就可以輕易獲得訪問者的ip。
這對於論壇來說沒多大意義。因為論壇里面訪客眾多,很難知道哪個ip是誰的。但電子郵件就不一樣了,很少會有其他人來用你的郵箱。
當我們向某個人發送一封郵件,里面有個不起眼的圖片,外鏈到我們的cgi程序上。當他打開郵件時,cgi程序接收到了他的請求,自然也就探測到了ip。為了防止圖不裂開,返回一個微小的圖片,以防發現破綻。
對於QQ郵件這類有推送提示的郵箱,對方很快就會打開郵件,尤其是寫一個比較真實的郵件標題。
利用這點,我們可以寫個郵件群發的腳本,向多個QQ發送探測郵件。我們把每個email對應圖片的url里帶上唯一參數,以區分不同的郵箱。
不出一時半日,當接收者陸續打開郵件,他們的ip也隨之暴露。即使用代理上網,也能通過HTTP的HTTP_X_FORWARDED_FOR字段獲得真實ip地址。
通過ip地理定位,很快就可以知道他們最近在哪里。如果有相同的ip,說不定他們正在一個內網里呢:)
防范措施
因為圖片保存在外部,所以完全不在自己的可控范圍里。即使用戶外鏈的是合法的圖片,也只能意味的是當前,而不是以后,因為用戶可以更新外鏈的內容,甚至可以針對不同的ip返回不同的內容。因此要完全防住,只能在客戶端上分析圖片的內容,后台最多起到輔助作用。
在目前版本的百度貼吧里,因為圖片會顯示在貼吧的主頁面上,所以對外鏈的安全性已極大的增強。當用戶使用外鏈的形式插入圖片時,后台服務器會不定期的檢查圖片的合法性,如果存在異常則會刪除此圖片。如果同樣的站點出現多次異常情況,則會進入黑名單。雖然仍有部分疏漏,但相比沒有要好的多。對於空間相冊,或者可信站點的圖片,則不會反復的掃描檢測。
類似的,像微博這類傳播性極強的應用,則完全不能使用外鏈。即使需要,也是由代理服務器讀取,再返回給用戶,因此就從根本上排除了安全隱患。