在百度贴吧(或 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 级别的错误):

 <?php
/*
PHP + socket 编程
@发送 HTTP 请求
@模拟下载
@实现注册、登录、批量发帖
*/ //http 请求类的接口
interface Proto{
//连接 url
function conn($url); //发送 GET 请求
function get(); //发送 POST 请求
function post(); //关闭连接
function close();
} class Http implements Proto{ //换行符
const CRLF = "\r\n"; //fsocket 的错误号与错误描述
protected $errno = -1;
protected $errstr = ''; //响应内容
protected $response = ''; protected $url = null;
protected $version = 'HTTP/1.1';
protected $fh = null; protected $line = array();
protected $header = array();
protected $body = array(); public function __construct($url){
$this->conn($url);
$this->setHeader('Host:' . $this->url['host']);
} //写请求行
protected function setLine($method){
$this->line[0] = $method . ' ' . $this->url['path'] . '?' . $this->url['query'] . ' ' . $this->version;
} //写头信息
public function setHeader($headerline){
$this->header[] = $headerline;
} //写主体信息
protected function setBody($body){
//构造 body 的字符串
$this->body[] = http_build_query($body);
} //连接 url
public function conn($url){
$this->url = parse_url($url);
//判断端口
if(!isset($this->url['port'])){
$this->url['port'] = 80;
}
//判断 query
if(!isset($this->url['query'])){
$this->url['query'] = '';
}
$this->fh = fsockopen($this->url['host'], $this->url['port'], $this->errno, $this->errstr, 3);
} //构造 GET 请求的数据
public function get(){
$this->setLine('GET');
//发送请求
$this->request();
return $this->response;
} //构造 POST 请求的数据
public function post($body = array()){
//构造请求行
$this->setLine('POST'); //设置 Content-type 和 Content-length
$this->setHeader('Content-type: application/x-www-form-urlencoded'); //构造主体信息, 和 GET 请求不一样的地方
$this->setBody($body); $this->setHeader('Content-length: ' . strlen($this->body[0])); //发送请求
$this->request();
return $this->response;
} //发送请求
public function request(){
//把请求行、头信息、主体信息拼接起来
$req = array_merge($this->line, $this->header, array(''), $this->body, array(''));
$req = implode(self::CRLF, $req);
//echo $req;exit; fwrite($this->fh, $req); while(!feof($this->fh)){
$this->response .= fread($this->fh, 1024);
} //关闭连接
$this->close();
} //关闭连接
public function close(){
fclose($this->fh);
}
}

测试防盗链:

caiji.php

 <?php
require './http.class.php'; $http = new Http('http://127.0.0.17/php/http/a.jpg'); $res = $http->get(); //取出 图片二进制码(和 HTTP 头信息中间有一个空行 \r\n,加上空行之前的换行\r\n,一共4个字节)
$res = file_put_contents('./b.jpg', substr(strstr($res, "\r\n\r\n"), 4));
echo 'complete';

运行之后,因为没有 Referer 头信息,因此被认为是盗链,生成的 b.jpg 变成了 “不要盗链”:

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

caiji.php

 <?php
require './http.class.php'; $http = new Http('http://127.0.0.17/php/http/a.jpg');
$http->setHeader('Referer:127.0.0.17');
$res = $http->get(); //取出 图片二进制码(和 HTTP 头信息中间有一个空行 \r\n,加上空行之前的换行\r\n,一共4个字节)
$res = file_put_contents('./b.jpg', substr(strstr($res, "\r\n\r\n"), 4));
echo 'complete';

此时采集到的 b.jpg 绕过了防盗链正常的显示了:

 

待完善:应该判断 response 的 MIME 头信息,确定图片的类型,再把文件写入相应类型的文件中。  

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

  1. http请求之referer头与防盗链

    在网页中的占用大流量的信息可以写成这个信息在网络上的url位置,这样就会减少本网站的流量,但是其他网站也 不会随意让你使用人家的资源,因为这样的情对人家的网站没有好处,会增加人家网站的流量,所以要防止 ...

  2. 05 referer头与防盗链

    像上图中的这个效果,当我们在网页里引用站外图片时,常出现这样的情况. ??? 服务器是怎么样知道,这个图片是在站外被引用的呢? 还有在网站的统计结果,统计用户从何而来,如下图 ??? 统计时,是如何得 ...

  3. javaweb之request获取referer请求头实现防盗链

    package test.request; import java.io.IOException; import javax.servlet.ServletException; import java ...

  4. 通过Referer设置来防盗链

    在Servlet中需要设置防盗链功能时可以通过以下代码: String referer = request.getHeader("Referer"); if(referer == ...

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

    1.防盗链的理解 所谓防盗链是防止其他的网站引用自己网站的资源连接,比如图片.视频等等,但是并不会阻碍从自己网站上享受资源的用户,这就要求能够将其他网站的连接请求阻止 2.防盗链的原理 其实从自己网站 ...

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

    check.php <html> <body> <form action="test.php" method="post"> ...

  7. 利用Referer请求头阻止"盗链"

    转自:http://wisdomsong2007.blog.163.com/blog/static/47783725200882523820664/ 前言 有一些站点自己没有提供下载空间,但是为了吸引 ...

  8. referer htttp headers 统计信息 防盗链

    HTTP headers是HTTP请求和相应的核心模块,它承载了关于客户端浏览器.请求页面.服务器等相关信息.Referer是HTTP头中的一个属性,告诉服务器我是从哪个页面链接过来的,所携带的信息用 ...

  9. 防盗链[referer]

    原文出处:http://www.cnblogs.com/devilfree/archive/2012/09/11/2680914.html 总结一下今天学习防盗链Filter的一些知识点: 防盗链要实 ...

随机推荐

  1. Android之Activity框架

    在安卓应用中,经常需要Activity中经常需要有大量相似的Activity类,这些类往往有相似的结构与功能,因此产生了大量重复代码,为此,以下提供一种方法有效的降低了代码冗余. 定义Activity ...

  2. commons-fileupload实现文件上传下载

    commons-fileupload是Apache提供的一个实现文件上传下载的简单,有效途径,需要commons-io包的支持,本文是一个简单的示例 上传页面,注意设置响应头 <body> ...

  3. 9.装饰者模式(Decorator Pattern)

    using System; namespace ConsoleApplication7 { class Program { static void Main(string[] args) { // 我 ...

  4. Linux 内核中断内幕

    转自:http://www.ibm.com/developerworks/cn/linux/l-cn-linuxkernelint/index.html#resources Linux 内核中断内幕 ...

  5. 在JavaWeb中使用Log4j步骤

    在JavaWeb中使用Log4J指南.每次在开始写一个项目的时候都忘记Log4J如何配置.所以写个步骤,作为记录. 第一步 下载Log4J jar包 从Apache Logging Services ...

  6. java线程安全总结

    转自:http://blog.csdn.net/haolongabc/article/details/7249098 最近想将java基础的一些东西都整理整理,写下来,这是对知识的总结,也是一种乐趣. ...

  7. Struts2文件上传和下载(原理)

    转自:http://zhou568xiao.iteye.com/blog/220732 1.    文件上传的原理:表单元素的enctype属性指定的是表单数据的编码方式,该属性有3个值:1)     ...

  8. Web service project中导入的库JAX-RS(Java EE 6.0新产品)

    JAX-RS是JAVA EE6 引入的一个新技术. JAX-RS即Java API for RESTful Web Services,是一个Java 编程语言的应用程序接口,支持按照表述性状态转移(R ...

  9. HDU 4292 Food 最大流

    Food Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submis ...

  10. 2016.6.17 kali Linux 隧道工具

    隧道工具的基本概念: 1.在计算机网络中,隧道工具是指使用一种网络协议去封装另一种网络协议的技术. 2.通常用来数据伪装或者穿越防火墙,在入侵目标系统后,可用来提升权限和权限维持. Kali中的隧道工 ...