下載許可權控制機制
要對下載的許可權進行精確的控制(防止盜鏈,防止迅雷吸血,下載扣除積分等虛擬貨幣),以前接觸的方法有幾種:
1、通過rewrite不斷地更改下載檔案的url,並插入很多無意義的字元;
2、驗證下載連結的來路,或者cookie;
3、通過伺服器端程式(例如一個php檔案),open檔案,讀取內容然後返回給客戶端。
第一種方法很笨,而且吃力不討好;
第二種方法很容易破解,因為referer和cookie都是客戶端發出的,能夠方便地偽造,而且迅雷對此已經是輕車熟路;
第三種方法是可行的有效的,所有的檔案都經過一個程式讀取併傳送,在讀取之前可以有效的驗證許可權,但是下載過程中始終要佔用一個cgi執行緒,而且一般cgi語言的IO效能都不好,速度很慢,佔用了伺服器的大量資源,導致總體效率極其低下,難以大規模運用。
為此我研究了一下csdn下載頻道的實現機制。
csdn下載頻道能夠有效的驗證許可權,扣除積分,而且不排斥迅雷等下載客戶端,同一個使用者下載同一個檔案也不會重複扣除積分,而且下載時始終沒有暴露檔案的真實地址,同一個下載URL到了別的地方也完全不可用,可以說是實現得比較理想的。
我選擇了一個檔案進行測試,下載的url是: http://dldx.csdn.net/fd.php?i=573624740728082&s=4fc2353ca769a0ebd9237b6f98791679
這個url向檔案儲存伺服器上的fd.php檔案傳送了兩個經過加密的引數,裡面應該包含有使用者登入資訊(使用者ID和sid)和目標檔案的ID號。
用迅雷下載這個檔案,截獲返回的頭資訊:
Host: dldx.csdn.net
Pragma: no-cache
Range: bytes=0-
Referer: http://d.download.csdn.net/down/2474072/waf9898
User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; )
HTTP/1.1 206 Partial Content
Server: nginx/0.7.65
Date: Tue, 22 Jun 2010 07:08:21 GMT
Content-Type: “application/octet-stream; charset=utf-8″
Content-Length: 667747
Last-Modified: Mon, 21 Jun 2010 23:45:02 GMT
Connection: keep-alive
Content-Disposition: attachment; filename=”DNF%E6%82%A0%E6%82%A05%5B1%5D.7.rar”
Expires: 0
Cache-Control: must-revalidate, post-check=0, pre-check=0
Content-Range: bytes 0-667746/667747
這裡面始終沒有暴露目標檔案的真實路徑,不是一般下載系統所使用的header重定向的方式。而且有一個重新命名的訊號。伺服器使用的程式是nginx/0.7.65。
根據這些資訊,在google搜尋到這篇文章:http://kovyrin.net/2006/11/01/nginx-x-accel-redirect-php-rails/
顯然,csdn就是使用了文中所說的nginx X-Accel-Redirect。
解釋一下整個過程:
步驟1,客戶端請求http://dldx.csdn.net/fd.php ,並傳遞相關資訊;
步驟2,fd.php根據所傳遞的資訊判斷出訪問者的身份和所請求的資源,然後應該驗證了客戶端的IP,進一步判斷其許可權。如果這個客戶端有權下載 此檔案,則在HTTP header加入X-Accel-Redirect: (檔案的真實路徑),並加上head Content-Type和Content-Disposition:;
步驟3,nginx得到fd.php的回應後發現帶有X-Accel-Redirect的header,那麼根據這個頭記錄的路徑資訊開啟目標檔案;
步驟4,nginx把開啟檔案的內容返回給客戶端。
這樣所有的許可權檢查和積分扣除等操作都可以在步驟2內完成,而且fd.php返回帶X-Accel-Redirect的頭後,其執行已經終止,剩下 的傳輸檔案的工作由nginx 來接管,同時X-Accel-Redirect頭的資訊被nginx刪除,不會返回給客戶端,也就不會暴露(實際上可以把目標檔案儲存在不能經由web訪 問的目錄),並且由於nginx在開啟靜態檔案上使用了 sendfile(),其IO效率非常高,比php的IO要快上N++倍。
這是一種優雅,有效,高效的實現方案。
因為沒有架設過nginx伺服器,我希望能在apache實現這個功能,於是查詢了一下有沒有類似的mod,果然查詢到了一個 mod_xsendfile:http://tn123.ath.cx/mod_xsendfile/ ,其實現機制與nginx的X-Accel-Redirect基本相同。
下載之後在本機測試。
1、載入mod_xsendfile。將檔案 mod_xsendfile.so 移動到 apache/modules 目錄下,將以下內容新增到httpd.conf中
LoadModule xsendfile_module modules/mod_xsendfile.so
XSendFile On
XSendFileAllowAbove On
2、使用PHP呼叫X-sendfile。程式碼如下:
接收_GET資料並解密;
驗證uid、sid、檔案id;
如果通過驗證:
{
扣除積分、計數統計等操作;
header(`Content-Type:(目標檔案型別)`);
header(`Content-Disposition: attachment; filename=”(希望客戶下載到的檔名)”`);
header(`X-Sendfile:(目標檔案真實路徑,使用絕對路徑,例如”E:/www/dl/test.rar`,此路徑可以是web無法訪問的目錄”)`);
exit;
}
如果不通過:
{
給客戶端返回一個提示性的html檔案;
}
?>
3、構造下載url,用迅雷成功下載;破壞驗證條件(比如改變客戶端IP)之後,迅雷只能下載到提示錯誤的檔案。
實際應用中可以採用以下具體方案:
1、把所有的目標檔案都儲存在伺服器B,此伺服器不需要資料庫,而且通過web只能訪問到某入口檔案(比如http://dldx.csdn.net/fd.php),在這個檔案中配合apache實現X-Sendfile;
2、 網站檔案(php和html),以及資料庫執行在伺服器A(當然資料庫也可以另設伺服器),此伺服器負責構造類似於 http://dldx.csdn.net/fd.php?i=573624740728082&s=4fc2353ca769a0ebd9237b6f98791679 的url;
3、伺服器B接到以上URL以後,分析客戶端IP,然後遠端連線伺服器A的資料庫,把uid,sid,檔案id,客戶端IP進行匹配分析,通過則扣除積分放行下載,否則提示錯誤。
此方案最終就能夠實現以下目的:
1、任何方式都無法直接通過web訪問到目標檔案,迅雷也沒有辦法;
2、類似於 http://dldx.csdn.net/fd.php?i=573624740728082&s=4fc2353ca769a0ebd9237b6f98791679 的URL沒有通用性,只能特定的使用者在特定的IP訪問特定的檔案,迅雷即使把這個URL儲存起來,也是沒有辦法吸血的(只能下載到提示錯誤的檔案);
3、檔案儲存和資料庫兩臺伺服器乾淨的分割,便於維護;
4、速度和效果都很完美,不會產生驗證差錯,也不會過多佔用伺服器資源。
本文轉自today4king部落格園部落格,原文連結:http://www.cnblogs.com/jinzhao/archive/2011/03/27/1997038.html,如需轉載請自行聯絡原作者
相關文章
- Solaris下控制ftp的許可權FTP
- Android許可權管理之Permission許可權機制及使用Android
- android permission 許可權與安全機制解析(下)Android
- Android 安全架構及許可權控制機制剖析Android架構
- 許可權控制下的SQL寫法SQL
- Linux中的許可權機制Linux
- Django許可權機制的實現Django
- Elasticsearch 許可權控制Elasticsearch
- 如何用 Vue 實現前端許可權控制(路由許可權 + 檢視許可權 + 請求許可權)Vue前端路由
- Linux許可權控制Linux
- Appfuse:許可權控制APP
- 填報表上下載檔案控制元件可寫許可權控制控制元件
- Python下載網易雲歌曲(版許可權制的怎麼播放和下載呢?)Python
- vsftpd許可權控制(使用者能上傳下載不能刪除)FTP
- android 6.0許可權機制的簡單封裝(支援批量申請許可權)Android封裝
- Laravel實現許可權控制Laravel
- mysql 許可權控制筆記MySql筆記
- oracle列級許可權控制Oracle
- Linux的許可權控制Linux
- .NET 程式許可權控制、獲得管理員許可權程式碼
- android permission許可權與安全機制解析(上)Android
- Android6.0執行時許可權機制Android
- 我的Django專案中的許可權機制Django
- js 許可權二進位制JS
- 資料分析的許可權控制
- 許可權控制及AOP日誌
- Java 訪問許可權控制(6)Java訪問許可權
- vue-router控制路由許可權Vue路由
- 資料安全之許可權控制
- 淺析Windows的訪問許可權檢查機制Windows訪問許可權
- android 6.0許可權申請機制(簡單案例)Android
- [WCF許可權控制]通過擴充套件自行實現服務授權[提供原始碼下載]套件原始碼
- Oracle的物件許可權、角色許可權、系統許可權Oracle物件
- Linux下ACL許可權控制以及用sudo設定使用者對命令的執行許可權Linux
- 小知識:軟體開發的許可權控制和許可權驗證
- 一對一原始碼,前端頁面許可權和按鈕許可權控制原始碼前端
- MYSQL學習筆記13: DCL許可權控制(使用者許可權操作)MySql筆記
- android強制申請許可權Android