什麼是盜鏈
資源不在自己伺服器上, 而通過技術手段, 把資源放置到自己的網站中, 通過這種方法盜取他人的資源.
什麼是Referer
Referer
是http
請求header
的一部分, 當瀏覽器(或者模擬瀏覽器行為)向web
伺服器傳送請求的時候,頭資訊裡有包含 Referer. 它表示當前介面的訪問來源.Referer
的正確英語拼法是referrer
. 由於早期http
規範的拼寫錯誤, 為了保持向後相容就將錯就錯了. 其它網路技術的規範企圖修正此問題, 使用正確拼法, 所以目前拼法不統一.
為什麼要設定防盜鏈
- 防爬蟲(流量暴漲, 服務提供者卻是受害者)
- 安全
如何設定防盜鏈
你完全可以用token驗證等方法去實現更嚴格的防盜鏈
...(如何新增路由等等就不說了, 有興趣直接去看看我的程式碼, 直接跳到驗證器的路由程式碼去)
routers/doorChain/controller.ts
import express from 'express';
import { Get, Headers, Res, Controller } from '@nestjs/common';
import { DoorChainService } from './service';
@Controller('door-chain')
export class DoorChainController {
constructor(private readonly doorChainService: DoorChainService) {}
@Get()
root(@Headers('referer') referer: string, @Res() res: express.Response) {
return this.doorChainService.root(referer, res);
}
}
複製程式碼
routers/doorChain/service.ts
import * as url from 'url';
import * as path from 'path';
import express from 'express';
import { Injectable } from '@nestjs/common';
import logger from 'utils/logger';
@Injectable()
export class DoorChainService {
root(referer: string, res: express.Response) {
let imageName = 'break.png';
if (!referer) {
imageName = 'yellow.png';
} else {
try {
const refererParsed = url.parse(referer);
if (refererParsed.host === 'localhost:8080') {
imageName = 'yellow.png';
}
} catch (err) {}
}
const imagePath = path.resolve(__dirname, `./../../assets/${imageName}`);
res.sendFile(imagePath, null, err => {
if (err) {
logger.error(err);
res.status(404).end();
} else {
logger.info(`Sent: ${imagePath}`);
}
});
}
}
複製程式碼
主要的邏輯程式碼就那麼幾行!
驗證的基本思路:
- 當referer為空時, 返回正確的圖
- 當referer不為空, 且host命中我的目標網站時, 返回正確的圖
- 當referer不為空, 但host未能命中我的目標網站時, 返回錯誤的圖
啟動服務, 訪問http://localhost:3333/door-chain, 返回正確的圖!!!
如何去掉訪問限制
這次我們僅討論怎麼在網頁端去掉訪問的限制, 另外還有七牛映象儲存, 或者把實現方案交由服務端處理等等都是可以的, 而且原理都是一樣, 這裡不一一贅述.
以下簡述去掉header
中的Referrer
的兩種方法:
-
新增name為referrer, content為never(whatwg標準, 相容性相對較好)或no-referrer(MDN標準)的meta標籤
策略名稱 屬性值(MDN標準) 屬性值(whatwg標準) No Referrer no-referrer never No Referrer When Downgrade no-referrer-when-downgrade default Origin Only origin - Origin When Cross-origin origin-when-crossorigin - Unsafe URL unsafe-url always 無論選擇哪一個值, 都有一個缺點, 就是預設情況下全部資源(包括介面)都被處理了
-
對標籤新增ReferrerPolicy屬性
更精確的指定了某一個資源的referrer策略
相對以上的值列表, ReferrerPolicy在此基礎上擴充套件了三個可供選擇的值:
- same-origin 對於同源的請求會傳送引用地址,但是對於非同源請求則不傳送引用地址資訊。
- strict-origin 在同等安全級別的情況下,傳送檔案的源作為引用地址(HTTPS->HTTPS),但是在降級的情況下不會傳送 (HTTPS->HTTP)。
- strict-origin-when-cross-origin 對於同源的請求,會傳送完整的URL作為引用地址;在同等安全級別的情況下,傳送檔案的源作為引用地址(HTTPS->HTTPS);在降級的情況下不傳送此首部 (HTTPS->HTTP)。
如果在純粹開發的角度上, 這個方式是接近完美的, 因為沒有汙染到其他任何東西. 再來看看瀏覽器相容性方面:
常規值的問題也不大.
新擴充套件的三個值的相容性圖
有點不容樂觀啊!
關於擴充套件img標籤屬性
在tsx中img標籤預設是不支援referrerPolicy的, 實現方案可以參考ts-react-webpack, 檢視我是如何擴充套件的, 歡迎來踩!!!
當然了, 雖然常用的會是類似上述的方案, 總的來說, 這裡只是防盜鏈知識體系中的鳳毛麟角, 仍有待探索.
此外還有referrer-killer等等的專案可以參閱