使用noopener和noreferrer讓HTML中的外部鏈接更安全
前言
剛學(xué)前端那會(huì)兒,我處理外鏈的方式簡(jiǎn)單粗暴:
<a >隨便一個(gè)外鏈</a>
點(diǎn)一下,當(dāng)前標(biāo)簽直接跳走。 用戶剛打開好不容易進(jìn)來的頁面,下一秒——嗖地沒了。
后來我發(fā)現(xiàn) target="_blank" 這個(gè)“神器”:
<a target="_blank">在新標(biāo)簽打開的外鏈</a>
從此以后,外鏈都乖乖在新標(biāo)簽里打開:
原頁面留在那兒
新內(nèi)容另起一頁
體驗(yàn)一下子順眼了很多,我自己也用得很爽。 直到有一天,我才知道:
只加
target="_blank",你其實(shí)給自己埋了一個(gè)安全坑。
問題不在“新標(biāo)簽”,而在它背后悄悄多出的那根“線”
當(dāng)你用 target="_blank" 打開一個(gè)新標(biāo)簽時(shí), 瀏覽器會(huì)在兩個(gè)頁面之間,悄悄建立一條 JavaScript 通道。
具體來說:
新開的頁面,可以通過一個(gè)叫
window.opener的對(duì)象, 直接“反向操作”你的原頁面。
就像這樣簡(jiǎn)單粗暴的一行:
window.opener.location = 'https://a-new-page.com';
意思就是:
“把原來的那一頁,重定向到我指定的這個(gè)新地址。”
這種操作,有個(gè)專業(yè)(但聽起來就很陰間)的名字:tabnabbing(標(biāo)簽劫持)。
你以為你只是好心把外鏈丟到新標(biāo)簽頁, 結(jié)果人家順著這條“繩子”,直接把你的原頁面拖走了。
更可怕的是——用戶根本意識(shí)不到發(fā)生了什么。
剛才還在你的后臺(tái)系統(tǒng)里操作
刷一下,頁面“看起來差不多”,其實(shí)已經(jīng)換了站點(diǎn)
繼續(xù)輸入密碼、填表單、點(diǎn)擊按鈕……
全程沒警覺,你的平臺(tái)就這樣被“借殼上演了一場(chǎng)騙局”。
哪些場(chǎng)景尤其危險(xiǎn)?
這種“標(biāo)簽劫持”風(fēng)險(xiǎn),對(duì)下面這些場(chǎng)景尤其致命:
管理后臺(tái)(Admin 面板)
支付系統(tǒng) / 充值頁面
郵箱 / 賬號(hào)登錄頁
SaaS 后臺(tái)、數(shù)據(jù)控制臺(tái)
政府、醫(yī)療、教育等敏感業(yè)務(wù)頁面
只要你的用戶:
在你這個(gè)頁面里登錄過
輸入過敏感信息
做過對(duì)賬號(hào)有影響的操作
那一旦被人利用 window.opener 做文章,你和用戶就一起掉坑里了。
一行就能補(bǔ)上的安全大洞:rel="noopener noreferrer"
好消息是,修這個(gè)問題,真的只要 加一小段屬性:
<a target="_blank" rel="noopener noreferrer">更安全的外鏈</a>
就這一行:
rel="noopener noreferrer"
后面這兩個(gè)值,分別干這些事:
noopener:直接剪斷那根“控制原頁面”的線
rel="noopener" 的作用是:
告訴瀏覽器: “新開的那一頁,不允許通過
window.opener訪問/控制我。”
也就是說:
新標(biāo)簽頁依然能正常打開
但它不再有權(quán)限反向操作你的原頁面
window.opener變成null,這條路被你堵死了
tabnabbing 這條攻擊鏈,直接被斬?cái)唷?/strong>
noreferrer:順帶把“我是誰”也隱藏掉
rel="noreferrer" 做的事情是:
在跳轉(zhuǎn)時(shí),不再把“從哪個(gè)頁面來的”這個(gè)信息, 通過 HTTP Referer 頭部傳給目標(biāo)站點(diǎn)。
簡(jiǎn)單說:
對(duì)方拿不到你頁面的 URL 作為來源
某些老瀏覽器里,不加這個(gè)就沒法同時(shí)兼容
noopener也順手給用戶多了一層隱私保護(hù)
兩個(gè)屬性一起用,就是現(xiàn)在業(yè)界推薦的“標(biāo)配”:
rel="noopener noreferrer"
它們一起做到了:
不給對(duì)方遠(yuǎn)程控制權(quán)
不亂暴露用戶從哪兒來的
還順便補(bǔ)上老瀏覽器的坑
你付出的成本? 不過就是在 <a> 標(biāo)簽里,多敲了 20 來個(gè)字符而已。
“瀏覽器不是已經(jīng)幫我自動(dòng)加 noopener 了嗎?”
確實(shí),部分現(xiàn)代瀏覽器 在某些場(chǎng)景里, 會(huì)自動(dòng)為 target="_blank" 的外鏈加上 noopener。
但問題有兩個(gè):
并不是所有瀏覽器都這么做
你也不能保證將來改動(dòng)、第三方組件、特殊環(huán)境里不會(huì)漏掉
作為一個(gè)開發(fā)者, 在這種“成本極低、收益極大”的地方, 與其賭瀏覽器,不如自己寫死。
親手多寫 1 行, 好過哪天追著用戶說:“這個(gè)問題是瀏覽器的問題,不是我。”
什么時(shí)候該用?什么時(shí)候不必用?
這對(duì)組合,也不是“逢 <a> 必加”。
可以簡(jiǎn)單記住一條:
給“外鏈”加上它
指向你無法完全信任的站點(diǎn)
跳到第三方支付、第三方內(nèi)容平臺(tái)
跳到合作方、廣告方、外部工具
這些地方,一律建議:
<a target="_blank" rel="noopener noreferrer">第三方頁面</a>
內(nèi)部導(dǎo)航,正常情況下不用加
如果你的鏈接是:
同一域名下的頁面之間跳轉(zhuǎn)
同一 SPA 應(yīng)用內(nèi)部用
<a>做路由(而不是window.open)必須依賴
window.opener做明確的、可信的雙向通信
那就不必強(qiáng)行加 noopener。 在同一個(gè)受控環(huán)境下,相互通信本身就是設(shè)計(jì)的一部分。
但有一點(diǎn)可以堅(jiān)守:
只要是 “點(diǎn)了就跳出我控制范圍” 的鏈接, 我都會(huì)習(xí)慣性補(bǔ)上這兩個(gè)屬性。
順手一個(gè)小優(yōu)化:用 CSS 標(biāo)記所有“會(huì)開新標(biāo)簽的外鏈”
為了給用戶一點(diǎn)“視覺提示”, 我還習(xí)慣順帶加一點(diǎn)點(diǎn) CSS:
a[target="_blank"] {
cursor: pointer;
}
a[target="_blank"]::after {
content: "↗";
font-size: 0.8em;
margin-left: 0.25em;
}這樣用戶一眼就能看出來:
這個(gè)鏈接點(diǎn)了會(huì)開新標(biāo)簽
跳出當(dāng)前站點(diǎn),不是普通內(nèi)部導(dǎo)航
UX 更清晰,安全感也更足一點(diǎn)。
最后一句:真正“專業(yè)”的前端,很多時(shí)候就藏在這種小細(xì)節(jié)里
rel="noopener noreferrer" 看起來只是一個(gè)不起眼的小屬性。
頁面不加照樣能跑
一般用戶也察覺不到區(qū)別
控制臺(tái)也不會(huì)給你報(bào)紅
可它解決的是一個(gè):
“安安靜靜存在了很多年,但一旦被利用就很致命”的問題。
你多寫這一行:
用戶更安全
你的站更難被拿去當(dāng)“跳板”或釣魚工具
安全審計(jì)時(shí)看你的代碼,也會(huì)多一絲尊重
成本幾乎為零,收益卻相當(dāng)可觀。
所以,下次你再寫:
<a target="_blank">外鏈</a>
不妨養(yǎng)成一個(gè)小習(xí)慣,順手補(bǔ)上這一段:
rel="noopener noreferrer"
就這一行, 讓外鏈安全了一大截。
鏈接類型處理表格
| 鏈接類型 | target | rel屬性 | 說明 |
|---|---|---|---|
| 內(nèi)部鏈接 | 不設(shè)置或_self | (無需) | 站內(nèi)導(dǎo)航 |
| 內(nèi)部資源 | _blank | noopener | PDF、下載文件等 |
| 可信外部 | _blank | noopener noreferrer | 合作伙伴、參考資料 |
| 用戶內(nèi)容 | _blank | ugc nofollow noopener noreferrer | 評(píng)論、論壇帖子 |
| 廣告鏈接 | _blank | sponsored nofollow noopener noreferrer | 付費(fèi)廣告、推廣 |
| 社交媒體 | _blank | noopener noreferrer | 分享按鈕 |
| 登錄/注冊(cè) | _blank | noopener noreferrer | OAuth認(rèn)證等 |
總結(jié)
到此這篇關(guān)于使用noopener和noreferrer讓HTML中的外部鏈接更安全的文章就介紹到這了,更多相關(guān)noopener和noreferrer讓HTML外鏈更安全內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Scratch3.0 頁面初始化同時(shí)加載sb3文件的操作代碼
今天通過本文給大家分享Scratch3.0 頁面初始化同時(shí)加載sb3文件的操作代碼,感興趣的朋友一起看看吧2021-08-08
詳細(xì)講解計(jì)算機(jī)網(wǎng)絡(luò)——應(yīng)用層
這不同類型的網(wǎng)絡(luò)應(yīng)用有不同的通信規(guī)則,因此應(yīng)用層協(xié)議是多種多樣的,比如DNS、FTP、Telnet、SMTP、HTTP、RIP、NFS等協(xié)議都是用于解決其各自的一類問題2021-08-08
在Postman中高效生成隨機(jī)環(huán)境變量的三種高效方法
在現(xiàn)代API測(cè)試中,生成真實(shí)的測(cè)試數(shù)據(jù)至關(guān)重要,作為Postman的高級(jí)用戶,我發(fā)現(xiàn)隨機(jī)數(shù)據(jù)生成不僅節(jié)省時(shí)間,還能提高測(cè)試覆蓋率,本文將分享三種在Postman中生成隨機(jī)環(huán)境變量的高效方法,幫助你提升API測(cè)試效率,需要的朋友可以參考下2025-07-07

