日常運維工作中,設定防盜鏈的需求會經常碰到,這也是優化網站的一個必要措施。今天在此介紹Nginx中設定下載防盜鏈和圖片防盜鏈的操作~
一、Nginx中下載防盜鏈的操作記錄
對於一些站點上的下載操作,有很多的下載來源不是本站,是迅雷、flashget, 源源不斷的頻寬,防盜鏈絕對是當務之急!使用來源判斷根本不靠譜,只能防止一些小白站點的盜鏈,迅雷之類的下載工具完全無效;
如果是nginx配置的站點,可以使用secure link來完美解決這個問題,遠離迅雷.
以下Nginx的盜鏈配置,僅用於下載伺服器的下載防盜鏈,不適用於圖片防盜鏈:
1)nginx的配置
[root@test-huanqiu ~]# cat /usr/local/nginx/conf/vhost/down.conf
server { listen 80; server_name x1.down.wangshibo.com; access_log /data/logs/nginx/x1.down.wangshibo.com.access.log main; index index.html index.php index.html; root /data/site/x1.down.wangshibo.com; location / { secure_link $arg_st,$arg_e; secure_link_md5 wangshibo.com$uri$arg_e; if ($secure_link = "") { return 403; } if ($secure_link = "0") { return 403; } } }
2)php下載頁面
[root@test-huanqiu ~]# cd /data/site/x1.down.wangshibo.com
[root@test-huanqiu x1.down.wangshibo.com]# cat down.php
<?php
# 作用:生成nginx secure link連結
# 站點:www.wangshibo.com
$secret = 'wangshibo.com'; # 金鑰
$path = '/web/nginx-1.4.2.tar.gz'; # 下載檔案
# 下載到期時間,time是當前時間,300表示300秒,也就是說從現在到300秒之內檔案不過期
$expire = time()+300;
# 用檔案路徑、金鑰、過期時間生成加密串
$md5 = base64_encode(md5($secret . $path . $expire, true));
$md5 = strtr($md5, '+/', '-_');
$md5 = str_replace('=', '', $md5);
# 加密後的下載地址
echo '<a href=http://x1.down.wangshibo.com/web/nginx-1.4.2.tar.gz?st='.$md5.'&e='.$expire.'>nginx-1.4.2</a>';
echo '<br>http://x1.down.wangshibo.com/web/nginx-1.4.2.tar.gz?st='.$md5.'&e='.$expire;
?>
3)測試nginx防盜鏈
瀏覽器上開啟http://test.wangshibo.com/down.php點選上面的連線下載
下載地址如下:
http://x1.down.wangshibo.com/web/nginx-1.4.2.tar.gz?st=LSVzmZllg68AJaBmeK3E8Q&e=1378881984
頁面不要重新整理,等到5分鐘後在下載一次,你會發現點選下載會跳轉到403頁面。
4)secure link 防盜鏈過程
1.使用者訪問down.php
2.down.php根據secret金鑰、過期時間、檔案uri生成加密串
3.將加密串與過期時間作為引數跟到檔案下載地址的後面
4.nginx下載伺服器接收到了過期時間,也使用過期時間、配置裡金鑰、檔案uri生成加密串
5.將使用者傳進來的加密串與自己生成的加密串進行對比,一致允許下載,不一致403
整個過程實際上很簡單,類似於使用者密碼驗證. 尤為注意的一點是一定不要洩露了自己的金鑰,否則別人就可以盜鏈了,除了洩露之外最好能經常更新金鑰.
5)secure link 指令
1.secure_link
語法: secure_link md5_hash[,expiration_time]
預設: none
配置段: location
variables: yes
這個指令由uri中的MD5雜湊值和過期時間組成. md5雜湊必須由base64加密的,過期時間為unix時間.如果不加過期時間,那麼這個連線永遠都不會過期.
2.secure_link_md5
語法: secure_link_md5 secret_token_concatenated_with_protected_uri
預設: none
配置段: location
variables: yes
md5值對比結果,使用上面提供的uri、金鑰、過期時間生成md5雜湊值.如果它生成的md5雜湊值與使用者提交過來的雜湊值一致,那麼這個變數的值為1,否則為0
3.secure_link_secret
語法: secure_link_secret word
預設:
配置段: location
Reference: secure_link_secret
nginx 0.8.50之後的版本已經使用secure_link_md5取代,不在多說.
注意事項
1.金鑰防止洩露、以及經常更新金鑰
2.下載伺服器和php伺服器的時間不能相差太大,否則容易出現檔案一直都是過期狀態.
secure link以及內建到了nginx,不需要額外安裝第三方模組,有下載伺服器的情況,極力推薦使用它,除非你不在乎你的頻寬.
6)珍愛頻寬,遠離迅雷
還可以配置nginx,讓nginx防止迅雷、快車的多執行緒下載:
作用域: server location
if ($http_range)
{
return 405;
}
這樣給使用者端的第二個執行緒返回405,只讓nginx單執行緒給使用者吐資料。
二、Nginx中圖片防盜鏈的操作記錄
圖片防盜鏈和下載防盜鏈使用的指令不同,下載防盜鏈使用secure link,並且需要程式配合,但是效果非常好;而圖片防盜鏈不需要程式配合,根據圖片來源來實現,但是隻能先限制基本的圖片盜用,無法防止圖片採集.
nginx referer指令簡介
nginx模組ngx_http_referer_module通常用於阻擋來源非法的域名請求.我們應該牢記,偽裝Referer頭部是非常簡單的事情,所以這個模組只能用於阻止大部分非法請求.我們應該記住,有些合法的請求是不會帶referer來源頭部的,所以有時候不要拒絕來源頭部(referer)為空的請求.
nginx防盜鏈指令
1)語法: referer_hash_bucket_size size;
預設值: referer_hash_bucket_size 64;
配置段: server, location
這個指令在nginx 1.0.5中開始出現.
2)語法: referer_hash_max_size size;
預設值: referer_hash_max_size 2048;
配置段: server, location
這個指令在nginx 1.0.5中開始出現.
3)語法: valid_referers none | blocked | server_names | string ...;
預設值: —
配置段: server, location
指定合法的來源'referer', 它決定了內建變數$invalid_referer的值,如果referer頭部包含在這個合法網址裡面,這個變數被設定為0,否則設定為1.記住,不區分大小寫的.
引數說明
none:“Referer” 來源頭部為空的情況,即表示空的來路,也就是直接訪問,比如直接在瀏覽器開啟一個圖片
blocked:“Referer”來源頭部不為空,但是裡面的值被代理或者防火牆刪除了,這些值都不以http://或者https://開頭.即表示被防火牆標記過的來路
server_names:“Referer”來源頭部包含當前的server_names(當前域名)
string:任意字串,定義伺服器名或者可選的URI字首.主機名可以使用*開頭或者結尾,在檢測來源頭部這個過程中,來源域名中的主機埠將會被忽略掉
regular expression:正規表示式,~表示排除https://或http://開頭的字串.
注意:
圖片使用來源頭部做防盜鏈是最合理的. 簡單、實用。但是沒有辦法防採集。
圖片防盜鏈的配置有三種方法,下面一一介紹:
1)針對不同檔案型別的防盜鏈:
配置示例1:
location ~* \.(gif|jpg|png|bmp)$ {
valid_referers none blocked *.wangshibo.com server_names ~\.google\. ~\.baidu\.;
if ($invalid_referer) {
return 403;
#rewrite ^/ http://www.wangshibo.com/403.jpg;
}
}
配置說明:
以上所有來至wangshibo.com和域名中包含google和baidu的站點都可以訪問到當前站點的圖片
如果來源域名不在這個列表中,那麼$invalid_referer等於1,在if語句中返回一個403給使用者,這樣使用者便會看到一個403的頁面;
如果使用下面的rewrite,那麼盜鏈的圖片都會顯示403.jpg;
如果使用者直接在瀏覽器輸入你的圖片地址,那麼圖片顯示正常,因為它符合none這個規則.
配置示例2:
location ~ .*\.(wma|wmv|asf|mp3|mmf|zip|rar|jpg|gif|png|swf|flv)$ {
valid_referers none blocked *.wangshibo.com wangshibo.com;
if($invalid_referer){
#rewrite ^/ http://www.765h.com/error.html;
return 403;
}
}
配置說明:
第一行:表示對wma|wmv|asf|mp3|mmf|zip|rar|jpg|gif|png|swf|flv字尾的檔案實行防盜鏈
第二行:表示對*.wangshibo.com和wangshibo.com這2個來路進行判斷(*代表任何,任何的二級域名),可以新增更多
if{}裡面內容的意思是,如果來路不是指定來路就跳轉到403錯誤頁面,當然直接返回404也是可以的,也可以是圖片。
一般常用的圖片防盜鏈的方法是在server或者location段中加入:
valid_referers none blocked www.wangshibo.com wangshibo.com;
如上面的兩個小示例能起到一定的圖片防盜鏈功能,但其實並不是真正的徹底的防盜鏈設定。
一般來說:
做好防盜鏈之後,其他網站盜鏈的本站圖片就會全部失效無法顯示,但是如果通過瀏覽器直接輸入圖片地址,仍然會顯示圖片,仍然可以右鍵圖片另存為下載檔案!
依然可以下載?這樣就不是徹底的防盜了!那麼,nginx應該怎麼樣徹底地實現真正意義上的防盜鏈呢?
首先,來看下nginx如何設定防盜鏈?
修改 /usr/local/nginx/conf/nginx.conf 這個配置檔案:
預設圖片是有過期時間設定的
[root@bastion-IDC ~]# vim /usr/local/nginx/conf/nginx.conf
location ~ .*\.(gif|jpg|jpeg|png|bmp|swf)$ {
expires 30d;
}
把上面的配置修改成:
[root@bastion-IDC ~]# vim /usr/local/nginx/conf/nginx.conf
location ~ .*\.(gif|jpg|jpeg|png|bmp|swf)$ {
valid_referers none blocked *.wangshibo.com wangshibo.com;
if($invalid_referer) {
rewrite ^/ http://www.wangshibo.com/404.jpg;
#return404;
}
expires 30d;
}
配置解說:
第一行:location ~ .*\.(gif|jpg|jpeg|png|bmp|swf)$
其中“gif|jpg|jpeg|png|bmp|swf”設定防盜鏈檔案型別,自行修改,每個字尾用“|”符號分開!
第二行:valid_referers none blocked *.wangshibo.com wangshibo.com;
就是白名單,允許檔案鏈出的域名白名單,自行修改成您的域名!*.wangshibo.com這個指的是子域名,域名與域名之間使用空格隔開!
第四行:rewrite ^/ http://www.wangshibo.com/404.jpg;
這個圖片是盜鏈返回的圖片,也就是替換盜鏈網站所有盜鏈的圖片。這個圖片要放在沒有設定防盜鏈的網站上,因為防盜鏈的作用,這個圖片如果也放在防盜鏈網站上就會被當作防盜鏈顯示不出來了,盜鏈者的網站所盜鏈圖片會顯示X符號。
這樣設定差不多就可以起到防盜鏈作用了,但是這樣並不是徹底地實現真正意義上的防盜鏈!
我們來看第二行:valid_referers none blocked *.wangshibo.com wangshibo.com;
valid_referers 裡多了“none blocked”
我們把“none blocked”刪掉,改成:
valid_referers *.wangshibo.com wangshibo.com;
所以說:
nginx徹底地實現真正意義上的防盜鏈完整的程式碼應該是這樣的:
1.去掉valid_referers 後面的none blocked
2.防盜鏈和expires圖片過期時間設定整合到一起。其實就是保證server段中只有一個類似location ~ .*\.(gif|jpg|jpeg|png|bmp|swf)$的配置
完整配置如下:
location ~ .*\.(gif|jpg|jpeg|png|bmp|swf)$ { valid_referers *.wangshibo.com wangshibo.com; if($invalid_referer) { rewrite ^/ http://www.wangshibo.com/404.jpg; #return404; } expires 30d; }
這樣您在瀏覽器直接輸入圖片地址就不會再顯示圖片出來了,也不可能會再右鍵另存什麼的。
第四行:
rewrite ^/ http://www.wangshibo.com/404.jpg;
這個是給圖片防盜鏈設定的防盜鏈返回圖片
如果我們是檔案需要防盜鏈下載,把第四行改成一個連結,比如可以改成是主站的連結
rewrite ^/ http://www.wangshibo.com;
這樣,當別人輸入檔案下載地址,由於防盜鏈下載的作用就會跳轉到您設定的這個連結!
最後,配置檔案設定完成別忘記重啟nginx生效!
再看一例:
比如現在google首頁點選廣告www.abc.com跳轉到www.baidu.com,但是直接在瀏覽器輸入www.abc.com,還是www.abc.com
配置如下:
valid_referers none blocked localhost *.abc.com abc.com;
if ($invalid_referer){
rewrite ^/(.*) http://www.baidu.com/? permanent;
break;
}
------------------------------------------------------------------------------------------------------------------------------
實驗說明:
[root@test-huanqiu ~]# vim /usr/local/nginx/conf/vhosts/image.conf
server { listen 80 ; server_name 192.168.1.14 web01.wangshibo.cn; root /var/www/html; index index.html index.php index.htm; location ~* \.(gif|jpg|png|swf|flv)$ { valid_referers none blocked *.wangshibo.cn; if ($invalid_referer) { rewrite ^/ http://www.heihei.com/404.jpg; #return 404; } expires 30d; } location ~ .*\.(php|php5)?$ { #fastcgi_pass unix:/tmp/php-cgi.sock; fastcgi_pass 127.0.0.1:9000; fastcgi_index index.php; include fastcgi.conf; } access_log /usr/local/nginx/logs/image.log; }
注意第8行 "valid_referers none blocked"
其中"none" "blocked" 的意思分別是:
none代表沒有referer;
blocded代表有referer但是被防火牆或者是代理給去除了。
以上配置後,訪問的跳轉流程:
1)首先當輸入要開啟的網址的時候,因為是直接輸入的沒有referer,所以匹配了valid_referers後面的none或者是blocked,invalid_referer值為0,因此不進行跳轉.
2)當是從這個網站裡面的連結跳到該網站首頁的時候,因為referer的值是肯定包含srever_names,所以匹配了server_names,因此不進行跳轉;
3)當從搜素引擎進去的時候因為referer欄位類似於www.google.com.hk/search,開始進行匹配,發現沒有一個匹配,則此時會設定invalid_referer值為1,if語句成功執行,進行了跳轉. 達到功能!
[root@test-huanqiu ~]# /usr/local/nginx/sbin/nginx -t
nginx: the configuration file /usr/local/nginx/conf/nginx.conf syntax is ok
nginx: configuration file /usr/local/nginx/conf/nginx.conf test is successful
[root@test-huanqiu ~]# /usr/local/nginx/sbin/nginx -s reload
只有把這兩個none,blocked去掉,才可以真正的實現防盜連!因為只有匹配到server_name的時候,才不會進行跳轉。如下說明:
[root@master-node html]# ll /var/www/html/
total 16
-rw-r--r-- 1 www www 143 Dec 14 11:34 index.html
-rw-r--r-- 1 www www 10571 Dec 14 11:35 long.jpg
[root@master-node html]# cat /var/www/html/index.html
<html> <body> <h1>"王士博",welcome to beijing!! </h1> <img alt="long.jpg" src="/long.jpg" height="auto" width="auto"></img> </body> </html>
訪問,看看效果:
接真輸入圖片地址可以顯示圖片:
現在將none,blocked去掉,看看效果:
[root@test-huanqiu ~]# vim /usr/local/nginx/conf/vhosts/image.conf
server { listen 80 ; server_name 192.168.1.14 web01.wangshibo.cn; root /var/www/html; index index.html index.php index.htm; location ~* \.(gif|jpg|png|swf|flv)$ { valid_referers *.wangshibo.cn; if ($invalid_referer) { rewrite ^/ http://www.heihei.com/404.jpg; #return 404; } expires 30d; } location ~ .*\.(php|php5)?$ { #fastcgi_pass unix:/tmp/php-cgi.sock; fastcgi_pass 127.0.0.1:9000; fastcgi_index index.php; include fastcgi.conf; } access_log /usr/local/nginx/logs/image.log; }
[root@test-huanqiu ~]# /usr/local/nginx/sbin/nginx -t
nginx: the configuration file /usr/local/nginx/conf/nginx.conf syntax is ok
nginx: configuration file /usr/local/nginx/conf/nginx.conf test is successful
[root@test-huanqiu ~]# /usr/local/nginx/sbin/nginx -s reload
再次訪問
當再次訪問http://web01.wangshibo.cn/long.jpg時就會跳轉到http://www.heihei.com/404.jpg(測試時,記得刪除瀏覽器快取。nginx中有圖片快取配置)
這樣就實現了完美的防盜鏈!!
另外注意:
1)請確保server段中只有一個location ~ .*\.(gif|jpg|jpeg|png|bmp|swf)$(比如還有另外的一個針對expires過期時間的這樣的location配置,那麼必須要將其和防盜鏈的location整合到一起),否則可能導致程式碼無效,如有這個程式碼段請合併或刪除。
2)切記:如果要跳轉到圖片,記得替換的圖片地址要使用沒有防盜鏈的網站圖片,否則由於替換的圖片其實也處於防盜鏈情況下,會造成仍舊無法顯示設定的圖片。
------------------------------------------------------------------------------------------------------------------------------
2)針對目錄的防盜鏈:( 這是nginx自帶的防盜鏈功能。)
location /img/ {
root /data/img/;
valid_referers none blocked *.wangshibo.com wangshibo.com;
if($invalid_referer){
rewrite ^/ http://www.wangshibo.com/images/error.gif;
#return 403;
}
}
location /images/ {
alias /data/images/;
valid_referers none blocked server_names *.wangshibo.com wangshibo.com ;
if ($invalid_referer) {
return 403;
}
}
3)使用第三方模組ngx_http_accesskey_module實現的防盜鏈:
1.下載Nginx和nginx-http-access模組
http://nginx.org/download/nginx-1.8.0.tar.gz
http://wiki.nginx.org/File:Nginx-accesskey-2.0.3.tar.gz
2.安裝
[root@test-huanqiu ~]# tar -zxvf nginx-1.8.0.tar.gz
[root@test-huanqiu ~]# cd nginx-1.8.0/
[root@test-huanqiu ~]# tar -xvfz nginx-accesskey-2.0.3.tar.gz
[root@test-huanqiu ~]# cd nginx-accesskey-2.0.3
[root@test-huanqiu nginx-accesskey-2.0.3]# vim config
#替換其中的”$HTTP_ACCESSKEY_MODULE”為”ngx_http_accesskey_module” (這是此模組的一個bug)
接著編譯安裝nginx
[root@test-huanqiu nginx-1.8.0]# ./configure --user=www --group=www --prefix=/usr/local/nginx --with-http_stub_status_module --with-http_ssl_module --add-module=/root/nginx-accesskey-2.0.3
配置nginx:
location /download {
accesskey on;
accesskey_hashmethod md5;
accesskey_arg "key";
accesskey_signature "mypass$remote_addr";
}
配置說明:
accesskey為模組開關;
accesskey_hashmethod為加密方式MD5或者SHA-1;
accesskey_arg為url中的關鍵字引數;
accesskey_signature為加密值,此處為mypass和訪問IP構成的字串。
編寫測試指令碼download.php:
<?
$ipkey= md5("mypass".$_SERVER['REMOTE_ADDR']);
$output_add_key="<a href=http://www.wangshibo.com/download/G3200507120520LM.rar?key=".$ipkey.">download_add_key</a><br />";
$output_org_url="<a href=http://www.wangshibo.com/download/G3200507120520LM.rar>download_org_path</a><br />";
echo $output_add_key;
echo $output_org_url;
?>
如上配置後:
訪問第一個download_add_key連結可以正常下載,第二個連結download_org_path會返回403 Forbidden錯誤。
如果不怕麻煩,有條件實現的話,推薦使用第三方模組ngx_http_accesskey_module實現的防盜鏈。
它的執行方式是:
比如download目錄下有一個 file.zip 的檔案。對應的URI 是http://www.wangshibo.com/download/file.zip
使用ngx_http_accesskey_module模組後http://www.wangshibo.com/download/file.zip?key=09093abeac094. 只有給定的key值正確了,才能夠下載download目錄下的file.zip。而且 key 值是根據使用者的IP有關的,這樣就可以避免被盜鏈了。
據說Nginx HttpAccessKeyModule現在連迅雷都可以防了,可以嘗試一下。
--------------------------------------------------------------------------------------------圖片訪問地址操作記錄------------------------------------------------------------------------------
1)需求:配置一個圖片上傳下載的需求,及在nginx裡配置一個url,用於圖片上傳和下載。 直接配置本機的nginx # vim vhosts/images.conf server { listen 80; server_name images.wang.com; index index.html index.php index.htm; server_tokens off; access_log logs/ehr_access.log; error_log logs/ehr_error.log; location ~ .*\.(gif|jpg|jpeg|png|bmp|swf)$ { expires 7d; //過期時間 root /data/nginx/images/; proxy_store on; proxy_store_access user:rw group:rw all:rw; proxy_temp_path /data/nginx/images/; //存放圖片的目錄 proxy_redirect off; proxy_set_header Host 127.0.0.1; client_max_body_size 100m; //圖片上傳的大小限制 client_body_buffer_size 256k; proxy_connect_timeout 900; proxy_send_timeout 900; proxy_read_timeout 900; proxy_buffer_size 40k; proxy_buffers 40 320k; proxy_busy_buffers_size 640k; proxy_temp_file_write_size 640k; } location ~ .*\.(js|css)?$ { expires 12h; } } 這樣: 圖片上傳和下載的url為:http://images.wang.com, 圖片存放的目錄為/data/nginx/images/ 2)需求:在tomcat裡部署一個用於圖片上傳和下載的目錄,然後在nginx裡配置圖片訪問的url。 先配置本機的tomcat # cat /data/tomcat7/conf/server.xml ....... <Host ..... ..... <Context path="/file" docBase="/data/tomcat7/ehrbak" debug="0" reloadable="true"/> //這一行寫在<Host </Host>之間 </Host> # mkdir /data/tomcat7/ehrbak 接著配置本機的nginx # cat /data/nginx/conf/vhosts/ehr.conf server { listen 80; server_name images.wang.com; index index.html index.php index.htm; server_tokens off; access_log logs/ehr_access.log; error_log logs/ehr_error.log; location ~ .*\.(gif|jpg|jpeg|png|bmp|swf)$ { expires 7d; root /data/tomcat7/ehrbak/; proxy_store on; proxy_store_access user:rw group:rw all:rw; proxy_temp_path /data/tomcat7/ehrbak/; proxy_redirect off; proxy_set_header Host 127.0.0.1; client_max_body_size 100m; client_body_buffer_size 256k; proxy_connect_timeout 900; proxy_send_timeout 900; proxy_read_timeout 900; proxy_buffer_size 40k; proxy_buffers 40 320k; proxy_busy_buffers_size 640k; proxy_temp_file_write_size 640k; } location ~ .*\.(js|css)?$ { expires 12h; } } 然後在前面的nginx代理層(即另一臺機器上) [root@BJLX_4_21_P vhosts]# cat ssl-ehr.conf upstream ehr { server 172.29.34.27:8080 max_fails=3 fail_timeout=30s; } upstream download { server 172.29.34.27:80 max_fails=3 fail_timeout=30s; } server { listen 443; server_name images.wang.com; ssl on; server_tokens off; ### SSL log files ### access_log logs/ehr_access.log; error_log logs/ehr_error.log; ### SSL cert files ### ssl_certificate ssl/wang.cer; ssl_certificate_key ssl/wang.key; #ssl_session_timeout 5m; location /file/ { proxy_pass http://download/; proxy_next_upstream error timeout invalid_header http_500 http_502 http_503; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto https; proxy_redirect off; } } 這樣: 圖片訪問的url是:https://images.wang.com/file/*** 圖片存放的路徑是本機的/data/tomcat7/ehrbak/ 比如有一張圖片路徑為/data/tomcat7/ehrbak/upload/201707/051622309x32.jpg 那麼這張圖片的訪問地址是:https://images.wang.com/file/upload/201707/051622309x32.jpg