ASP.NET中實現檔案的保護性下載基礎篇_實用技巧

來源:互聯網
上載者:User
一、檔案保護性下載的需求

  如果我們需要在網站上出售數字形式的商品,如電子書、數字油畫等,那麼如何在供授權使用者正常下載的同時又阻止非授權使用者非法下載您的產品呢? 通過Forms身分識別驗證,只能使這個問題得到部分解決。本文中,我將講解如何防止某些使用者訪問網站上的某些檔案;即使這些檔案能夠被這些使用者直接瀏覽。

  解決這個問題的方法有多種,但是有些方法本身就有問題。本文中,我們將考察軟體供應廠商常用的一些技術,然後再介紹一種新的解決方案。需要注意的是,這裡介紹的是針對ASP.net網站的。

  二、常見的檔案保護技術

  我們中很多人都有網上購買軟體的經驗,所以可能領教過用於檔案下載的常見保護措施。下面,我們對它們進行考察。

  壓縮檔口令保護

  這種保護方法比較簡單,它不是防止您下載檔案,而是防止未經授權的人員從壓縮檔中提取檔案的內容,因為WinZip和許多其他壓縮程式都提供了口令保護功能。然而,這種方法的缺點也很明顯,如果您允許某人訪問該檔案內容,那就必須給他提供口令,之後,您卻無法阻止這個人將口令傳給其他人。實際上,如果您搜尋互連網的話,會發現各種各樣的口令遍地都是。採用這種保護措施的時候,只能指望授權使用者是有道德的人,不會將口令外傳。或者,將這種保護措施提供一個層次,為每個人產生一個不同口令的壓縮檔,然後傳給他。 當然,這需要一個檔案儲存體解決方案,因為需要能控制發送給使用者的檔案。這導致第二種檔案保護方法。

  電子郵件

  許多軟體供應廠商並不會把檔案張貼到它們的網站上,而是向購買該軟體的使用者發送一封電子郵件,告知下載詳細資料,或者直接連同檔案一塊發過去。 電子郵件可以包含檔案下載連結,並限定該連結的有效時間。有時候,軟體供應商還可以將這種這種技術跟口令保護相結合。檔案一旦交到使用者手裡,剩下的保護措施就靠軟體許可和註冊了。其他基於電子郵件的解決方案還有動態組建檔案名方法。

  臨時檔案名稱

  一些軟體供應廠商會使用GUID或者其它的秘密的命名技術產生一個難以猜測的檔案名稱,同時還可以令檔案只能在規定時間內下載。

  三、技術分析

  雖然這些技術仍在使用,但是它們卻不能在您的網站上開闢一片用戶端區域,使得使用者能夠檢查他們的購買記錄,並隨時重新下載他們的軟體。依我看來,提供了類似功能的網站能夠提供更好的使用者體驗,對軟體供應商來說也更容易管理——使用者購買產品之後,您僅需給使用者發送一封包含許可證密鑰和他們在網站上相應用戶端區域的連結即可。這樣的話,使用者知道可以隨時登入和下載軟體,他們就會安心多了,即使弄丟了軟體檔案也不用怕了。

  為此,我們將介紹一種結合了ASP.net的Forms身分識別驗證和稱為HTTP處理常式的保護方案來提供這種良好的使用者體驗。類System.Web.UI.Page本身就是一個HTTP處理常式,並且會註冊到您的機器的Web.config檔案中。

內容導航

  四、HTTP處理常式

  實際上,使用ASP.NET定製HTTP處理常式並沒有人們想象的那麼複雜,下面我們用盡量容易理解的方式來討論這一主題。HTTP處理常式的應用有很多,不過我們這裡主要討論它在檔案保護問題方面的應用。

用ASP.NET實現檔案的保護性下載基礎篇

  圖1 IIS中的副檔名映射

  下面我們將介紹什麼是處理常式,及其工作原理,同時我們力爭做到進行可能簡單。在當ASP.NET環境中,您請求一個ASPX頁面的時候,IIS會將該請求傳遞給相應的DLL來進行處理。所謂HTTP處理常式,就是處理IIS傳給它們的請求的那些類。當您在機器上安裝ASP.NET的時候,會隨同向IIS添加一串表項(參見圖 1)。這些表項包含希望ASP.NET處理的檔案的副檔名(ASPX、ASMX等等)。當我們請求一個ASPX的時候,IIS收到該請求後,會將其傳遞給相應的DLL,在本例中為aspnet_isapi.dll,隨後生產相應的HTTP處理常式執行個體來處理該請求。就ASPX頁面而論,用到的HTTP處理常式是位於System.Web.UI命名空間中的一個Page類。

  就ASPX頁面而論,頁面處理常式用來控制和觸發生命週期事件;當您瀏覽一個ASPX頁面的時候,基本上一切工作都是由它來處理的。然而,您可以編寫一個定製的HTTP處理常式來攔截瀏覽器發出的所有的請求,從而調整或者定製正常發生的動作。為此,我們需要用到多種技術,本文中我將首先討論其中的IIS表項,以及Forms身分識別驗證有關內容。

  五、IIS與Forms身分識別驗證

  前面提過,IIS會把註冊的副檔名發送到aspnet_isapi.dll。圖1展示的是找到的登入副檔名。我們可以在虛擬目錄或者網站的“Properties”中的“Configuration”選項就可以看到這個對話方塊。帶有由aspnet_isapi.dll進行處理的登入副檔名的任何檔案都受到ASP.NET的Forms身分識別驗證的支配。下面我們對Forms身分識別驗證的運行機製做簡單介紹。

  定製的HTTP處理常式實際上就是實現了IHttpHandler介面的那些類。Forms身分識別驗證允許您防止匿名使用者在未授權的情況下訪問某些web頁面。檔案web.config利用以下代碼來設定Forms身分識別驗證:



Code highlighting produced by Actipro CodeHighlighter (freeware)
http://www.CodeHighlighter.com/

   <authentication mode="Forms">
   <forms loginUrl="Login.aspx"/>
   </authentication>
   <authorization>
   <deny users="?"/>
   </authorization>

  上面的代碼會防止沒有通過身分識別驗證的使用者訪問所有的頁面。如果一個匿名使用者試圖訪問一個網頁,該代碼會自動地將他們重新導向到Login.aspx頁面。這樣一來,網站開發人員就能決定在這個頁面中使用哪種驗證方法,但是在ASP.NET 2.0中,開發人員可以很輕鬆地使用新的安全控制項來完成此項工作。

  現在,我們說過這個代碼能夠阻止未通過身分識別驗證的使用者訪問任何頁面,但是準確來說它是阻止了未經認證的使用者訪問所有被aspnet_isapi.dll攔截的那些檔案。這將在後面詳加解釋。為了給本文的後面的內容做鋪墊,我們需要先描述樣本電子商務網站的一些具體細節。

內容導航

  六、保護措施規劃

  假設我們的網站使使用者能線上購買軟體,但是在購買或者下載軟體之前,使用者必須首先註冊。然後,分別為使用者和產品建立一個表,然後分別存放使用者名稱和產品序號。當使用者購買軟體的時候,通過在另一個表中建立一個記錄來關聯使用者和產品。我們稱這個表為UserProducts。

  我們想把所有的軟體產品檔案儲存體在一個稱為files的檔案夾中,該檔案夾位於網站的根資料夾之中。產品表有一個欄位,用於產品檔案名稱,該檔案名稱對應於files檔案夾中的一個壓縮檔。 我們稱這個欄位為ProductFileName。下面我們逐步介紹如何保護這些ZIP 檔案。

  七、保護所有的壓縮檔

  首先,我們要防止所有的壓縮檔被未經驗證的使用者所下載。我們要讓所有副檔名為.zip的檔案經由ASP.NET 的Forms身分識別驗證處理,這樣匿名使用者就不能訪問它們了。雖然這一步並不是最關鍵的,但是它確實提供了檔案的安全性。

  通常如果您能直接瀏覽某網站上的一個ZIP 檔案,該網站會提示您開啟或者將該檔案儲存到硬碟上。我們想讓ASP.NET攔截對副檔名為zip的檔案的請求,所以需要在IIS的應用程式對應表中添加相應的副檔名。

  為此,可以開啟IIS的管理主控台,找到相應的網站或虛擬目錄,單擊右鍵並選擇“Properties”選項,就會顯示圖 2。如果單擊“Web Site”或者“Virtual Directory”選項卡中的“Configuration”按鈕的話,就會看到副檔名表和用於處理它們的DLL,見圖1。我們必須將副檔名“zip”添加到這個列表中,為此,可以單擊“add”按鈕,然後再副檔名文字框中鍵入“zip”,並單擊“Limit to verb”選項按鈕。

用ASP.NET實現檔案的保護性下載基礎篇

圖2 網站屬性

用ASP.NET實現檔案的保護性下載基礎篇

圖3 導航至aspnet_isapi.dll

內容導航

  在Verbs文字框中,鍵入GET、HEAD、POST、DEBUG,以指示aspnet_isapi.dll攔截zip類型檔案的請求。在Executable:文字框中,導航至aspnet_isapi.dll檔案的位置,見圖3。這個檔案位於相應架構版本檔案夾下的C:\WINDOWS\Microsoft.NET\Framework\目錄中,如圖4所示。

  

圖4 給IIS添加zip副檔名映射

  

圖5 映射zip副檔名

  建立這個表項後,我們的映射表將如圖5所示。注意在這個表中的所有其他副檔名例如VBPROJ、CONFIG等等,aspnet_isapi.dll也會攔截這些副檔名以便進行保護。這就是當企圖瀏覽web.config檔案時會被重新導向到一個拒絕頁面的原因。

  在IIS中建立這個表項之後,如果嘗試直接瀏覽我們網站上的ZIP檔案的時候,如果使用者沒有通過身分識別驗證的話,IIS會將其重新導向到登入頁面。所以,現在我們已經能夠防止匿名使用者下載我們的檔案了,不過,一旦通過了網站的身分識別驗證,這種保護就形同虛設了。

內容導航

  八、更加具體的保護措施

  我們的目標是,讓授權使用者能夠瀏覽一個包含了已經購買的軟體的頁面,並且通過單擊其中的連結就可以下載特定的商品。列出產品時,可以使用表結構,但是如何來保護連結呢? 之前我們介紹的方法只是防止匿名使用者下載壓縮檔,但是現在我們要防止授權使用者直接瀏覽壓縮檔。為此,我們需要編寫一個定製的處理常式。

  定製的HTTP處理常式是實現了IHttpHandler介面的類。這個介面定義了一個稱為ProcessRequest的方法,以及一個Boolean類型的名為IsReusable的屬性。該屬性決定了其它請求是否能夠利用同一個處理常式,所以這裡簡單返回一個真值。這個方法將會收到一個HttpContext類型的參數。這變數為我們提供了訪問該請求整個內容相關的許可權,包括請求中的資訊和訂製另一個方向上的請求的方法。

  現在,我們要建立一個稱為FileDenialHandler的處理常式,它的作用是停止一個請求,並將使用者重新導向到一個頁面來通知他們訪問被拒絕。當這個處理常式取得該請求的時候,就會調用ProcessRequest方法並且執行重新導向。



Code highlighting produced by Actipro CodeHighlighter (freeware)
http://www.CodeHighlighter.com/

public void ProcessRequest(HttpContext context)
   {
   context.Response.Redirect(
      "~/Downloads/Files/AccessDenied.aspx");
   }

  如您所見,這個頁面位於根目錄的Downloads/Files檔案夾中,完整的FileDenialHandler.cs處理常式如下所示:



Code highlighting produced by Actipro CodeHighlighter (freeware)
http://www.CodeHighlighter.com/

using System;
using System.Data;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
namespace DotNetDude.Web.UI
{
   public class FileDenialHandler : IHttpHandler
   {
      public void ProcessRequest(HttpContext context)
      {
         context.Response.Redirect(
            "~/Downloads/Files/AccessDenied.aspx");
      }

      public bool IsReusable
      {
         get
         {
            return true;
         }
      }
   }
}

  現在,這個FileDenialHandler類什麼也沒做,所以必須將其寫入網站。為了這樣,我們將其放入web.config檔案的中。

  檔案web.config列出了配置部分的所有特殊處理常式,並為其規定了相應的資訊,包括執行個體化這個處理常式的謂詞,匹配要讓這個處理常式來處理的檔案的萬用字元路徑,以及用於該定製的處理常式的類型定義。在這個例子中,添加的配置部分如下所示:



Code highlighting produced by Actipro CodeHighlighter (freeware)
http://www.CodeHighlighter.com/

   <httpHandlers>
   <add verb="*" path="*.zip"
   type="DotNetDude.Web.UI.
   FileProtectionHandler,
   DotNetDude.HttpHandlers"/>
   </httpHandlers>

  參數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”。此外,我們還要訪問請求的產品號碼,代碼如下所示:



Code highlighting produced by Actipro CodeHighlighter (freeware)
http://www.CodeHighlighter.com/

context.Request.QueryString["Product"]

  這樣,我們就取得了產品號碼和使用者名稱。 有了這兩者,我們就可以訪問UserProducts表並確定這個使用者是否購買過這個產品。此外,這個表還儲存有該產品的檔案名稱。

  既然有了使用者名稱和產品號碼,並通過它們確定除了使用者購買情況。如果該使用者沒有購買相應的產品,我們就將其重新導向到前面的處理常式,並返回一個訪問拒絕頁面。為簡潔起見,我們將其重新導向到一個告知他們還沒有購買過此產品的頁面,並告知如何進行購買。

  如果確定該使用者購買了這個產品,可以通過ProductFileName欄位瞭解該使用者可以查看哪些檔案。這裡,我們沒有儲存完整的路徑,只是儲存了檔案名稱。如果需要,我們可以從web.config中的設定來獲得該檔案夾,所以最終獲得了完整的檔案路徑和名稱,並授權下載。 下面我們通過稱為StartDownload方法來完成此任務:



Code highlighting produced by Actipro CodeHighlighter (freeware)
http://www.CodeHighlighter.com/

private void StartDownload(
       HttpContext context, string downloadFile)
   {
         context.Response.Buffer = true;
         context.Response.Clear();
         context.Response.AddHeader(
            "content-disposition",
            "attachment; filename=" + downloadFile);
         context.Response.ContentType =
            "application/zip";
         context.Response.WriteFile(
            "~/Downloads/Files/" + downloadFile);
   }

  這裡的ProcessRequest方法會調用StartDownload方法,完整的Download.ashx代碼如下所示:



Code highlighting produced by Actipro CodeHighlighter (freeware)
http://www.CodeHighlighter.com/

<%@ WebHandler Language="C#" Class="Download" %>
using System;
using System.Web;
public class Download : IHttpHandler
{
   public void ProcessRequest (HttpContext context)
   {
      if (context.User.Identity.IsAuthenticated)
      {
         if(context.Request.QueryString["Product"] != null
            && context.Request.QueryString["Product"] != "")
         {
            int productID = Convert.ToInt16(
               context.Request.QueryString["Product"]);
            string userName = context.User.Identity.Name;
            UserProduct product = UserProductFactory.GetProductByUser(
               userName, productID);
            if(product != null)
               StartDownload(product.FileName);
            else
               context.Response.Redirect(
                  "~/Downloads/Files/AccessDenied.aspx");
         }
      }
   }

   public bool IsReusable
   {
      get
      {
         return false;
      }
   }
   private void StartDownload(string downloadFile)
   {
      context.Response.Buffer = true;
      context.Response.Clear();
      context.Response.AddHeader(
         "content-disposition",
         "attachment; filename=" + downloadFile);
      context.Response.ContentType = "application/zip";
      context.Response.WriteFile(
         "~/Downloads/Files/" + downloadFile);
   }
}

  這個方法會收到檔案的名稱以及HttpContext。由此處,我們將清空響應緩衝區,設定一個新的頭部,然後設定內容類型。最後,使用WriteFile方法輸出該檔案,終端使用者會收到一個檔案儲存或開啟視窗。

  注意,使用WriteFile會輸出ZIP 檔案,而是要Response.Redirect則會把使用者重新導向到訪問拒絕頁面。使用這種技術的時候,聰明的使用者可以繞過安全檢查而直接導航至Download.ashx檔案。但即使它們設法直接瀏覽到ZIP 檔案,也會被FileDenialHandler處理常式重新導向到訪問拒絕頁面。

  注意這兩種類型處理常式的區別,一個是可以放在外部組件中的標準C#(或者VB.NET)類,如果您需要編寫可重用的處理常式的時候,這種類型比較理想,因為您可以把它們編譯成一個動態連結程式庫,並在不同的網站之間分享。當然,我們需要在web.config檔案中對它們進行註冊。對於ASHX類型的處理常式,可以像ASPX頁面一樣添加到網站中。事實上,我們可以使用其他技術來完成類似Download.ASHX的功能,但是ASHX處理常式是更加簡潔的解決方案。

  十、小結

  使用ASP.NET保護檔案下載的所有方法中,利用HTTP處理常式是最重要的一種。通過與其他技術相結合,我們不僅能夠防止非授權使用者下載檔案,還能在處理使用者下載檔案試圖時獲得絕對控制權,希望本文的內容對您能夠有所協助。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.