以Referer方案寫一個圖片防盜鏈服務並實現網頁端"破解"

什麼是盜鏈

資源不在本身服務器上, 而經過技術手段, 把資源放置到本身的網站中, 經過這種方法盜取他人的資源.

什麼是Referer

Refererhttp請求 header的一部分, 當瀏覽器(或者模擬瀏覽器行爲)向 web服務器發送請求的時候,頭信息裏有包含 Referer. 它表示當前接口的訪問來源. Referer的正確英語拼法是 referrer. 因爲早期 http規範的拼寫錯誤, 爲了保持向後兼容就將錯就錯了. 其它網絡技術的規範企圖修正此問題, 使用正確拼法, 因此目前拼法不統一.

爲何要設置防盜鏈

  • 防爬蟲(流量暴漲, 服務提供者倒是受害者)
  • 安全

如何設置防盜鏈

此處以基於 express的二次開發框架 nestjs起一個小demo

你徹底能夠用token驗證等方法去實現更嚴格的防盜鏈react

...(如何添加路由等等就不說了, 有興趣直接去看看個人代碼, 直接跳到驗證器的路由代碼去)webpack

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}`);
            }
        });
    }
}

主要的邏輯代碼就那麼幾行!git

驗證的基本思路:github

  • 當referer爲空時, 返回正確的圖
  • 當referer不爲空, 且host命中個人目標網站時, 返回正確的圖
  • 當referer不爲空, 但host未能命中個人目標網站時, 返回錯誤的圖

啓動服務, 訪問http://localhost:3333/door-chain, 返回正確的圖!!!web

如何去掉訪問限制

此次咱們僅討論怎麼在網頁端去掉訪問的限制, 另外還有七牛鏡像儲存, 或者把實現方案交由服務端處理等等都是能夠的, 並且原理都是同樣, 這裏不一一贅述.

如下簡述去掉header中的Referrer的兩種方法:express

  • 添加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等等的項目能夠參閱

相關文章
相關標籤/搜索