如果我們需要在站點上出售數字形式的商品,如電子書、數字油畫等,那麼如何在供授權用戶正常下載的同時又阻止非授權用戶非法下載您的產品呢? 通過Forms身份驗證,只能使這個問題得到部分解決。本文中,我將講解如何防止某些用戶訪問站點上的某些文件;即使這些文件能夠被這些用戶直接浏覽。
解決這個問題的方法有多種,但是有些方法本身就有問題。本文中,我們將考察軟件供應廠商常用的一些技術,然後再介紹一種新的解決方案。需要注意的是,這裡介紹的是針對ASP.net站點的。
二、常見的文件保護技術
我們中很多人都有網上購買軟件的經驗,所以可能領教過用於文件下載的常見保護措施。下面,我們對它們進行考察。
壓縮文件口令保護
這種保護方法比較簡單,它不是防止您下載文件,而是防止未經授權的人員從壓縮文件中提取文件的內容,因為WinZip和許多其他壓縮程序都提供了口令保護功能。然而,這種方法的缺點也很明顯,如果您允許某人訪問該文件內容,那就必須給他提供口令,之後,您卻無法阻止這個人將口令傳給其他人。實際上,如果您搜索互聯網的話,會發現各種各樣的口令遍地都是。采用這種保護措施的時候,只能指望授權用戶是有道德的人,不會將口令外傳。或者,將這種保護措施提供一個層次,為每個人生成一個不同口令的壓縮文件,然後傳給他。 當然,這需要一個文件存儲解決方案,因為需要能控制發送給用戶的文件。這導致第二種文件保護方法。
電子郵件
許多軟件供應廠商並不會把文件張貼到它們的網站上,而是向購買該軟件的用戶發送一封電子郵件,告知下載詳細信息,或者直接連同文件一塊發過去。 電子郵件可以包含文件下載鏈接,並限定該鏈接的有效時間。有時候,軟件供應商還可以將這種這種技術跟口令保護相結合。文件一旦交到用戶手裡,剩下的保護措施就靠軟件許可和注冊了。其他基於電子郵件的解決方案還有動態生成文件名方法。
臨時文件名
一些軟件供應廠商會使用GUID或者其它的秘密的命名技術生成一個難以猜測的文件名,同時還可以令文件只能在規定時間內下載。
三、技術分析
雖然這些技術仍在使用,但是它們卻不能在您的站點上開辟一片客戶區域,使得用戶能夠檢查他們的購買歷史記錄,並隨時重新下載他們的軟件。依我看來,提供了類似功能的站點能夠提供更好的用戶體驗,對軟件供應商來說也更容易管理——用戶購買產品之後,您僅需給用戶發送一封包含許可證密鑰和他們在站點上相應客戶區域的鏈接即可。這樣的話,用戶知道可以隨時登錄和下載軟件,他們就會安心多了,即使弄丟了軟件文件也不用怕了。
為此,我們將介紹一種結合了ASP.net的Forms身份驗證和稱為HTTP處理程序的保護方案來提供這種良好的用戶體驗。類System.Web.UI.Page本身就是一個HTTP處理程序,並且會注冊到您的機器的Web.config文件中。
內容導航四、HTTP處理程序
實際上,使用ASP.NET定制HTTP處理程序並沒有人們想象的那麼復雜,下面我們用盡量容易理解的方式來討論這一主題。HTTP處理程序的應用有很多,不過我們這裡主要討論它在文件保護問題方面的應用。
圖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身份驗證:
上面的代碼會防止沒有通過身份驗證的用戶訪問所有的頁面。如果一個匿名用戶試圖訪問一個網頁,該代碼會自動地將他們重定向到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”選項按鈕。
圖2 網站屬性
圖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方法並且執行重定向。
如您所見,這個頁面位於根目錄的Downloads/Files文件夾中,完整的FileDenialHandler.cs處理程序如下所示:
現在,這個FileDenialHandler類什麼也沒做,所以必須將其寫入站點。為了這樣,我們將其放入web.config文件的
文件web.config列出了配置部分的所有特殊處理程序,並為其規定了相應的信息,包括實例化這個處理程序的謂詞,匹配要讓這個處理程序來處理的文件的通配符路徑,以及用於該定制的處理程序的類型定義。在這個例子中,添加的配置部分如下所示:
參數type是標准的.NET完全限定名寫法,並通過逗號組合了一個組件程序集名稱。在實際的Web項目中編寫處理程序的時候,可以省去程序集名稱。
現在這個條目將所有的壓縮文件請求轉發給新的處理程序,因此立即將請求重定向到“Access Denied”頁面。即使在本例中跳過該IIS條目,它仍然會照常工作,因為這些事情都交由我們的處理程序了。 然而,我們想要的效果是讓系統在判定匿名用戶訪問非法的ZIP 文件之前,首先把他們導航至登錄頁面。
如果檢查框架目錄中的web.config文件,就會發現一列處理常見文件擴展名用於ASP.NET的處理程序。定義這個文件中的
所以您可能問,無什麼不只用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處理程序是最重要的一種。通過與其他技術相結合,我們不僅能夠防止非授權用戶下載文件,還能在處理用戶下載文件試圖時獲得絕對控制權,希望本文的內容對您能夠有所幫助。