JSONP
先說 JSONP。通過 JavaScript 調用,被調用域名和當前頁面域名不一致,就需要用到 JSONP。不過我不太推薦這么跨域調用。
如果真的要解決跨域問題,我覺得有幾個不錯的方法,一個是兩組服務器配上相同的域名。還有就是自己的服務器 nginx 上做一個轉發。
XSS
跨站腳本(英語:Cross-site scripting,通常簡稱為:XSS)是一種網站應用程序的安全漏洞攻擊,是代碼注入的一種。它允許惡意用戶將代碼注入到網頁上,其他用戶在觀看網頁時就會受到影響。這類攻擊通常包含了HTML以及用戶端腳本語言。
上面是維基百科的解釋。實際一點的例子可以看看我文本的頭圖。頁面被注入了一張圖片。惡意的注入可以注入一段腳本。
問題原因
瀏覽器為了保證跨域訪問的安全性,會默認發一個 callback 參數到后臺,接口拿到這個參數之后,需要將返回的 JSON 數據外面包上 callback 參數。
具體的返回格式:
CALLBACK(JSON)
如果 ajax 請求是 JSONP 請求,返回的內容瀏覽器還會自動檢測,如果不是按這個格式返回或者 callback 的內容不對,這次請求就算失敗了。
這里有一個機制,那就是請求的 callback 會被放入返回的內容當中,這也是可能出問題的地方。
支持 JSONP 的鏈接如果直接放到瀏覽器里面訪問,瀏覽器就不會做 callback 校驗了。
Content-Type: application/json
瀏覽器渲染就是靠 Content-Type 來做的。如果返回內容標記是 json,哪怕 body 里面都是 html 的標簽,瀏覽器也不會渲染。所以,如果接口返回的不是 html,千萬不要寫成 html。
Content-Type: text/html
如果返回的內容是頁面,html類型。那么 callback 注入的 html 元素都可以直接放到頁面上了。那么,html 頁面必然不能支持 callback。
解決方法
就是前面說到的,Content-Type 不要亂用,嚴格按照標準協議來做。目前的框架默認肯定會檢測一下內容類型,如果不是很必要,不要手動設置。因為有可能多轉發幾次 Content-Type 就被改了。
callback 做長度限制,這個比較 low。
檢測 callback 里面的字符。一般 callback 里面都是字母和數字,別的符號都不能有。
callback 做一個編碼,如果用 Go 語言做的話,如下。對所有 callback 都處理。
callback = template.JSEscapeString(callback)
完整代碼可以參考這里。