一、概述
我們知道,網頁裏的a標籤默認在當前窗口跳轉鏈接地址,如果需要在新窗口打開,需要給 a 標籤添加一個target="_blank"屬性,這個屬性的意思是在新的瀏覽器窗口打開此超鏈接,但是這個其實是有安全缺陷的,當我們在這樣的寫的時候一個非常簡單的釣魚攻擊的漏洞就這樣產生了。
二、原理
熟悉js的朋友都應該知道當我們在調用window下的open方法創建一個新窗口的同時,我們可以獲得一個創建窗口的opener句柄,但你也許沒注意到,通過target="_blank"點開的窗口活着標籤頁,子窗口也能捕獲opener句柄,通過這個句柄,子窗口可以訪問到父窗口的一些屬性,雖然很有限,但是我們卻可以修改父窗口的頁面地址,讓父窗口顯示指定的頁面。
舉個例子,在頁面a.html中有這樣一段代碼:
<a href="b.html" target="_blank">跳轉</a>;
當我們點擊頁面a.html中的跳轉鏈接時,瀏覽器會在新的窗口或標籤頁中打開b.html,假如這個時候b.html中有這樣一段js代碼:
if (window.opener) {
window.opener.location.href = 'b.html';
}
當頁面b.html被打開的同時原來打開a.html的標籤頁會被重定向到b.html, b.html可以是和原來域完全不相關的其它域的資源。
三、性能
除了安全隱患外,還有可能造成性能問題。通過target="_blank"打開的新 窗口,跟原來的頁面窗口共用一個進程。如果這個新頁面執行了一大堆性能不好的 JavaScript 代碼,佔用了大量系統資源,那你原來的頁面也會受到池魚之殃。
四、防範
如果需要限制window.opener的訪問行爲,我們只需要在原始頁面每個使用了 target="_blank" 的鏈接中加上一個 rel=“noopener” 屬性。
但是,火狐並不支持這個屬性值,火狐瀏覽器裏需要寫成 rel=“noreferrer” ,所以我們可以將兩個屬性值合併寫成 rel=“noopener noreferrer” 來完整覆蓋。
這樣新窗口的window.openner就是null了,而且會讓新窗口運行在獨立的進程裏,不會拖累原來頁面的進程。
當然,我們也可以通過js來控制來限制句柄的訪問,代碼如下:
var otherWindow = window.open();
otherWindow.opener = null;
otherWindow.location = url;
otherWindow.target = "_blank";
五、總結
在開發中,我們以後在寫a標籤的時候儘量都在target="_blank"後面添加一句 rel=“noopener noreferrer”