如果我们需要在站点上出售数字形式的商品,如电子书、数字油画等,那么如何在供授权用户正常下载的同时又阻止非授权用户非法下载您的产品呢? 通过Forms身份验证,只能使这个问题得到部分解决。本文中,我将讲解如何防止某些用户访问站点上的某些文件;即使这些文件能够被这些用户直接浏览。
解决这个问题的方法有多种,但是有些方法本身就有问题。本文中,我们将考察软件供应厂商常用的一些技术,然后再介绍一种新的解决方案。需要注意的是,这里介绍的是针对ASP.net站点的。
二、常见的文件保护技术
我们中很多人都有网上购买软件的经验,所以可能领教过用于文件下载的常见保护措施。下面,我们对它们进行考察。
压缩文件口令保护
这种保护方法比较简单,它不是防止您下载文件,而是防止未经授权的人员从压缩文件中提取文件的内容,因为WinZip和许多其他压缩程序都提供了口令保护功能。然而,这种方法的缺点也很明显,如果您允许某人访问该文件内容,那就必须给他提供口令,之后,您却无法阻止这个人将口令传给其他人。实际上,如果您搜索互联网的话,会发现各种各样的口令遍地都是。采用这种保护措施的时候,只能指望授权用户是有道德的人,不会将口令外传。或者,将这种保护措施提供一个层次,为每个人生成一个不同口令的压缩文件,然后传给他。 当然,这需要一个文件存储解决方案,因为需要能控制发送给用户的文件。这导致第二种文件保护方法。
电子邮件
许多软件供应厂商并不会把文件张贴到它们的网站上,而是向购买该软件的用户发送一封电子邮件,告知下载详细信息,或者直接连同文件一块发过去。 电子邮件可以包含文件下载链接,并限定该链接的有效时间。有时候,软件供应商还可以将这种这种技术跟口令保护相结合。文件一旦交到用户手里,剩下的保护措施就靠软件许可和注册了。其他基于电子邮件的解决方案还有动态生成文件名方法。
临时文件名
一些软件供应厂商会使用GUID或者其它的秘密的命名技术生成一个难以猜测的文件名,同时还可以令文件只能在规定时间内下载。
三、技术分析
虽然这些技术仍在使用,但是它们却不能在您的站点上开辟一片客户区域,使得用户能够检查他们的购买历史记录,并随时重新下载他们的软件。依我看来,提供了类似功能的站点能够提供更好的用户体验,对软件供应商来说也更容易管理——用户购买产品之后,您仅需给用户发送一封包含许可证密钥和他们在站点上相应客户区域的链接即可。这样的话,用户知道可以随时登录和下载软件,他们就会安心多了,即使弄丢了软件文件也不用怕了。
为此,我们将介绍一种结合了ASP.net的Forms身份验证和称为HTTP处理程序的保护方案来提供这种良好的用户体验。类System.Web.UI.Page本身就是一个HTTP处理程序,并且会注册到您的机器的Web.config文件中。
内容导航四、HTTP处理程序
实际上,使用ASP.NET定制HTTP处理程序并没有人们想象的那么复杂,下面我们用尽量容易理解的方式来讨论这一主题。HTTP处理程序的应用有很多,不过我们这里主要讨论它在文件保护问题方面的应用。
图4 给IIS添加zip扩展名映射
图5 映射zip扩展名
建立这个表项后,我们的映射表将如图5所示。注意在这个表中的所有其他扩展名例如VBPROJ、CONFIG等等,aspnet_isapi.dll也会拦截这些扩展名以便进行保护。这就是当企图浏览web.config文件时会被重定向到一个拒绝页面的原因。
在IIS中创建这个表项之后,如果尝试直接浏览我们站点上的ZIP文件的时候,如果用户没有通过身份验证的话,IIS会将其重定向到登录页面。所以,现在我们已经能够防止匿名用户下载我们的文件了,不过,一旦通过了站点的身份验证,这种保护就形同虚设了。
内容导航八、更加具体的保护措施
我们的目标是,让授权用户能够浏览一个包含了已经购买的软件的页面,并且通过单击其中的链接就可以下载特定的商品。列出产品时,可以使用表结构,但是如何来保护链接呢? 之前我们介绍的方法只是防止匿名用户下载压缩文件,但是现在我们要防止授权用户直接浏览压缩文件。为此,我们需要编写一个定制的处理程序。
定制的HTTP处理程序是实现了IHttpHandler接口的类。这个接口定义了一个称为ProcessRequest的方法,以及一个Boolean类型的名为IsReusable的属性。该属性决定了其它请求是否能够利用同一个处理程序,所以这里简单返回一个真值。这个方法将会收到一个HttpContext类型的参数。这变量为我们提供了访问该请求整个上下文的权限,包括请求中的信息和订制另一个方向上的请求的方法。
现在,我们要创建一个称为FileDenialHandler的处理程序,它的作用是停止一个请求,并将用户重定向到一个页面来通知他们访问被拒绝。当这个处理程序取得该请求的时候,就会调用ProcessRequest方法并且执行重定向。
如您所见,这个页面位于根目录的Downloads/Files文件夹中,完整的FileDenialHandler.cs处理程序如下所示:
现在,这个FileDenialHandler类什么也没做,所以必须将其写入站点。为了这样,我们将其放入web.config文件的中。
文件web.config列出了配置部分的所有特殊处理程序,并为其规定了相应的信息,包括实例化这个处理程序的谓词,匹配要让这个处理程序来处理的文件的通配符路径,以及用于该定制的处理程序的类型定义。在这个例子中,添加的配置部分如下所示:
参数type是标准的.NET完全限定名写法,并通过逗号组合了一个组件程序集名称。在实际的Web项目中编写处理程序的时候,可以省去程序集名称。
现在这个条目将所有的压缩文件请求转发给新的处理程序,因此立即将请求重定向到“Access Denied”页面。即使在本例中跳过该IIS条目,它仍然会照常工作,因为这些事情都交由我们的处理程序了。 然而,我们想要的效果是让系统在判定匿名用户访问非法的ZIP 文件之前,首先把他们导航至登录页面。
如果检查框架目录中的web.config文件,就会发现一列处理常见文件扩展名用于ASP.NET的处理程序。定义这个文件中的部分的处理程序决定了IIS如何恰当地转发ASPX页面、ASMX Web 服务以及所有其他文件。 这个处理程序列表还定义了哪些文件扩展名是禁用的,例如*.config。事实上,可以利用一个称为HttpForbiddenHandler的处理程序来禁用所有以扩展名.config结尾的文件,并自动显示一个“HTTP 403error Forbidden :Access is denied ”页面。
所以您可能问,无什么不只用Microsoft提供的处理程序来处理压缩文件呢? 答案是,当然可以用,不过我们需要自己的“access denied”页面,这样通过定制我们自己的拒绝页面,就能跟我们的网站风格保持一致。在某些情况下,我们还想为用户提供更多的信息,甚至向管理员发送“未经授权的尝试”类电子邮件。
这里只是防止下载所有的压缩文件,但是我们实际想要做的是什么?对了,我们要取得从我们站点上文件下载方式的绝对控制权。我们不想让用户直接浏览压缩文件。通过表结构,我们可建立一个项目、用户列表,以及每个用户购买产品的关系表。因此如果我们有一个用户名和一个产品序列号,就可以通过一个简单的数据库查询来判断这个用户是否购买了这个产品。同时,我们还想让用户只需单击一个链接就能启动查询并确定是否被允许下载文件。 这些功能的确非常令人向往。
内容导航九、控制下载
下面,我们开始讲述如何编写一个用于某些文件请求的处理程序,以及该处理程序的安装方法。我们的处理程序的功能很简单,它只是将请求重定向到其他地方而已。ASP.NET还提供了另外一种文件扩展名即ASHX,它无需安装到web.config文件中。我们可以创建一个以这个扩展名结尾的类,来实现IHttpHandler接口,并就直接导航至该类。实际上它与一个页面非常类似,只是它不会使用Web表单和Code-Behind类,所以它是一种更加简洁的方案。
现在,我们创建一个新的处理程序称为Download.ashx,并让用户浏览到该处理程序的位置,同时在QueryString参数中规定一些信息。下面的URL就是下载链接:
~/Downloads/Download.ashx?Product=101
这个URL表示下载与产品101有关的文件。用户或者链接可以访问上述URL来试图下载一个文件,这时,该处理程序的ProcessRequest方法就会执行。
利用标准Forms身份验证对用户身份进行验证,这样就能访问在我们站点上下文中的User对象。请记住,HTTP上下文会传递给该处理程序的ProcessRequest方法,所以能访问到所需的内容。对象User允许我们获得使用User.Identity.Name的授权用户的名称,还有,我们还可以使用该方法访问User表中的用户。访问用户的名称,我们要使用User.Identity.IsAuthenticated的值来检查他们是否已经过身份认证,如果没有,将其重定向到“access denied”。此外,我们还要访问请求的产品号码,代码如下所示:
这样,我们就取得了产品号码和用户名。 有了这两者,我们就可以访问UserProducts表并确定这个用户是否购买过这个产品。此外,这个表还存储有该产品的文件名。
既然有了用户名和产品号码,并通过它们确定除了用户购买情况。如果该用户没有购买相应的产品,我们就将其重定向到前面的处理程序,并返回一个访问拒绝页面。为简洁起见,我们将其重定向到一个告知他们还没有购买过此产品的页面,并告知如何进行购买。
如果确定该用户购买了这个产品,可以通过ProductFileName字段了解该用户可以查看哪些文件。这里,我们没有存储完整的路径,只是存储了文件名。如果需要,我们可以从web.config中的设置来获得该文件夹,所以最终获得了完整的文件路径和名称,并授权下载。 下面我们通过称为StartDownload方法来完成此任务:
这里的ProcessRequest方法会调用StartDownload方法,完整的Download.ashx代码如下所示:
这个方法会收到文件的名称以及HttpContext。由此处,我们将清空响应缓冲区,设置一个新的头部,然后设置内容类型。最后,使用WriteFile方法输出该文件,最终用户会收到一个文件保存或打开窗口。
注意,使用WriteFile会输出ZIP 文件,而是要Response.Redirect则会把用户重定向到访问拒绝页面。使用这种技术的时候,聪明的用户可以绕过安全检查而直接导航至Download.ashx文件。但即使它们设法直接浏览到ZIP 文件,也会被FileDenialHandler处理程序重定向到访问拒绝页面。
注意这两种类型处理程序的区别,一个是可以放在外部组件中的标准C#(或者VB.NET)类,如果您需要编写可重用的处理程序的时候,这种类型比较理想,因为您可以把它们编译成一个动态链接库,并在不同的站点之间分享。当然,我们需要在web.config文件中对它们进行注册。对于ASHX类型的处理程序,可以像ASPX页面一样添加到站点中。事实上,我们可以使用其他技术来完成类似Download.ASHX的功能,但是ASHX处理程序是更加简洁的解决方案。
十、小结
使用ASP.NET保护文件下载的所有方法中,利用HTTP处理程序是最重要的一种。通过与其他技术相结合,我们不仅能够防止非授权用户下载文件,还能在处理用户下载文件试图时获得绝对控制权,希望本文的内容对您能够有所帮助。
新闻热点
疑难解答
图片精选