上週突然發現自己的自己站點的圖片全都403了,之前還是好好的,圖片咋就全都存取不了呢?由於我每次發文章都是先發了掘金,然後再從掘金拷貝到我自己的站點,這樣我就不用在自己的站點去上傳圖片了,非常方便。
啥也沒幹,圖片咋就403了呢?估計又是整了什麼開源節流,降本增效吧,說白了就是大家都用他站點的圖片導致流量費用蹭蹭蹭的往上漲,人家肯定不願意了,這下給圖片都加上防盜了,非自己的站點全都給你返回403.
是不是很好奇這些圖片防盜是怎麼做的?
我們可以自己來實現一下這個場景:不受信任的域名存取我伺服器上的圖片資源全都返回403
這裡沒有域名也不用擔心,我們可以直接本地模擬就行了,比如我這裡使用SwitchHosts
給本地新增的三個域名並且都指向我們的本地IP
這樣的話這三個域名都能夠存取我們的本地服務了。
這裡就用之前的nest
服務來做演示,之前我們在這個服務上指定了靜態資源目錄
app.useStaticAssets(join(__dirname, '../static'), {
prefix: '/static',
}); // 靜態資源
前端存取圖片
<img class="my_img" src="http://nanjiu.com:3000/static/sy.jpg" />
這裡是使用nanjiu.com
代理域名來存取的,圖片能夠正常存取
這裡我們可以來實現一個全域性中介軟體用來處理圖片的存取,當存取域名不在我們信任的白名單內直接給他返回403
// 白名單
const whiteList = ['nanjiu.com', 'fenanjiu.com']
// 圖片防盜中介軟體
function imgMiddleware(req, res, next) {
console.log('--req', req.headers)
// 獲取資源型別
const type = req.headers.accept || ''
if(!type.includes('image')) {
// 不是圖片資源,直接放行
next()
return
}
const referer = req.headers.referer || ''
// 獲取referer的域名
const { hostname } = url.parse(referer, true)
if(referer && whiteList.includes(hostname) || !referer) {
// 存取域名在白名單內,放行 !referer表示直接存取圖片(比如瀏覽器位址列輸入圖片地址)
res.status(200)
next()
}else {
// 存取域名不在白名單內,返回403
res.status(403)
res.send('逮到你了,又來偷我圖片是吧!')
}
}
這裡需要注意的是,全域性中介軟體在使用時一定要在useStaticAssets
之前
async function bootstrap() {
const app = await NestFactory.create<NestExpressApplication>(AppModule);
app.setGlobalPrefix('api'); // 全域性路由字首
app.use(cors()); // 允許跨域
app.use(json({ limit: '10mb' })); // 允許上傳大檔案
app.use(urlencoded({ extended: true, limit: '10mb' })); // 允許上傳大檔案
app.use(imgMiddleware) // 圖片防盜中介軟體
app.useStaticAssets(join(__dirname, '../static'), {
prefix: '/static',
}); // 靜態資源
await app.listen(3000);
console.log(`Application is running on: ${await app.getUrl()}`);
}
bootstrap();
這上面的程式碼中我們可以看到,現在受信任的域名就只有nanjiu.com
和fenanjiu.com
當前端頁面使用sy.com
這個域名去存取nanjiu.com
域名下的圖片時,此時應該是會進入防盜邏輯,返回403
並且送他一句
從上面我們實現的防盜原理來看,這其中最關鍵的就是referer
,那麼這個referer
到底是什麼呢?為什麼可以用它來做圖片防盜
MDN解釋如下:
Referer
請求頭包含了當前請求頁面的來源頁面的地址,即表示當前頁面是通過此來源頁面裡的連結進入的。伺服器端一般使用Referer
請求頭識別存取來源,可能會以此進行統計分析、紀錄檔記錄以及快取優化等。
從這裡我們就大概能知道圖片防盜的原理了,伺服器端可以通過請求頭中的Referer
來識別存取來源,然後判斷應不應該給你返回圖片
Referer
這個單詞實際上是Referrer
的錯誤拼寫,這其實是個歷史原因,在早期 HTTP 規範當中就存在的拼寫錯誤,後面為了向下相容,所以將錯就錯。
拼寫錯誤只有 Request Headers
的 Referer
,在其他地方比如General Headers
、 JavaScript
及 DOM
上,都是正確的拼寫。
Referrer-Policy
首部用來監管哪些存取來源資訊——會在Referer
中傳送——應該被包含在生成的請求當中。
它其實是用來控制 Referer 返回的具體內容的
它有以下屬性值:
Referer
首部會被移除。存取來源資訊不隨著請求一起傳送。https://example.com/page.html
會將 https://example.com/ 作為參照地址
。這麼多referrer
策略,我們怎麼使用呢?
我們可以用一個 name 為 referrer
的meta
元素為整個檔案設定 referrer
策略
<meta name="referrer" content="no-referrer">
我的個人站點就是使用該方法來解決圖片存取403問題的,但需要注意的是,如果你為頁面設定了no-referrer
策略會導致頁面上所有的請求都不會傳送referer
,使用時需要自己權衡利弊。
可以在a
、area
、link
標籤上通過rel
屬性來單獨指定referrer
的策略
<a href="xxx" rel="noreferrer">新地址</a>
可以在a
、area
、link
、img
、iframe
、script
標籤上通過referrerpolicy
屬性來單獨指定referrer
策略
<img class="my_img" referrerpolicy="no-referrer" src="http://nanjiu.com:3000/static/sy.jpg" />
比如上面例子中的這張圖片我們加上referrerpolicy="no-referrer"
再去存取,頁面還是在sy.com
這個域名下面
可以看到請求頭中沒有攜帶referer
,所以它就能夠躲過圖片防盜邏輯。
也可以更改 HTTP 頭資訊中的 Referer-Policy 值。比如你使用的是 Nginx,則可以設定 add_headers 設定請求頭。
add_header Referrer-Policy "no-referrer";
Headers 請求頭和其它頁面元素屬性同時存在時,確定元素的有效策略時的優先順序是:
如果這篇文章有幫助到你,❤️關注+點贊❤️鼓勵一下作者,文章公眾號首發,關注 前端南玖
第一時間獲取最新文章~
-------------------------------------------
如果這篇文章有幫助到你,❤️關注+點贊❤️鼓勵一下作者,文章公眾號首發,關注 前端南玖 第一時間獲取最新的文章~
掃描下方二維條碼關注公眾號,回覆進群,拉你進前端學習交流群