HTTP 筆記與總結(6)referer 頭與防盜鏈


在百度貼吧(或 QQ 空間等)中找到一張圖片,復制圖片地址,在站外通過 img src 引用,會發現:

 

此外,在一些統計軟件中,統計訪客的來路(直接訪問、外部鏈接、搜索引擎),都用到了 HTTP 協議請求頭中 Referer 的知識。

 

 

【例】直接訪問 www.baidu.com 和 在通過本地頁面跳轉至 www.baidu.com,觀察 HTTP 請求頭信息的差異:

① 直接訪問百度,HTTP 請求頭信息:

 

② 通過本地 referer.html 跳轉至 www.baidu.com:

 

HTTP 協議頭信息的 Referer 選項代表網頁的來源(上一頁的地址),如果是直接訪問(直接在瀏覽器輸入地址訪問),則沒有 Referer 選項。

 

 

配置 Apache 服務器用於圖片防盜鏈

原理:在 web 服務器層面,根據 http 協議的 referer 頭信息來判斷網頁來源,如果來自站外,則統一重寫到一個很小的防盜鏈題型圖片上(URL 重寫)。

步驟:

① 打開 apache 重寫模塊 rewrite_mod。重啟 apache。

 

② 在需要防盜鏈的網站或目錄下,寫 .htaccess 文件,並指定防盜鏈規則 —— 分析 referer,如果不是來自本站,則重寫

例如在 127.0.0.17/php/http/ 目錄下新建 .htaccess 文件,寫入重寫規則:

當是 jpg/jpeg/gif/png 圖片 ,且 referer 頭與 127.0.0.17 不匹配時重寫,統一 Rewrite 到某個防盜鏈圖片

重寫方式參見:apache 手冊

D:\practise\php\http\.htaccess:

RewriteEngine On
RewriteCond %{REQUEST_FILENAME} .*\.(jpg|jpeg|gif|png) [NC]
RewriteCond %{HTTP_REFERER} !127.0.0.17 [NC]
RewriteRule .* http://127.0.0.17/php/logo.jpg

第 1 行:開啟重寫功能;

第 2 行:當請求的文件名以 .jpg,.jpeg,.gif,.png 結尾時

第 3 行:當 HTTP 的 Referer 頭 與 服務器地址 127.0.0.17 不匹配時

第 4 行:重寫規則,把符合條件的文件重寫到 http://127.0.0.17/php/http/logo.jpg 上

 

實例:

D:\practise\php\logo.jpg:

 

D:\practise\php\http\a.jpg:

 

站內地址(127.0.0.17,D:\practise),站外地址(127.0.0.16,D:\practise\php)。也就是說,127.0.0.16 上的文件外鏈 127.0.0.17 上的 a.jpg 時,會被重寫至 logo.jpg。

http://127.0.0.17/php/http/referer.html:

<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<title>Document</title>
</head>
<body>
	<img src="./a.jpg" alt="">
</body>
</html>

輸出:

  

 

http://127.0.0.16/http/referer.html:

<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<title>Document</title>
</head>
<body>
	<img src="./http/a.jpg" alt="">
</body>
</html>

輸出:

 

防盜鏈功能實現。

 

如果把 .htaccess 放在根目錄,則網站所有的圖片都會受到影響;如果只要對某個目錄生效,則在 .htaccess 中加上:

Rewrite Base /php/http

 

 

采集圖片功能(通過設置 Referer 頭信息,繞過防盜鏈)

先測試通過 HTTP GET 請求圖片

caiji.php:

<?php
require './http.class.php';

$http = new Http('http://127.0.0.17/php/http/a.jpg');

echo $res = $http->get();

輸出:

  

 

修改 http.class.php line:72(增加判斷 $url['query'],防止出現 Notice 級別的錯誤):

  1 <?php
  2 /*
  3     PHP + socket 編程
  4     @發送 HTTP 請求
  5     @模擬下載
  6     @實現注冊、登錄、批量發帖
  7 */
  8 
  9 //http 請求類的接口
 10 interface Proto{
 11     //連接 url 
 12     function conn($url);
 13 
 14     //發送 GET 請求
 15     function get();
 16 
 17     //發送 POST 請求
 18     function post();
 19 
 20     //關閉連接
 21     function close();
 22 }
 23 
 24 class Http implements Proto{
 25 
 26     //換行符
 27     const CRLF = "\r\n";
 28 
 29     //fsocket 的錯誤號與錯誤描述
 30     protected $errno = -1;
 31     protected $errstr = '';
 32 
 33     //響應內容
 34     protected $response = '';
 35 
 36     protected $url = null;
 37     protected $version = 'HTTP/1.1';
 38     protected $fh = null;
 39 
 40     protected $line = array();
 41     protected $header = array();
 42     protected $body = array();
 43 
 44     public function __construct($url){
 45         $this->conn($url);
 46         $this->setHeader('Host:' . $this->url['host']);
 47     }
 48 
 49     //寫請求行
 50     protected function setLine($method){
 51         $this->line[0] = $method . ' ' . $this->url['path'] . '?' . $this->url['query'] . '  ' . $this->version;
 52     }
 53 
 54     //寫頭信息
 55     public function setHeader($headerline){
 56         $this->header[] = $headerline;
 57     } 
 58 
 59     //寫主體信息
 60     protected function setBody($body){
 61         //構造 body 的字符串
 62         $this->body[] = http_build_query($body);
 63     }
 64 
 65     //連接 url 
 66     public function conn($url){
 67         $this->url = parse_url($url);
 68         //判斷端口
 69         if(!isset($this->url['port'])){
 70             $this->url['port'] = 80;
 71         }
 72         //判斷 query
 73         if(!isset($this->url['query'])){
 74             $this->url['query'] = '';
 75         }        
 76         $this->fh = fsockopen($this->url['host'], $this->url['port'], $this->errno, $this->errstr, 3);
 77     }
 78 
 79     //構造 GET 請求的數據
 80     public function get(){
 81         $this->setLine('GET');
 82         //發送請求
 83         $this->request();
 84         return $this->response;
 85     }
 86 
 87     //構造 POST 請求的數據
 88     public function post($body = array()){
 89         //構造請求行
 90         $this->setLine('POST');
 91 
 92         //設置 Content-type 和 Content-length
 93         $this->setHeader('Content-type: application/x-www-form-urlencoded');
 94         
 95         //構造主體信息, 和 GET 請求不一樣的地方
 96         $this->setBody($body);
 97         
 98         $this->setHeader('Content-length: ' . strlen($this->body[0]));
 99 
100         //發送請求
101         $this->request();
102         return $this->response;        
103     }
104 
105     //發送請求
106     public function request(){
107         //把請求行、頭信息、主體信息拼接起來
108         $req = array_merge($this->line, $this->header, array(''), $this->body, array(''));
109         $req = implode(self::CRLF, $req);
110         //echo $req;exit;
111 
112         fwrite($this->fh, $req);
113 
114         while(!feof($this->fh)){
115             $this->response .= fread($this->fh, 1024);
116         }
117 
118         //關閉連接
119         $this->close();
120     }
121 
122     //關閉連接
123     public function close(){
124         fclose($this->fh);
125     }
126 }
View Code

 

測試防盜鏈:

caiji.php

 1 <?php
 2 require './http.class.php';
 3 
 4 $http = new Http('http://127.0.0.17/php/http/a.jpg');
 5 
 6 $res = $http->get();
 7 
 8 //取出 圖片二進制碼(和 HTTP 頭信息中間有一個空行 \r\n,加上空行之前的換行\r\n,一共4個字節)
 9 $res = file_put_contents('./b.jpg', substr(strstr($res, "\r\n\r\n"), 4)); 10 echo 'complete';

運行之后,因為沒有 Referer 頭信息,因此被認為是盜鏈,生成的 b.jpg 變成了 “不要盜鏈”:

 

 

在 caiji.php 中加入 Referer 頭信息后:

caiji.php

 1 <?php
 2 require './http.class.php';
 3 
 4 $http = new Http('http://127.0.0.17/php/http/a.jpg');
 5 $http->setHeader('Referer:127.0.0.17');
 6 $res = $http->get();
 7 
 8 //取出 圖片二進制碼(和 HTTP 頭信息中間有一個空行 \r\n,加上空行之前的換行\r\n,一共4個字節)
 9 $res = file_put_contents('./b.jpg', substr(strstr($res, "\r\n\r\n"), 4)); 10 echo 'complete';

 

此時采集到的 b.jpg 繞過了防盜鏈正常的顯示了:

 

 

待完善:應該判斷 response 的 MIME 頭信息,確定圖片的類型,再把文件寫入相應類型的文件中。  

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM