1、JSONP概念
JSONP(JSON with Padding)是JSON的一種“使用模式”,可用于解決主流瀏覽器的跨域數據訪問的問題。由于同源策略,協議+IP+端口有任意不同都會導致請求跨域,而HTML的script元素是一個例外。利用script元素的這個開放策略,網頁可以得到從其他來源動態產生的JSON 資料。
代碼如下僅供參考
假設有一個遠程服務器 https://example.com/api/data,它返回以下 JSONP 格式的響應:
myCallback({"name": "John", "age": 30});
在前端,你可以創建一個 script標簽,并將其 src 屬性設置為該 URL,同時定義一個名為 myCallback 的函數來處理返回的 JSON 數據:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>JSONP Example</title>
<script> // 定義回調函數 function myCallback(data) { console.log(data); // 輸出:{name: "John", age: 30} }
</script>
</head>
<body>
<script> // 創建一個新的script標簽 var script = document.createElement('script'); // 設置script標簽的src屬性為遠程API的URL script.src = 'https://example.com/api/data?callback=myCallback'; // 將新創建的script標簽添加到DOM中 document.body.appendChild(script);
</script>
</body>
</html>
舉例:你可以在自己的界面建立搜索功能,但是搜索的數據等內容可以通過script標簽的src屬性為其他瀏覽器的URL ,那么你所搜索的數據就是來自于瀏覽器,也就是訪問到這個函數參數中的 JSON 數據…
2、JSONP劫持概念
通過JSONP技術可以實現數據的跨域訪問,必然會產生安全問題。如果網站B對網站A的JSONP請求沒有進行安全檢查直接返回數據,則網站B便存在JSONP漏洞,網站A利用JSONP漏洞能夠獲取用戶在網站B上的數據。
3、流程
(1)用戶在網站B注冊并登錄,網站B 包含了用戶的id,name,email等信息。
(2)用戶通過瀏覽器向網站A發出URL請求。
(3)網站A向用戶返回響應頁面,響應頁面中注冊了JavaScript的回調函數和向網站B請求的script標簽。
(4)用戶收到響應,解析JS代碼,將回調函數作為參數向網站B發出請求
(5)網站B接收到請求后,解析請求的URL,以JSON 格式生成請求需要的數據,將封裝的包含用戶信息的JSON數據作為回調函數的參數返回給瀏覽器。
(6)網站B數據返回后,瀏覽器則自動執行Callback函數對步驟4返回的JSON格式數據進行處理,通過alert彈窗展示了用戶在網站B的注冊信息。另外也可將JSON數據回傳到網站A的服務器,這樣網站A利用網站B的JSONP漏洞便獲取到了用戶在網站B注冊的信息。
4、JSPNP劫持的危害
(1)攻擊者利用存在漏洞的網站,將鏈接通過郵件等形式推送給受害者,如果受害者點擊了鏈接,則攻擊者便可以獲取受害者的個人敏感的信息。所以JSONP劫持漏洞會泄露信息。
(2)可能導致用戶權限被盜用:攻擊者通過JSON劫持構造盜取管理員或高權限用戶的腳本,一旦被訪問,權限立即被盜用。
(3)可以通過劫持對網頁進行掛馬;在JSON劫持點構造引向漏洞后門木馬,但訪問直接利用漏洞批量掛馬。
(4)可對劫持頁進行網站釣魚;利用JSON劫持直接導向偽裝網站地址
(5)可做提權攻擊。
5、JSONP劫持的防護
(1)限制referer
前端可以通過設置document.referrer屬性來限制Referer。雖然這并不能阻止攻擊者偽造Referer,但可以增加一層防護。
代碼如下僅供參考
// 設置或修改當前文檔的Referer
document.referrer = 'https://trusted-domain.com';
// 發起JSONP請求
const script = document.createElement('script');
script.src = 'https://example.com/api/data?callback=handleResponse';
document.body.appendChild(script);
function handleResponse(data) { // 處理返回的數據 console.log(data);
}
注意:由于Referer可以被偽造,所以僅僅依賴Referer來防止JSONP劫持是不夠的。它應該與其他安全措施結合使用。
(2)使用token
在前端,你可以通過添加一個自定義的token參數來增強JSONP請求的安全性。這個token可以是服務器生成的一個隨機字符串,并存儲在客戶端的某個安全位置(如localStorage)。在服務器端驗證該token。只有持有有效token的請求才會被處理。這樣可以防止未經授權的第三方發起JSONP請求。
代碼如下僅供參考
// 從安全存儲中獲取token
const token = localStorage.getItem('secureToken');
// 發起帶token的JSONP請求
const script = document.createElement('script');
script.src = `https://example.com/api/data?callback=handleResponse&token=${token}`;
document.body.appendChild(script);
function handleResponse(data) { // 驗證token if (data.token === token) { // 處理返回的數據 console.log(data); } else { // token驗證失敗,可能是劫持攻擊 console.error('Invalid token, potential JSONP hijacking!'); }
}
在服務器端,你還需要驗證這個token是否有效。只有當token有效時,才返回數據。這種方法可以增加攻擊者偽造有效請求的難度。
(3)不使用JSONP進行跨域(最直接的方法)
現代瀏覽器支持CORS(跨源資源共享)機制,它提供了更安全、更靈活的跨域解決方案。通過使用CORS,可以在不暴露數據給不安全腳本的情況下實現跨域通信。
代碼如下僅供參考
javascript
// 使用CORS替代JSONP
fetch('https://example.com/api/data', { method: 'GET', mode: 'cors', // 表明這是一個跨域請求 headers: { 'Content-Type': 'application/json' }
})
.then(response => response.json())
.then(data => { // 處理返回的數據 console.log(data);
})
.catch(error => { console.error('Error:', error);
});
使用CORS時,服務器需要正確配置響應頭部以允許跨域請求
http
Access-Control-Allow-Origin: https://your-frontend-domain.com
Access-Control-Allow-Methods: GET, POST, PUT, DELETE
Access-Control-Allow-Headers: Content-Type
通過上面措施,前端可以顯著減少JSONP劫持的風險。但是安全是一個綜合性的工作,前端和后端都需要共同努力來確保系統的安全性。