首页 > 代码库 > asp.net MVC 网站图片防盗链的几种方法

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差了2个字,没有规则,这里是指定自定义路由处理图片。
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. 通过
HttpModModule 防盗链
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种 次之。 条条大路通罗马,就看那种方法最适合。

     

asp.net MVC 网站图片防盗链的几种方法