前端也需要了解的 JSONP 安全

_Kieran發表於2018-08-16

什麼是 JSONP(JSON with Padding)?

What? 你還不知道 JSONP 是什麼?趕緊去補補吧,我就不多講了。 補個百度百科連結先,baike.baidu.com/item/jsonp/…

會有哪些安全隱患?怎麼防範?

我們假設有這樣一個場景一
我登入了 www.qq.com,QQ 為了給第三方提供服務,可能會有這樣的 jsonp 介面,www.qq.com/getUserInfo?callback=action,那我就可以自己構造一個惡意頁面,請求這個 jsonp 介面,放在網路上,收集 qq 使用者的資訊了。要是 jsonp 介面還涉及了一些敏感操作或者資訊,就更嗨皮了~比如登陸啊,刪除啊等操作。不過國內很多後端開發並不重視此問題,突然想起來老東家的後端開發為了加速開發,寫了個通用的函式,只要能 GET 訪問的介面都可以 jsonp 訪問。Emmm...

對於第一種情況,首先要驗證 JSONP 呼叫的來源(Referer),這種方案利用了 js 資源載入時會傳送 Referer 的特性,服務端判斷 Referer 是不是白名單即可。
說起來容易,但實際還會因為過濾的正則不嚴謹導致繞過,比如只驗證了是否存在 www.qq.com 關鍵字,那我可以構造 www.qq.com.domain.com 來進行攻擊。又比如很多開發會允許空 Referer,而跨協議呼叫 js 是不傳送 Referer 的,可謂是千里之堤潰於蟻穴~跨協議呼叫 js 的一個例子: <iframe src="javascript:'<script src=http://attack.com/jsonp></script>'"></iframe> 程式碼裡使用 iframe 呼叫 javascript 偽協議,來傳送空 Referer 的 js 請求。
所以空 Referer 還是要禁止滴。
另外就是部署隨機 Token 來防禦了,每一次請求都帶上 token 值,token 值字母加數字長一點最好了,不然有被暴力破解的可能。

接下來是場景二
不嚴謹的 content-type 導致的 XSS 漏洞 想象一下 jsonp 就是你請求 http://youdomain.com?callback=douniwan, 然後返回 douniwan({ data }),那假如請求 http://youdomain.com?callback=<script>alert(1)</script> 不就返回 <script>alert(1)</script>({ data }) 了嗎,如果沒有嚴格定義好 Content-Type( Content-Type: application/json ),再加上沒有過濾 callback 引數,直接當 html 解析了,就是一個赤裸裸的 XSS 了。 Content-Type 設定成 application/javascript 在 IE 等瀏覽器下一樣可以解析成 HTML 導致 XSS 漏洞。所以要嚴格定義成 application/json。不過即使這樣,在五花八門的瀏覽器面前,也會有個別特殊的,比如在 IE6/7 下面,請求的 URL 檔案後面加一個 /x.html 就可以解析成 html。

防禦這種情況首先要嚴格定義 Content-Type: application/json,然後嚴格過濾 callback 後的引數並且限制長度。
有時候我們會在某些框架的內建 jsonp 函式返回內容裡看到這樣的開頭:/**/, 比如 Express 框架內建的 jsonp 函式會這樣返回:

/**/ typeof func === 'function' && func({"data":"hello"});
複製程式碼

這是為什麼呢?其實這都是有歷史原因的,2011 年的時候出過一個通過 mhtml 協議解析跨域的漏洞:MHTML Mime-Formatted Request Vulnerability (CVE-2011-0096),當時也是影響了一堆國際廠商,想詳細瞭解的可以戳這裡,technet.microsoft.com/library/sec…
防禦這個就是在前面加上 /**/ 或者多個換行符就能一定程度預防其他檔案格式的輸出了。

接下來是場景三
假如我的網站用了第三方的服務,而對方提供的只有 jsonp 介面,萬一對方的伺服器被黑了,返回了一串惡意程式碼,那不是城門失火,殃及池魚了嗎?
請記住一句話,所有的第三方都是不可完全信任的。
防禦的話,首先,考慮一下,前端能做什麼防禦措施?
iframe?好像可以,搜了下,網上已經有人做了嘗試了,詳細可以看這裡 github.com/aui/jsonp-s…
還有什麼方法呢?前端好像沒什麼可以檢測返回的 js 內容的函式了,好像沒什麼可以玩的了。
那換個思路,服務端轉發呢,既然前端不能檢測第三方的 jsonp 內容,那我用自己的服務端去檢測第三方的 jsonp 內容是否合法,再返回結果不就行了。

最後

繞來繞去,總感覺用的不太爽,可能正是由於 jsonp 的種種缺陷,才一直沒有被瀏覽器標準採納吧。

相關文章