[基于Asp.Net的防盗链](三) 实践

上文介绍了思路,本篇根据 赞美诗网(http://www.zanmeishi.com/) 的实际情况,来加入防盗链功能。

 

赞美诗网 现状:启动了2个域名:
http://www.zanmeishi.com/    主站     所有的页面,都在主站
http://file.zanmeishi.com/       文件    文件站只提供 相应的 歌手形象照片,专辑封面,试听,下载,等的文件访问。

分别对应了 两个 web项目。  Zms.Web 和 Zms.File

 

文件存储方式如下,  在表中 (如歌曲表Song)  记录 试听和下载的文件位置。如:
试听: 表中记录     PlayUrl = /歌手/专辑/歌曲.wma 
试听: 表中记录     DownUrl = /歌手/专辑/歌曲.mp3
文件存在服务器中某目录。。。。

在 Zms.File 直接通过传递 歌曲(Song) 的 Id, 得到 文件保存的路径。。 然后读取文件,发送。。。
也就是说,我的文件都是通过 Asp.Net 程序发送的。。。采用了url重写,所以,你会得到像下载的地址:
http://file.zanmeishi.com/play/150/634/11864.wma
http://file.zanmeishi.com/play/150/634/11864.mp3

这个地址很简单,就是 /歌手Id/专辑Id/歌曲Id.wma   为什么要这样重写呢?
因为要考虑到,别人批量采集你的文件。。 所以,我加了 歌手,专辑,歌曲Id的限定。。

然后在 主站中 用一个方法来生成 试听 和 下载地址。。 Urls.Play     Urls.Down





项目的情况基本上是这样,  现在跟据这个情况,结合上文说的思路,我们来对 赞美诗网 做防盗链吧。。。

 

看看,我们怎么加密这个内容,
类型,标识,浏览器信息,IP,这都是很简单的,直接可以得到。。
比较麻烦的是,过期时间怎么处理。 生成hash后,这个hash要在指定的时间内有用,过期无效。。

我想到的办法是这样。。 先设定一个时间值,比如 60分钟。
得到当前时间,而且要得到一个累加的值,我使用当前年的1月1日0点0分0秒 做基数。
用当前 时间 去减去 基数,得到 总分钟数。。。。
然后用这个 总分钟数 对 60 取余,  再减去这个余数。。。。。
这样,我得到的这个值,  总是 60 的倍数(或说,是你设定时间的倍数)

比如,现在离2010年1月1日0点0分 相差的分钟数是  543 (随意值)。。
那这样算下来,得到的 值等于 543-(543%60) = 540 然后用这个值,去放到hash里面。
也就是说,得到的hash 在 540-600分钟之内,是有效的。  当到了 总分钟数到了 600的时候,  基数变成了 600。
所以,在之前的hash就没法通过验证了。就失效了。。


放代码,以下是生成hash的代码。。(伪代码):

 

 1 /// <summary>
 2 /// 生成 验证Hash
 3 /// </summary>
 4 /// <param name="type">类型</param>
 5 /// <param name="id">标识</param>
 6 /// <returns></returns>
 7 public static string Hash(string type, string id)
 8 {
 9     //得到:当前时间,和,减于基数的TimeSpan
10     var now = DateTime.Now;
11     var ts = now - new DateTime(now.Year, 11000);
12 
13     //得到:总分钟数,余数,参于hash的值 (也可以按秒计算,随意)(我这是60分钟)
14     int total = (int)ts.TotalMinutes;
15     int mod = total % 60;
16     int time = total - mod;
17 
18     //得到:浏览器信息,IP地址
19     string agent = Request.UserAgent;
20     string ip = Request.UserHostAddress;
21 
22     //Hash格式 (可以把几个参数调换位置 或 加一些混淆内容)(如果不要限制某一项,把参数去掉就可以了)
23     string encrypt = "{type}{id}{time}{agent}{ip}";
24 
25     //替换相应的内容
26     encrypt = encrypt.Replace("{type}", type);
27     encrypt = encrypt.Replace("{id}", id);
28     encrypt = encrypt.Replace("{time}", time.ToString());
29     encrypt = encrypt.Replace("{agent}", agent);
30     encrypt = encrypt.Replace("{ip}", ip);
31 
32     //算Md5 并转成小写
33     return Md5(encrypt).ToLower();
34 }

 

 
生成Hash的方法完成了。。 接下来,我们来包装URL。。
我把得到URL封装了两个方法,比如 Urls.Play   Urls.Down
我使用Play和Down做为类型,使用Id做为标识,这样来生成url

在这两个方法中,我把得到的URL加上一个参数, 就是生成的Hash 加在Url上。。所以,得到如下的地址:
http://file.zanmeishi.com/play/156/600/11398.wma?hash=804f14072e779121b00d340994f5e6d9
http://file.zanmeishi.com/down/156/600/11398.mp3?hash=a92ccb3f582fe9d8703377a08aedec20

具体生成Url的方法,我就不贴代码了,你可以按你自己的方法,来加上hash就可以了。


然后我在处理文件的时候,  得到参数 hash  ,然后又生成一个新的Hash,再去验证两个hash是否相等。。。
伪代码如下:

 1     //读文件参数,和数据的代码,省略,得到文件保存路径
 2     string file = Server.MapPath(".......");
 3 
 4     //得到类型和标识和Hash
 5     string type = "Play";    //注意,这个和你生成Hash时候使用的 type 要一致
 6     int id = Convert.ToInt32(Request.QueryString["SongId"]);
 7     string hash = Request.QueryString["SongId"];
 8 
 9     //生成新的hash
10     string newHash = Link.Hash(type, id);   //刚刚写的方法
11 
12     //判断两个hash是否一致,不区分大小写
13     if (string.Compare(newHash, hash, true!= 0)
14     {
15         //不一致,提示错误
16         Response.Write("请不要盗链本站文件!");
17         Response.End();
18     }
19     else
20     {
21         //输出文件
22         Response.WriteFile(file);
23     }

 


到这里就差不多了。。  可以试试了。。。。
注:如果你想取消某一项的限制,只需要在加密内容中去掉相应的参数即可。

测试请直接到 赞美诗网 http://www.zanmeishi.com
当前配置:类型+标识+时间(60分钟)+IP限制,  没有限制浏览器。。。

为什么不加浏览器限制呢,是因为我提供在线试听, 播放器和浏览器的 http header 是不同的,
所以,浏览时得到的hash, 在播放器中根本没法通过验证。。所以,取消了此限制。。。。。。
你可以根据自己的需求来增减相应的限制。。


补充上文忘记写的内容, 对于音乐试听,只判断来源页,是没办法防止的,因为播放器调用你的文件,是不携带,来源页的。。
所以,如果只判断来源,是没办法防止百度MP3来抓我的文件,提供给网友试听。。

所以,这里的IP限制很有作用,也就是说,百度抓到的Url,只有百度服务器的IP可以用。
这样,就算百度MP3提供试听,其它人是访问不了我的文件的了。。

 这样也可以限制下载软件,因为下载软件和浏览器携带的Http header 是不同的。。
用户在浏览网页是得到的Hash,去使用下载软件下载,是无法通过验证的。。

相对来说,这种方法可以防掉大部分的盗链,采集批量下载。。 可以只允许用户在浏览时候访问文件。。也防止URL被传播或是盗用。
其实商业的防盗链软件,差不多是类似的思路,不同的只是在加密内容和验证方式上做文章。。。
本文是使用Asp.Net来实现, 不需要使用isapi之类的底层方式,也同样可以实现很强的防盗链。
最重要的是:简单且免费~~



下篇剧透:应用此方式,使用 HttpModule 编写成 Asp.Net 组件。以实现通用。。将来在自己的项目中都会使用此组件防盗链。



枫知秋 原创文章 转载请声明 并 写明出处
http://jorise.cnblogs.com/

posted @ 2010-01-08 15:12  枫知秋  阅读(734)  评论(4编辑  收藏  举报