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" >
</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" >
</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 }

测试防盗链:

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 头信息,确定图片的类型,再把文件写入相应类型的文件中。  

时间: 2024-10-18 10:45:20

HTTP 笔记与总结(6)referer 头与防盗链的相关文章

05 referer头与防盗链

像上图中的这个效果,当我们在网页里引用站外图片时,常出现这样的情况. ??? 服务器是怎么样知道,这个图片是在站外被引用的呢? 还有在网站的统计结果,统计用户从何而来,如下图 ??? 统计时,是如何得知用户从哪儿来到的本网站呢? 在Http协议中,头信息里,有一个重要的选项: Referer Referer: 代表网页的来源,即上一页的地址 如果是直接在浏览器上输入地址,回来进来,则没有Referer头. 这也是: 为什么服务器知道我们的图片是从哪儿引用的,也知道我们的客户从哪个网站链接点击过来

请求头和防盗链

getHeader(name)方法 --- String ,获取指定名称的请求头的值 getHeaders(String name)方法 --- Enumeration<String> ,获取指定名称的请求头的值的集合,因为可能出现多个重名的请求头 getHeaderNames方法 --- Enumeration<String> ,获取所有请求头名称组成的集合 getIntHeader(name)方法 --- int ,获取int类型的请求头的值 getDateHeader(nam

[php]referer应用--http防盗链技术

1.防盗链的理解 所谓防盗链是防止其他的网站引用自己网站的资源连接,比如图片.视频等等,但是并不会阻碍从自己网站上享受资源的用户,这就要求能够将其他网站的连接请求阻止 2.防盗链的原理 其实从自己网站使用资源的时候不是由浏览器直接请求资源的,肯定是通过在自己网站上点击,然后从这个页面跳转到资源,无论怎么样,用户是通过自己的网站页面作为中介来访问资源,就类似通过类中定义的方法来访问受保护的变量一样,因此在发向服务器的http请求中就有一个字段为referer用来表明来源于何处,假如是从自己网站发出

php通过判断来源主机头进行防盗链

check.php <html> <body> <form action="test.php" method="post"> message<input type="text" name="name" value="123456" /> <input type="submit" value="submit" /&g

C++学习笔记(一):头文件和源文件

说明: 当一个源文件(a.cpp)要调用另一个源文件(b.cpp)定义的方法时,需要在a.cpp中写上这个方法的声明(只需要该方法的名称.返回值和参数,类似Java的接口): 如果每次调用其他文件的方法时都写上相同的声明就会很麻烦,而且当b.cpp的定义修改时所有调用到该文件的声明都要修改,这样工作量太大且容易出错,所以出现了头文件,我们把所有的声明都存放到头文件中,需要使用到的时候使用宏命令“#include”包含进这个.cpp文件中即可: #include:只有一个功能:把它后面所写的那个文

http请求详解,防盗链技术_韩顺平PHP视频听课笔记

韩顺平PHP视频听课笔记 第84讲 http请求详解,防盗链技术 1,  通过httpwatch插件来抓取http请求内容 2,  http1.0短连接, http1.1长连接 http1.0短连接:每次通信时间很短,效率极低,已被废除. http1.1长连接:通话时间长.只要现在基本都采用http1.1. 只要Connection的状态为keep-alive,就说明是通话状态 3,  http是tcp/ip协议的一个应用层协议,http也是我们web开发的基础. 4,  一个问题:看一个tes

web页面防盗链功能使用--request.getHeader(&quot;Referer&quot;)

使用Request对象设置页面的防盗链 所谓的防盗链就是当你以一个非正常渠道去访问某一个Web资源的时候,服务器会将你的请求忽略并且将你的当前请求变为按正常渠道访问时的请求并返回到相应的页面,用户只有通过该页面中的相关操作去访问想要请求的最终资源. 例如,你有一个访问某资源的网址,但是你事先不知道这个网址是有防盗链的,那么当你输入该网址时你可能会发现,并没有马上跳转到你想要的资源页面而是一些无关的信息页面,但是就是在这些信息页面中你发现有一个超链接或是其他操作可以跳转到你所访问的最终资源页面.

referer htttp headers 统计信息 防盗链

HTTP headers是HTTP请求和相应的核心模块,它承载了关于客户端浏览器.请求页面.服务器等相关信息.Referer是HTTP头中的一个属性,告诉服务器我是从哪个页面链接过来的,所携带的信息用于做统计,也可以用来防盗链.获取方式有两种: 1服务器端获取 Java中获取referer的方法是:request.getHeader("referer") String referer = request.getHeader("referer"); //getServ

Nginx-利用Referer防盗链

面的内容包括:1 Nginx Referer 模块2 valid_referers 指令3 测试Nginx 防盗链 1 Nginx Referer模块当一个请求头的Referer字段中包含一些非正确的字段,这个模块可以禁止这个请求访问站点.这个头可以随意的伪造,因此,使用这个模块并不能100%的阻止这些请求,绝大多数拒绝的请求来自一些典型的浏览器,可以认为这些典型的浏览器并不能提供一个"Referer"头,甚至是那些正确的请求. 2 valid_referers 指令语法:valid_