今天在书上偶然看到了如何实现防盗链的问题,到网上查看了一下盗链主要是其他的一些网站引用本站图片或者下载链接。如果被引用的站比较小这样外站盗链带来 的“无作用”流量就给站长带来了压力了(流量也是要钱滴)。对于防盗链可以从两个方面来防,一个是服务器,一个是程序里面判断。各个服务器的判断不一 样,iis需要安装特定的防盗链软件。我们今天主要讨论的是程序里实现防盗链。
网上现在比较流行的是使用handler来实现防盗链。具体的意思如下:专门新建一个针对某种文件请求的处理类(继承于IHttpHandler)并在 web.config里面配置好所有的该文件请求都指向该类。然后在类里面判断该请求的前一次请求是不是存在并且指向我们站的域名,如果存在则认为不是盗 链,返回真实的文件。否则返回error图片。
让我们设想一下如果现在另外一个网站引用了我们站的图片,并应用到了一篇文章当中。现在有个人请求那个网站的文章,用户的request是向他们的服务器 发出的,他们站的服务器返回html让浏览器解析。浏览器解析到我们的图片地址时他会向我们站发起这个图片的请求。因为我们程序的设置这个请求会被转发到 我们特定的类做处理,程序判断这个request前面的请求是不是为空(显然它只请求了我们的图片其他没有请求,所以当然没有前面的请求),为空则返回 error图片。理解了上面的过程就容易知道为什么请求我们站的那个网页时里面的图片则正确显示了,用户显示request了那个页面,所以里面当然有前 面访问的记录。当浏览器解析我们站的图片时候就正确返回了。不知道大家懂了没呢?
首先创建一个类继承于IHttpHandler,我这里就叫做ForbiddenInvaliteDownload类了:
代码 public bool IsReusable { get { return true; } } public void ProcessRequest(HttpContext context) { if (null != context.Request.UrlReferrer) { context.Response.Expires = 0; context.Response.Clear(); context.Response.ContentType = "image/jpg"; context.Response.WriteFile(context.Request.PhysicalPath); context.Response.End(); } else { context.Response.Expires = 0; context.Response.Clear(); context.Response.ContentType = "text/html"; context.Response.Write("盗链"); context.Response.End(); } }
代码很少,大家一看就明白了。就是用context.Request.UrlReferrer这个判断一下前面一个请求是否存在,存在则认为是合法的,否则不合法。
仅仅是这个类还不能将所有的jpg请求转发过来,我们需要配置一下webconfig,在System.Web下配置:
代码 <httpHandlers> <add verb="*" path="*.jpg" type="Namespace.ForbiddenInvaliteDownload,Namespace"/> </httpHandlers>
这里还要提到的是IIS默认是不会为JPG文件发送请求的,而是直接获取。所以我们还要在iis里面配置一下让所有的jpg请求都转发到我们的那个处理程序,而不是iis默认的直接获得。配置如图:
至此,你的网站已经可以防止jpg文件被盗了。当然,其他的zip等等文件同样也可以实现,您可以处理一个通用类,根据请求的后缀判断是什么类型从而进行操作。下面是效果图:
上面的方式并不能防止迅雷等下载软件的下载,在迅雷里面输入这些地址照样可以下载。如果别的站引用了你的某个.zip的文件链接,这样还是可以直接下载到的。那该如何解决呢?我目前想到的就是加入session验证。
如果用户访问了你的下载页面则在load里面设置session[“visited”]=”true”,然后在下载里面增加一个session验证,代码如下(注意,需要继承
System.Web.SessionState.IRequiresSessionState才能使用session):
代码 if (null != context.Request.UrlReferrer && context.Session["visited"] == "true") { context.Response.Expires = 0; context.Response.Clear(); context.Response.ContentType = "image/jpg"; context.Response.WriteFile(context.Request.PhysicalPath); context.Response.End(); } else { context.Response.Expires = 0; context.Response.Clear(); context.Response.ContentType = "image/jpg"; context.Response.WriteFile(context.Request.PhysicalApplicationPath + "Images/2.jpg"); context.Response.End(); }
这样我们调试的时候调用迅雷下载这个图片就可以发现session里面是没有值的,当然就下载error图片了。