HTTP之Referrer和Referrer-policy

这篇具有很好参考价值的文章主要介绍了HTTP之Referrer和Referrer-policy。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

目录

HTTP之Referrer和Referrer-policy   

Referer

Referrer-policy

如何设置referrer

盗链

防盗链的工作原理

绕过图片防盗链

利用https网站盗链http资源网站,refer不会发送

设置meta

设置referrerpolicy="no-referrer"

利用iframe伪造请求referer

客户端在请求时修改header头部

利用XMLHttpRequest

利用fetch

服务器作防盗链图片中转

常见防盗链方法

利用nginx

服务器端判断referer

防止网址被 iframe


HTTP之Referrer和Referrer-policy   

Referer

        定义 --- 当一个用户点击当前页面中的一个链接,然后跳转到目标页面时,目标页面会收到一个信息,即用户是从哪个源链接跳转过来的。

        包含 --- 当前请求页面的来源页面的地址,即表示当前页面是通过此来源页面里的链接进入的

        作用 --- 识别访问来源,可能会以此统计分析、日志记录以及缓存优化等。

HTTP之Referrer和Referrer-policy

注意:

        Referer请求头可能会暴露用户的浏览历史、涉及到用户的隐私问题。

Referrer-policy

        作用 --- 为了控制请求头中referer的内容

        包含 --- 

                no-referrer --- 整个referee首部会被移除,访问来源信息不随着请求一起发送。

                no-referrer-when-downgrade --- 在没有指定任何策略的情况下用户代理的默认行为。在同等安全级别的情况下,引用页面的地址会被发送(HTTPS->HTTPS),但是在降级的情况下不会被发送 (HTTPS->HTTP).

                origin --- 在任何情况下,仅发送文件的源作为引用地址。例如 https://example.com/page.html 会将 Example Domain 作为引用地址。

                origin-when-cross-origin ---  对于同源的请求,会发送完整的URL作为引用地址,但是对于非同源请求仅发送文件的源。

                same-origin --- 对于同源的请求会发送引用地址,但是对于非同源请求则不发送引用地址信息。

                strict-origin ---  在同等安全级别的情况下,发送文件的源作为引用地址(HTTPS->HTTPS),但是在降级的情况下不会发送 (HTTPS->HTTP)。

                strict-origin-when-cross-origin --- 对于同源的请求,会发送完整的URL作为引用地址;在同等安全级别的情况下,发送文件的源作为引用地址(HTTPS->HTTPS);在降级的情况下不发送此首部 (HTTPS->HTTP)。

                unsafe-url ---  无论是同源请求还是非同源请求,都发送完整的 URL(移除参数信息之后)作为引用地址。(最不安全了)

        浏览器兼容性(https://caniuse.com/?search=referer-policy):

HTTP之Referrer和Referrer-policy

如何设置referrer

1. 在HTML里设置meta 

<meta name="referrer" content="origin">

        如下图:  

 HTTP之Referrer和Referrer-policy

2. 或者用<a>、<area>、<img>、<iframe>、<script> 或者 <link> 元素上的 referrerpolicy 属性为其设置独立的请求策略。

<script src='/javascripts/test.js' referrerpolicy="no-referrer"></script>

HTTP之Referrer和Referrer-policy

 HTTP之Referrer和Referrer-policy

         未加referrerpolicy属性的link元素:

HTTP之Referrer和Referrer-policy

盗链

        定义 --- 指在自己的页面上展示一些并不在自己服务器上的一些内容, 获取别人的资源地址,绕过别人的资源展示页面,直接在自己的页面上向最终用户提供此内容。 一般被盗链的都是图片、可执行文件、音视频文件、压缩文件等资源。通过盗链的手段可以减轻自己服务器的负担

         比如在自己页面里引入百度贴吧里的一张照片:

<body>
    <img src="https://tiebapic.baidu.com/forum/w%3D580%3B/sign=f88eb0f2cf82b9013dadc33b43b6ab77/562c11dfa9ec8a135455cc35b203918fa1ecc09c.jpg"> 
</body>

         但实际上是无法展示的(如下图),之所以无法展示是因为百度的图片做过防盗链处理

HTTP之Referrer和Referrer-policy

防盗链的工作原理

        通过Referrer或者签名,网站可以检测目标网页访问的来源网页,如果是资源文件,则可以追踪到显示它的网页地址 一旦检测到来源不是本站,即进行阻止或者返回指定的页面

绕过图片防盗链

        那么现在的很多网站是如何利用referrer来进行防图片盗链的呢?

        三种情况下允许引用图片:

               1. 本网站。

                2.无referer信息的情况。(服务器认为是从浏览器直接访问的图片URL,

                   所以这种情况下能正常访问)

                3.授权的网址。

我们只能从情况2入手,通过设置referrer为空进行绕过防盗链。

利用https网站盗链http资源网站,refer不会发送

        先利用openssl生成自签名证书(具体可看Blog/HTTP相关/Demos/referer/demo03 at main · zxl925768661/Blog · GitHub) client.js

let https = require("https");
let fs = require("fs");
let url = require("url");
let path = require("path");
​
​
var options = {
  hostname: "localhost",
  port: 8000,
  path: "/",
  method: "GET",
  rejectUnauthorized: false,
  key: fs.readFileSync("./keys/client.key"),
  cert: fs.readFileSync("./keys/client.crt"),
  ca: [fs.readFileSync("../ca/ca.crt")],
};
​
// 创建服务器
https.createServer(options, function (req, res) {
​
  let staticPath = path.join(__dirname, "src");
  let pathObj = url.parse(req.url, true);
​
  if (pathObj.pathname === "/") {
    pathObj.pathname += "index.html";
  }
  //  读取静态目录里面的文件,然后发送出去
  let filePath = path.join(staticPath, pathObj.pathname);
  fs.readFile(filePath, "binary", function (err, content) {
    if (err) {
      res.writeHead(404, "Not Found");
      res.end("<h1>404 Not Found</h1>");
    } else {
      res.writeHead(200, "Not Found");
      res.write(content, "binary");
      res.end();
    }
  });
​
}).listen(8080);
​

        index.html

<div id="container">
    <img src="http://localhost:9999">
</div>

        启动结果如下: 提示: 由于我们使用了自签名的证书,访问页面时可能会看到浏览器的证书警告,可能需要手动点击信任当前证书,或者手动点击链接确认访问该页面。例如Chrome 提醒“您的连接不是私密连接”,并禁止你访问。你可以直接在当前页面输入 thisisunsafe,不是在地址栏输入,而是直接敲击键盘输入,页面会自动刷新进入网页。 HTTP之Referrer和Referrer-policy

设置meta

<meta name="referrer" content="no-referrer" />

设置referrerpolicy="no-referrer"

        以上已验证过,只是存在部分兼容性问题。

https://images.weserv.nl/?url=${你的图片地址}

        因为网址是国外的速度有点慢效果还行,目的就是返回一个不受限制的图片,但是 GIF 格式会返回jpg也就是没有了动画效果。

利用iframe伪造请求referer

        内容参考 如何绕开referrer防盗链 - 掘金

function showImg(src, wrapper ) {
    let url = new URL(src);
    let frameid = 'frameimg' + Math.random();
    window.img = `<img id="tmpImg" width=400 src="${url}" alt="图片加载失败,请稍后再试"/> `;
​
    // 构造一个iframe
    iframe = document.createElement('iframe')
    iframe.id = frameid
    iframe.src = "javascript:parent.img;" // 通过内联的javascript,设置iframe的src
    // 校正iframe的尺寸,完整展示图片
    iframe.onload = function () {
        var img = iframe.contentDocument.getElementById("tmpImg")
        if (img) {
            iframe.height = img.height + 'px'
            iframe.width = img.width + 'px'
        }
    }
    iframe.width = 10
    iframe.height = 10
    iframe.scrolling = "no"
    iframe.frameBorder = "0"
    wrapper.appendChild(iframe)
}
​
showImg('https://tiebapic.baidu.com/forum/w%3D580%3B/sign=f88eb0f2cf82b9013dadc33b43b6ab77/562c11dfa9ec8a135455cc35b203918fa1ecc09c.jpg', document.querySelector('#container'))

        结果如下: HTTP之Referrer和Referrer-policy

客户端在请求时修改header头部

        内容参考 如何绕开referrer防盗链 - 掘金

利用XMLHttpRequest

        XMLHttpRequest中setRequestHeader方法,用于向请求头添加或修改字段。我们能不能手动将修改 referer字段呢?

// 通过ajax下载图片
function loadImage(uri) {
    return new Promise(resolve => {
        let xhr = new XMLHttpRequest();
        xhr.responseType = "blob";
        xhr.onload = function() {
            resolve(xhr.response);
        };
​
        xhr.open("GET", uri, true);
        // 通过setRequestHeader设置header不会生效
        // 会提示 Refused to set unsafe header "Referer"
        xhr.setRequestHeader("Referer", ""); 
        xhr.send();
    });
}
  
​
// 将下载下来的二进制大对象数据转换成base64,然后展示在页面上
function handleBlob(blob) {
    let reader = new FileReader();
    reader.onload = function(evt) {
        let img = document.createElement('img');
        img.src = evt.target.result;
        document.getElementById('container').appendChild(img)
    };
    reader.readAsDataURL(blob);
}
​
const imgSrc = "https://tiebapic.baidu.com/forum/w%3D580%3B/sign=f88eb0f2cf82b9013dadc33b43b6ab77/562c11dfa9ec8a135455cc35b203918fa1ecc09c.jpg";
​
loadImage(imgSrc).then(blob => {
    handleBlob(blob);
});
​

上述代码运行时会发现控制台提示错误:

        Refused to set unsafe header "Referer"

        可以看见setRequestHeader设置referer响应头是无效的,这是由于浏览器为了安全起见,无法手动设置部分保留字段,不幸的是Referer恰好就是保留字段之一,详情列表参考Forbidden header name。

利用fetch

// 将下载下来的二进制大对象数据转换成base64,然后展示在页面上
function handleBlob(blob) {
    let reader = new FileReader();
    reader.onload = function(evt) {
        let img = document.createElement('img');
        img.src = evt.target.result;
        document.getElementById('container').appendChild(img)
    };
    reader.readAsDataURL(blob);
}
​
const imgSrc = "https://tiebapic.baidu.com/forum/w%3D580%3B/sign=f88eb0f2cf82b9013dadc33b43b6ab77/562c11dfa9ec8a135455cc35b203918fa1ecc09c.jpg";
​
​
function fetchImage(url) {
    return fetch(url, {
        headers: {
            // "Referer": "", // 这里设置无效
        },
        method: "GET",  
        referrer: "", // 将referer置空
        // referrerPolicy: 'no-referrer', 
    }).then(response => response.blob());
}
​
fetchImage(imgSrc).then(blob => {
    handleBlob(blob);
});

        通过将配置参数referrer置空,可以看见本次请求已经不带referer了 HTTP之Referrer和Referrer-policy

        或者设置 referrerPolicy为"no-referrer"

HTTP之Referrer和Referrer-policy

服务器作防盗链图片中转

        这里我们使用express index.js

const express = require('express');
const app = express();
​
app.use('/img', require('./routers/index.js'))
​
app.listen(3000);
routers/index.js

var express = require('express');
var router = express.Router();
var request = require('request');
​
router.get('/', function(req, res, next) {
    var options = {
        method: 'GET',
        url: 'https://tiebapic.baidu.com/forum/w%3D580%3B/sign=f88eb0f2cf82b9013dadc33b43b6ab77/562c11dfa9ec8a135455cc35b203918fa1ecc09c.jpg',
        headers: {
            'Referer': '',
        }
    };
    request(options).pipe(res)
    
});
​
module.exports = router;

常见防盗链方法

        防盗链一般有下面几种方式:

                1.动态文件名,或者定期修改文件名称或路径

                2.判定引用地址,一般是判断浏览器请求时HTTP头的Referer字段的值

                3.使用登录验证,cookie

                4.图片加水印

利用nginx

        ngx_http_referer_module用于阻挡来源非法域名的请求 nginx指令valid_refers,全局变量$invalid_refer 对资源的防盗链nginx配置为

location ~.*\.(gif|jpg|png|bmp|flv|swf|rar|zip)$
{
    valid_referers none blocked test.com *.test.com;   // 加none的目的是确保浏览器可以直接访问资源
    if($invalid_referer)
    {
        #return 403;  // 直接返回403
        rewrite ^/ http://www.test.com/403.jpg; // 返回指定提示图片
    }
}

        这种方法是在server或者location段中加入:valid_referers

        这个指令在referer头的基础上为 $invalid_referer 变量赋值,其值为0或1。如果valid_referers列表中没有Referer头的值, $invalid_referer将被设置为1。 如果 $invalid_referer等于 1,在if语句中返回一个 403 给用户,这样用户便会看到一个 403 的页面, 如果使用下面的rewrite,那么盗链的图片都会显示 403.jpg。 该指令支持none和blocked:

  • 其中none表示空的来路,也就是直接访问,比如直接在浏览器打开一个文件

  • blocked表示被防火墙标记过的来路,*..com表示所有子域名

        但是传统的防盗链也会存在一些问题,因为refer是可以伪造的, 所以可以使用加密签名的方式来解决这个问题。 什么是加密签名?就是当我们请求一个图片的时候,我要给它带一些签名过去,然后返回图片的时候我们判断下签名是否正确,相当于对一个暗号。 更多内容请参考 防盗链的原理以及实现 - 知乎

服务器端判断referer

        我们能通过对比req.headers['referer']和req.url中的host来确认资源请求是否是别的站点发来的。 接着,当我们知道了资源请求的来源,我们就能通过一系列手段来决定是否响应请求以及怎样响应。 通常的做法是设置一个白名单,在白名单内的请求我们就响应,否则就不响应。

let http = require("http");
let fs = require("fs");
let url = require("url");
let path = require("path");
// 白名单
const whiteList = ["localhost:8080"];
​
/**
 * 三种情况下允许引用图片:
 * 1. 本网站
 * 2. 无referer信息的情况。(服务器认为是从浏览器直接访问的图片URL,所以这种情况下能正常访问)
 * 3. 授权的网址。(配置白名单)
 */
​
http
  .createServer(function (req, res) {
​
    let refer = req.headers["referer"] || req.headers["refer"];
    console.log('refer----', refer, req.url);
    res.setHeader("Access-Control-Allow-Origin", "*");
    if (refer) {
      let referHostName = url.parse(refer, true).host;
      let currentHostName = url.parse(req.url, true).host;
      console.log(referHostName, currentHostName, '--==')
      // 当referer不为空, 但host未能命中目标网站且不在白名单内时, 返回错误的图
      if (
        referHostName != currentHostName &&
        whiteList.indexOf(referHostName) == -1
      ) {
        res.setHeader("Content-Type", "image/jpeg");
        fs.createReadStream(path.join(__dirname, "/src/img/403.jpg")).pipe(res);
        return;
      }
    }
    // 当referer为空时, 返回正确的图
    res.setHeader("Content-Type", "image/jpeg");
    fs.createReadStream(path.join(__dirname, "/src/img/1.jpg")).pipe(res);
    
  })
  .listen(9999);
     利用http启动一个客户端: client.js
let http = require("http");
let fs = require("fs");
let url = require("url");
let path = require("path");
​
// 创建服务器
http.createServer(function (req, res) {
  let staticPath = path.join(__dirname, "src");
  let pathObj = url.parse(req.url, true);
​
  if (pathObj.pathname === "/") {
    pathObj.pathname += "index.html";
  }
  //  读取静态目录里面的文件,然后发送出去
  let filePath = path.join(staticPath, pathObj.pathname);
  fs.readFile(filePath, "binary", function (err, content) {
    if (err) {
      res.writeHead(404, "Not Found");
      res.end("<h1>404 Not Found</h1>");
    } else {
      res.writeHead(200, "Not Found");
      res.write(content, "binary");
      res.end();
    }
  });
}).listen(8080);
​

        index.html

<div id="container">
    <img src="http://localhost:9999">
</div>

分别启动客户端和服务器: HTTP之Referrer和Referrer-policy

        如果我们修改下服务器端whiteList:

// 白名单
const whiteList = [];

        重启服务器端,访问客户端后 我们发现响应结果变成了403图片:

防止网址被 iframe

        在页面底部或其它公用部位加入如下代码:

// 用js方法检测地址栏域名是不是当前网站绑定的域名,如果不是,则跳转到绑定的域名上来,这样就不怕网站被别人iframe了
if(window!=parent) {
    window.top.location.href = window.location.href; 
}

注:

        以上代码地址: Blog/HTTP相关/Demos/referer at main · zxl925768661/Blog · GitHub

参考资料:

Referrer-Policy - HTTP | MDN

Referer - HTTP | MDN

如何绕开referrer防盗链 - 掘金

referer与防盗链 - 掘金

八种常见的防盗链方法总结及分析 - ForeverPine - 博客园文章来源地址https://www.toymoban.com/news/detail-403814.html

到了这里,关于HTTP之Referrer和Referrer-policy的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【HTTP版本】HTTP/1.0、HTTP/1.1、HTTP/2.0、HTTP/3.0等重点知识汇总

    目录 HTTP/1.1 的优点有哪些? HTTP/1.1 的缺点有哪些? HTTP 1.0,1.1,2.0,3.0 的主要区别 HTTP/1.1 相比 HTTP/1.0 提高了什么性能? HTTP/2 做了什么优化? HTTP/3 做了哪些优化? HTTP 最突出的优点是「简单、灵活和易于扩展、应用广泛和跨平台」。 1. 简单 HTTP 基本的报文格式就是 head

    2024年02月07日
    浏览(38)
  • web前端面试-- http的各个版本的区别(HTTP/0.9、HTTP/1.0、HTTP/1.1、HTTP/2.0、HTTP/3.0)

    本人是一个web前端开发工程师,主要是vue框架,整理了一些面试题,今后也会一直更新,有好题目的同学欢迎评论区分享 ;-) web面试题专栏:点击此处 HTTP(超文本传输协议)是用于在网络上传输和接收超文本的协议。HTTP的各个版本有以下区别: HTTP/0.9 :这是最早的版本,

    2024年02月07日
    浏览(39)
  • HTTP——HTTP报文内的HTTP信息

    HTTP 通信过程包括从客户端发往服务器端的请求及从服务器端返回客户端的响应。本章就让我们来了解一下请求和响应是怎样运作的。 HTTP——一、了解Web及网络基础 HTTP——二、简单的HTTP协议 HTTP——三、HTTP报文内的HTTP信息 HTTP——四、返回结果的HTTP状态码 HTTP——五、与

    2024年02月14日
    浏览(45)
  • 【HTTP/1.1、HTTP/2、HTTP/3】

    三种优化思路来优化 HTTP/1.1 协议: 尽量避免发送 HTTP 请求; 在需要发送 HTTP 请求时,考虑如何减少请求次数; 减少服务器的 HTTP 响应的数据大小; 避免发送HTTP请求 对于一些具有重复性的 HTTP 请求,比如每次请求得到的数据都一样的,我们可以把这对「请求-响应」的数据

    2024年02月03日
    浏览(28)
  • 计算机网络—HTTP基本概念、HTTPS、HTTP状态码、HTTP缓存、HTTP请求

    参考小林coding HTTP是超文本传输协议。所谓的超文本,就是超越了普通文本的文本,最关键的是有超链接,能从一个超文本跳转到另一个超文本。 HTML是最常见的超文本,本身是纯文字文件,但是内部使用很多标签定义图片、视频等链接,再经过浏览器的解释,呈现出来的就是

    2024年02月07日
    浏览(47)
  • HTTP/1.1、HTTP/2、HTTP/3 基本概述

    参考链接 https://xiaolincoding.com/network/2_http/http_interview.html#http-1-1-%E7%9B%B8%E6%AF%94-http-1-0-%E6%8F%90%E9%AB%98%E4%BA%86%E4%BB%80%E4%B9%88%E6%80%A7%E8%83%BD HTTP/1.1 相比 HTTP/1.0 性能上的改进: 使用长连接的方式改善了 HTTP/1.0 短连接造成的性能开销。 支持管道(pipeline)网络传输,只要第一个请求发

    2024年01月25日
    浏览(44)
  • 网络协议HTTP/1、HTTP/2 及 HTTP/3详解

    目录 概述  一、发展史 HTTP/1.1  Keep-alive  动静分离  HTTP/2 二进制传输   多路复用 Header 压缩 服务端 Push  HTTP/3 QUIC  多路复用 0-RTT 纠错机制 三、小结 HTTP(Hyper Text Transformer Protocol,超文本传输协议)是一种通信协议,它允许将超文本标记语言(HTML)文档从Web服务器传送到

    2024年02月02日
    浏览(56)
  • 【Jmeter】HTTP请求(HTTP Request) - 配置基本HTTP请求

    右击 Thread (线程组) 鼠标移至 Add (添加) → Sampler (取样器) 点击 HTTP Rrequest (HTTP请求头) 即可完成HTTP请求新建 进入 HTTP Rrequest (HTTP请求头) 页面 输入 Protocol (传输协议类型) ,不输入默认为HTTP请求 输入 Server Name or IP (服务器或IP地址) 输入 Port Number (端口号),没有端口号则不输入

    2024年02月14日
    浏览(41)
  • 了解HTTP/1.1、HTTP/1.0 和 HTTP/2.0

    HTTP/1.1、HTTP/1.0 和 HTTP/2.0 是超文本传输协议(HTTP)的三个主要版本 先解释一下什么是超文本协议 超文本传输协议(HyperText Transfer Protocol,简称 HTTP)是互联网上应用最广泛的一种网络协议。设计 HTTP 的初衷是为了允许浏览器从服务器获取(或向服务器提交)网页数据,从而

    2024年01月25日
    浏览(35)
  • http1.0、http1.1 http 2.0

    HTTP/1.0是无状态、无连接的应用层协议。 无连接:每次请求都要建立连接,需要使用 keep-alive 参数建立长连接、HTTP1.1默认长连接keep-alive   无法复用连接,每次发送请求都要进行TCP连接,TCP的连接释放都比较费事,会导致网络利用率低 队头阻塞 队头阻塞(head of line blocking),

    2024年02月16日
    浏览(34)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包