asp.net MVC 網站圖片防盜鏈的幾種方法


                                目錄

1. 通過 URL Rewrite Module 組件

2. 通過 nginx 圖片防盜鏈

3.自定義 HttpHandler 處理

4. 通過 MVC 自定義路由規則防盜鏈

5. 通過 MVC 自定義 RouteHandler 防盜鏈

6. 通過 HttpModModule 防盜鏈

7. 涉及知識點,相關資源

 

      

自己網站上的圖片被別的網站盜用是一件很令人厭惡的事情,下面是處理圖片盜鏈的幾種方法。

在這里先交代一下環境,我用的是 MVC4 ,IIS7 應用程序池為集成模式,以下配置都是基於此環境進行。

1. 通過 URL Rewrite Module 組件

這是一個比較簡單,方便的方法。首先要去 Url Rewite 官網 下載 URL Rewrite Module 2.0 並安裝。安裝完成后可以看到 IIS設置里多了  URL重寫 的模塊如下圖:

在這里,可以對URL訪問規則進行設置, 雙擊 URL 重寫,添加入站規則

     

   

 

 在條件(c)  里面添加  {HTTP_REFERER}    模式為: ^http://localhost/.*$, 意思是 請求  HTTP_REFERER 必須包含 http://localhost/ 字符,規則當然是根據自己的情況寫。

添加保存后,站點的 web.config 文件的 system.webServer 節點下就多了 rewrite 節點,配置如下。

<system.webServer>
    <validation validateIntegratedModeConfiguration="false" />    
    <handlers>
      <remove name="ExtensionlessUrlHandler-Integrated-4.0" />
      <remove name="OPTIONSVerbHandler" />
      <remove name="TRACEVerbHandler" /> 
      <add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="*" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />
    </handlers>
        <rewrite>
            <rules>
                <rule name="防盜鏈" stopProcessing="true">
                    <match url=".*\.(gif|jpg|png)" />
                    <conditions> 
                        <add input="{HTTP_REFERER}" pattern="^http://localhost/.*$" negate="true" />
                    </conditions>
                    
                    <action type="Redirect" url="http://www.baidu.com" />
                </rule>
            </rules>
        </rewrite>
  </system.webServer>

配置好了,有沒有效果呢,我們做一個測試頁面試試

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
    <title></title>
</head>
<body>
    <img src="Content/webpage/img/111.jpg" />
    <img src="111.jpg"/>
</body>
</html>

      里面有2張圖片,由於在IIS “入站規則條件” 里面配置的  HTTP_REFERER  正則表達式為 ^http://localhost/.*$  如果規則有效,我們訪問 http://localhost/HtmlPage1.html  圖片應正常顯示,而如果通過  http://127.0.0.1/HtmlPage1.html  訪問是不應該顯示圖片的,下面是我通過這兩個地址訪問效果。

   

說明配置是成功的。當然了,URL Rewrite Module 並非僅僅做圖片防盜鏈喲!

 

2. 通過 nginx 圖片防盜鏈

 

防盜鏈的原理都是一樣的,主要是通過 referer 判斷來源站點,如果來源站點不在 “白名單” 里,則拒絕或返回一張默認圖片

 

location ~.*\.(jpg|gif|png)$ {
     valid_referers none blocked *.abc.com abc.com;
     if ($invalid_referer) {
     #rewrite ^/ http://abc.com/error.html;
     return 403;
      }
}
location ~.*\.(jpg|gif|png)$  表示所有 以 jpg|gif|png 為后綴名的文件都進行防盜鏈處理
valid_referers none blocked *.abc.com abc.com;   驗證 referer  其中 none 表示直接訪問的,不存在referer   blocked為根據防火牆偽裝的 referer 
#rewrite ^/ http://abc.com/error.html;  如果圖片是放盜鏈,重定向到 地址 http://abc.com/error.html,一般是圖片地址,但是要注意,這個圖片地址不只能在此防盜鏈規則里,否則也訪問不到。

對 nginx 配置不熟悉的同學請參考 windows 下配置 Nginx 常見問題

3.自定義 HttpHandler
處理

方法步驟: 1 創建自定義 handlers 代碼如下,根據 Referre 判斷請求來源,如果符合標准,輸出文件流,否則停止響應。也可以輸出一個特定的圖片。
namespace WeiXinDemo.Globals
{
    /// <summary>
    /// 測試 Handler 實現圖片防盜鏈
    /// </summary>
    public class MyImgHandler : IHttpHandler
    {
        public bool IsReusable
        {
            get { return false; }
        }
         
        public void ProcessRequest(HttpContext context)
        {
            var response = context.Response;
            var request = context.Request; if (request.UrlReferrer == null || !WebApplication.ImgHost.Equals(request.UrlReferrer.Host))
            {
                response.End();
                return;
            }

            var fileName = context.Server.MapPath(request.FilePath);
            response.WriteFile(fileName);

            if (request.UrlReferrer == null || WebApplication.ImgHost.Equals(request.UrlReferrer.Host))
            {
                response.WriteFile(fileName);
            }
            else
            {
                response.End();
            }
        } 
    }
}


2 在web.config 文件 handlers 節點下添加自定義 Handler,滿足要求的請求進入 WeiXinDemo.Globals.MyImgHandler 進行處理
<system.webServer> 
    <handlers>
      <remove name="ExtensionlessUrlHandler-Integrated-4.0" />
      <remove name="OPTIONSVerbHandler" />
      <remove name="TRACEVerbHandler" />  
      <add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="*" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />
    <!-- 這是添加的自定義Handler -->
<add name="jpgHandler" path="*.jpg" verb="*" type="WeiXinDemo.Globals.MyImgHandler,WeixinDemo" />
    <add name="pngHandler" path="*.png" verb="*" type="WeiXinDemo.Globals.MyImgHandler,WeixinDemo" />
<add name="bmpHandler" path="**.bmp" verb="*" type="WeiXinDemo.Globals.MyImgHandler,WeixinDemo" />
<add name="gifHandler" path="*.gif" verb="*" type="WeiXinDemo.Globals.MyImgHandler,WeixinDemo" />
</handlers> </system.webServer>

4. 通過 MVC 自定義路由規則防盜鏈

首先我們要在 web.config 文件里 system.webServer 節點下 設置<modules runAllManagedModulesForAllRequests="true" /> 同時還要在 RouteConfig.cs 文件里添加 routes.RouteExistingFiles = true;確保所有路由都通過 RouteCollection 匹配 。
在這里我們需要了解 UrlRoutingModule,它是System.Web.Routing的一部分。UrlRoutingModule用於檢驗請求的url和本地硬盤 中的文件能不能相匹配。如果匹配,則交給IIS處理。如果不匹配它會檢驗 RouteCollection 來決定能不能繼續傳遞請求。而設置了 runAllManagedModulesForAllRequests="true" 后,會改變默認行為,所有請求都須要 運用 Routing來處理。
<system.webServer>
    <validation validateIntegratedModeConfiguration="false" />
    <modules runAllManagedModulesForAllRequests="true" />    
    <handlers>
      <remove name="ExtensionlessUrlHandler-Integrated-4.0" />
      <remove name="OPTIONSVerbHandler" />
      <remove name="TRACEVerbHandler" /> 
      <add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="*" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />
    </handlers> 
  </system.webServer>

     配置文件設置好以后添加自定義路由規則,下面是自定義路由規則的實現代碼,其實里面就做了一件事,使用正則表達式判斷當前請求是否符合規則,如果符合規則,則進入指定的處理頁面,否則去匹配其他的路由規則。

 
        
namespace WeiXinDemo.Globals
{
    /// <summary>
    /// 圖片路由規則(自定義)
    /// </summary>
    public class ImgRouteRule : IRouteConstraint
    {  
        public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection)
        {
            var regex = new Regex(@"/[^/]+(.jpg|.bmp|.gif|.png)");
            var result = regex.IsMatch(httpContext.Request.RawUrl); 
            return result;
        }
    }
}
 
        

    這樣就造成了一個問題,所有的請求(比如 .css  .js  .htm 等等)都去路由規則里面去匹配,如果在路由規則里面匹配不到那么就會返回 404,如何避免呢?通過 RouteConfig.cs 文件配置忽略。

public class RouteConfig
    {
        public static void RegisterRoutes(RouteCollection routes)
        {
            //確保所有路由都通過 RouteCollection 匹配(圖片防盜鏈)
            routes.RouteExistingFiles = true;

            //忽略 json,html,js,css文件
            routes.IgnoreRoute("{*pathInfo}", new { pathInfo = @".+(.json|.html|.js|.css)" });
            routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
 //符合路由規則的轉到控制器 ImgRule/Index 處理 (自定義路由規則實現 圖片防盜鏈)
            routes.MapRoute(
                name: "ImagesRoute",
                url: "{*catchall}",
                defaults: new { controller = "ImgRule", action = "Index" },
                // ImgRouteRule 為自定義路由規則,符合此規則,進入路由 訪問 ImgRule/Index 
                constraints: new { customConstraint = new ImgRouteRule() },
                //控制器類命名空間
                namespaces: new[] { "WeiXinDemo.Controllers" });

            routes.MapRoute(
                name: "Default",
                url: "{controller}/{action}/{id}",
                defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
            );            
        }
    }

    在上面的代碼里配置了 "ImagesRoute"   的路由,使用的自定義路由規則,當滿足規則時,跳轉到 ImgRule/Index 去處理,處理代碼跟使用 HttpHandler 類似

 public class ImgRuleController : Controller
    {
        // GET: ImgRule
        public FileStreamResult Index()
        {
            var fPath = Server.MapPath("~" + Request.FilePath);
            if (Request.UrlReferrer == null)   return null;            

            if (!System.IO.File.Exists(fPath) || !WebApplication.ImgHost.Equals(Request.UrlReferrer.Host) || !WebApplication.ImgHost.Equals(Request.UrlReferrer.Host))            
                return null; 
            return GetFile(fPath);
        }

        private FileStreamResult GetFile(string fPath)
        { 
            return File(new FileStream(fPath, FileMode.Open, FileAccess.Read), GetContentType(Request.FilePath));
        }

        private static string GetContentType(string url)
        {
            switch (Path.GetExtension(url))
            {
                case ".gif":
                    return "Image/gif";
                case ".jpg":
                    return "Image/jpeg";
                case ".png":
                    return "Image/png";
                default:
                    break;
            }
            return null;
        }
    }

5. 通過
MVC 自定義 RouteHandler 防盜鏈
注意這里是自定義路由,別跟第4種方法混淆了,這里是指定自定義路由處理圖片。
1 web.config 文件配置同第4種方法,也要開啟 runAllManagedModulesForAllRequests="true"
2 創建自定義路由,自定義路實現代碼如下 ImageRouteHandler ,同時還有自定義路由調用的 HttpHandlerImageHandler
using System.IO;
using System.Text.RegularExpressions;
using System.Web;
using System.Web.Routing;

namespace WeiXinDemo.Globals
{
    /// <summary>
    /// 測試自定義 RouteHandler 圖片防盜鏈
    /// </summary>
    public class ImageRouteHandler : IRouteHandler
    {
        public IHttpHandler GetHttpHandler(RequestContext requestContext)
        { 
            return new ImageHandler();
        }
    }
     
    /// <summary>
    /// 自定義路由調用的 HttpHandler
    /// </summary>
    public class ImageHandler : IHttpHandler
    {
        public ImageHandler()
        {
            
        }
         
        public bool IsReusable
        {
            get
            {
                return true;
            }
        } 

        public void ProcessRequest(HttpContext context)
        {
            var response = context.Response;
            var request = context.Request; if (request.UrlReferrer == null || !WebApplication.ImgHost.Equals(request.UrlReferrer.Host))
            {
                response.End();
                return;
            }

            var fileName = context.Server.MapPath(request.FilePath);
            response.WriteFile(fileName);  
        }
    }
}

     RouteConfig.cs 文件配置 如下,這里指定了 對根目錄下的 jpg 文件的訪問進入指定路由處理程序 ImageRouteHandler。    其實這里可以把圖片都放在某一個特定文件夾下,然后對這個文件夾下文件的訪問做放盜鏈。

namespace WeiXinDemo
{
    public class RouteConfig
    {
        public static void RegisterRoutes(RouteCollection routes)
        {
            //確保所有路由都通過 RouteCollection 匹配(圖片防盜鏈)
            routes.RouteExistingFiles = true;

            //忽略 json,html,js,css文件
            routes.IgnoreRoute("{*pathInfo}", new { pathInfo = @".+(.json|.html|.js|.css)" });
            routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

            //圖片防盜鏈
            routes.Add("ImagesRoute",
                new Route("{name}.jpg", new ImageRouteHandler()));
 
            routes.MapRoute(
                name: "Default",
                url: "{controller}/{action}/{id}",
                defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
            );
            
        }
    }
}

6. 通過
HttpModule 防盜鏈
1. 修改 web.config 配置文件  
<system.webServer>
    <modules runAllManagedModulesForAllRequests="true" >
      <add   name="ImgModule" type="WeiXinDemo.Globals.ImageModel,WeiXinDemo"/>
    </modules> 
    <handlers>
      <remove name="ExtensionlessUrlHandler-Integrated-4.0" />
      <remove name="OPTIONSVerbHandler" />
      <remove name="TRACEVerbHandler" /> 
    </handlers>       
  </system.webServer>

2. 創建實現 IHttpModule 接口的 ImageModel

using System;
using System.Text.RegularExpressions;
using System.Web;

namespace WeiXinDemo.Globals
{
    /// <summary>
    /// 測試 HttpModel 圖片防盜鏈
    /// </summary>
    public class ImageModel : IHttpModule
    {
        public void Dispose()
        {
        }
public void Init(HttpApplication context) { context.BeginRequest += new EventHandler(BeginRequest); } void BeginRequest(object sender, EventArgs e) { HttpApplication context = (HttpApplication)sender; var regex = new Regex(@"/[^/]+(.jpg|.bmp|.gif|.png)"); var request = context.Context.Request; if (!regex.IsMatch(request.RawUrl)) return; if (request.UrlReferrer == null || !WebApplication.ImgHost.Equals(request.UrlReferrer.Host)) { context.Context.Response.End(); return; } var fileName = context.Context.Server.MapPath(request.FilePath); context.Context.Response.WriteFile(fileName); } } }

3.  RouteConfig.cs 文件忽略不需要防盜鏈的靜態資源

using System.Web.Mvc;
using System.Web.Routing;

namespace WeiXinDemo
{
    public class RouteConfig
    {
        public static void RegisterRoutes(RouteCollection routes)
        {
            //確保所有路由都通過 RouteCollection 匹配(圖片防盜鏈)
            routes.RouteExistingFiles = true;

            //忽略 json,html,js,css文件
            routes.IgnoreRoute("{*pathInfo}", new { pathInfo = @".+(.json|.html|.js|.css)" });
            routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

            routes.MapRoute(
                name: "Default",
                url: "{controller}/{action}/{id}",
                defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
            );            
        }
    }
}

 

7. 涉及知識

本文只做了一件事情,圖片防盜鏈,其實從不同的實現方式來看它涉及到不同的知識。

1. URL Rewrite Module  組件的使用

 如何使用mod_rewrite模塊完成URL重寫

 Creating Rewrite Rules for the URL Rewrite Module

2.  Nginx

借助Nginx搭建反向代理服務器

使用nginx實施負載均衡

3. IIS 工作原理,asp.net 管線

 IIS是如何處理ASP.NET請求的

ASP.NET那點不為人知的事

IIS 內部運行機制

ASP.NET MVC5請求管道和生命周期

ASP.NET MVC請求處理管道生命周期的19個關鍵環節(1-6)

4. Mvc UrlRouting 處理機制

MVC之前的那點事兒系列(8):UrlRouting的理解

 

    本文只是在這里探討了一下實現防盜鏈的方法,沒有考慮性能的問題,如果考慮性能跟簡便性,我個人喜歡用 第 1 和第 2種實現方式,第 3種 次之。 條條大路通羅馬,就看那種方法最適合。

     


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM