你不知道的 HTTP Referer
前言
上周突然发现自己的自己站点的图片全都403了,之前还是好好的,图片咋就全都访问不了呢?由于我每次发文章都是先发了掘金,然后再从掘金拷贝到我自己的站点,这样我就不用在自己的站点去上传图片了,非常方便。
啥也没干,图片咋就403了呢?估计又是整了什么开源节流,降本增效吧,说白了就是大家都用他站点的图片导致流量费用蹭蹭蹭的往上涨,人家肯定不愿意了,这下给图片都加上防盗了,非自己的站点全都给你返回403.
防盗原理
是不是很好奇这些图片防盗是怎么做的?
我们可以自己来实现一下这个场景:不受信任的域名访问我服务器上的图片资源全都返回403
准备几个域名
这里没有域名也不用担心,我们可以直接本地模拟就行了,比如我这里使用SwitchHosts
给本地添加的三个域名并且都指向我们的本地IP
这样的话这三个域名都能够访问我们的本地服务了。
服务端逻辑
静态资源目录
这里就用之前的nest
服务来做演示,之前我们在这个服务上指定了静态资源目录
app.useStaticAssets(join(__dirname, '../static'), {
prefix: '/static',
}); // 静态资源
前端访问图片
<img class="my_img" src="http://nanjiu.com:3000/static/sy.jpg" />
这里是使用nanjiu.com
代理域名来访问的,图片能够正常访问
防盗中间件
这里我们可以来实现一个全局中间件用来处理图片的访问,当访问域名不在我们信任的白名单内直接给他返回403
// 白名单
const whiteList = ['nanjiu.com', 'fenanjiu.com']
// 图片防盗中间件
function imgMiddleware(req, res, next) {
console.log('--req', req.headers)
// 获取资源类型
const type = req.headers.accept || ''
if(!type.includes('image')) {
// 不是图片资源,直接放行
next()
return
}
const referer = req.headers.referer || ''
// 获取referer的域名
const { hostname } = url.parse(referer, true)
if(referer && whiteList.includes(hostname) || !referer) {
// 访问域名在白名单内,放行 !referer表示直接访问图片(比如浏览器地址栏输入图片地址)
res.status(200)
next()
}else {
// 访问域名不在白名单内,返回403
res.status(403)
res.send('逮到你了,又来偷我图片是吧!')
}
}
这里需要注意的是,全局中间件在使用时一定要在useStaticAssets
之前
async function bootstrap() {
const app = await NestFactory.create<NestExpressApplication>(AppModule);
app.setGlobalPrefix('api'); // 全局路由前缀
app.use(cors()); // 允许跨域
app.use(json({ limit: '10mb' })); // 允许上传大文件
app.use(urlencoded({ extended: true, limit: '10mb' })); // 允许上传大文件
app.use(imgMiddleware) // 图片防盗中间件
app.useStaticAssets(join(__dirname, '../static'), {
prefix: '/static',
}); // 静态资源
await app.listen(3000);
console.log(`Application is running on: ${await app.getUrl()}`);
}
bootstrap();
这上面的代码中我们可以看到,现在受信任的域名就只有nanjiu.com
和fenanjiu.com
当前端页面使用sy.com
这个域名去访问nanjiu.com
域名下的图片时,此时应该是会进入防盗逻辑,返回403
并且送他一句
Referer
从上面我们实现的防盗原理来看,这其中最关键的就是referer
,那么这个referer
到底是什么呢?为什么可以用它来做图片防盗
Referer是什么
MDN解释如下:
Referer
请求头包含了当前请求页面的来源页面的地址,即表示当前页面是通过此来源页面里的链接进入的。服务端一般使用Referer
请求头识别访问来源,可能会以此进行统计分析、日志记录以及缓存优化等。
从这里我们就大概能知道图片防盗的原理了,服务端可以通过请求头中的Referer
来识别访问来源,然后判断应不应该给你返回图片
Referer
这个单词实际上是Referrer
的错误拼写,这其实是个历史原因,在早期 HTTP 规范当中就存在的拼写错误,后面为了向下兼容,所以将错就错。
拼写错误只有 Request Headers
的 Referer
,在其他地方比如General Headers
、 JavaScript
及 DOM
上,都是正确的拼写。
Referrer-Policy
Referrer-Policy
首部用来监管哪些访问来源信息——会在Referer
中发送——应该被包含在生成的请求当中。
它其实是用来控制 Referer 返回的具体内容的
它有以下属性值:
- no-referrer: 整个
Referer
首部会被移除。访问来源信息不随着请求一起发送。 - no-referrer-when-downgrade(默认值): 在没有指定任何策略的情况下用户代理的默认行为。在同等安全级别的情况下,引用页面的地址会被发送 (HTTPS->HTTPS),但是在降级的情况下不会被发送 (HTTPS->HTTP)。
- origin: 在任何情况下,仅发送文件的源作为引用地址。例如
https://example.com/page.html
会将https://example.com/ 作为引用地址
。 - 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(移除参数信息之后)作为引用地址。
这么多referrer
策略,我们怎么使用呢?
使用
meta标签
我们可以用一个 name 为 referrer
的meta
元素为整个文档设置 referrer
策略
<meta name="referrer" content="no-referrer">
我的个人站点就是使用该方法来解决图片访问403问题的,但需要注意的是,如果你为页面设置了no-referrer
策略会导致页面上所有的请求都不会发送referer
,使用时需要自己权衡利弊。
rel属性
可以在a
、area
、link
标签上通过rel
属性来单独指定referrer
的策略
<a href="xxx" rel="noreferrer">新地址</a>
referrerpolicy属性
可以在a
、area
、link
、img
、iframe
、script
标签上通过referrerpolicy
属性来单独指定referrer
策略
<img class="my_img" referrerpolicy="no-referrer" src="http://nanjiu.com:3000/static/sy.jpg" />
比如上面例子中的这张图片我们加上referrerpolicy="no-referrer"
再去访问,页面还是在sy.com
这个域名下面
可以看到请求头中没有携带referer
,所以它就能够躲过图片防盗逻辑。
Headers请求头
也可以更改 HTTP 头信息中的 Referer-Policy 值。比如你使用的是 Nginx,则可以设置 add_headers 设置请求头。
add_header Referrer-Policy "no-referrer";
Headers 请求头和其它页面元素属性同时存在时,确定元素的有效策略时的优先顺序是:
- 元素级策略
- 页面级策略
- 浏览器默认
如果这篇文章有帮助到你,️关注+点赞️鼓励一下作者,文章公众号首发,关注 前端南玖
第一时间获取最新文章~
你不知道的 HTTP Referer的更多相关文章
- MySQL 系列(三)你不知道的 视图、触发器、存储过程、函数、事务、索引、语句
第一篇:MySQL 系列(一) 生产标准线上环境安装配置案例及棘手问题解决 第二篇:MySQL 系列(二) 你不知道的数据库操作 第三篇:MySQL 系列(三)你不知道的 视图.触发器.存储过程.函数 ...
- MySQL 系列(二) 你不知道的数据库操作
第一篇:MySQL 系列(一) 生产标准线上环境安装配置案例及棘手问题解决 第二篇:MySQL 系列(二) 你不知道的数据库操作 本章内容: 查看\创建\使用\删除 数据库 用户管理及授权实战 局域网 ...
- 《你不知道的JavaScript》整理(二)——this
最近在读一本进阶的JavaScript的书<你不知道的JavaScript(上卷)>,这次研究了一下“this”. 当一个函数被调用时,会创建一个活动记录(执行上下文). 这个记录会包含函 ...
- 《你不知道的JavaScript》整理(一)——作用域、提升与闭包
最近在读一本进阶的JavaScript的书<你不知道的JavaScript(上卷)>,里面分析了很多基础性的概念. 可以更全面深入的理解JavaScript深层面的知识点. 一.函数作用域 ...
- 把token带到 http头部 或者验证一下referer
提交地址:http://baozoumanhua.com/users/8311358提交数据:-----------------------------195704664324Content-Disp ...
- 你不知道的Javascript(上卷)读书笔记之一 ---- 作用域
你不知道的Javascript(上卷)这本书在我看来是一本还不错的书籍,这本书用比较简洁的语言来描述Js的那些"坑",在这里写一些博客记录一下笔记以便消化吸收. 1 编译原理 在此 ...
- javascript操作referer
Referrer的重要性 HTTP请求中有一个referer的报文头,用来指明当前流量的来源参考页.例如在www.sina.com.cn/sports/上点击一个链接到达cctv.com首页,那么就r ...
- Http referer origin
为了防止CSRF的攻击,我们建议修改浏览器在发送POST请求的时候加上一个Origin字段,这个Origin字段主要是用来标识出最初请求是从哪里发起的.如果浏览器不能确定源在哪里,那么在发送的请求里面 ...
- http - referer
以前对Http中Referer的认识不够透彻.最近理了理,记录一下. 1 Referer可以记录访问的来源,统计访问量,可以用来防盗链. 2 客户端用js不能篡改Referer,用一些插件什么的可以达 ...
- 在JavaScript和C#中获得referer
1. JavaScript /** * 获取HTTP请求的Referer * @ishost 布尔类型 Referer为空时是否返回Host(网站首页地址) */ function get_http_ ...
随机推荐
- 还不知道怎么 Mock ,用这 6款工具!
以下是几个常用的国外可以mock测试的工具,供参考: MockServer: MockServer 是一个开源的 API mock 测试工具,提供了强大的模拟服务器和 mock 服务功能.MockSe ...
- [Pytorch框架] 5.2 Pytorch处理结构化数据
文章目录 5.2 Pytorch处理结构化数据 简介 数据预处理 定义数据集 定义模型 训练 import numpy as np import pandas as pd import torch f ...
- Python-解三元一次方程
需要解的方程组为: x + y + z = 26 x - y = 1 2x - y + z = 18 下面进入代码实现: 1.导入数学计算库 numpy import numpy as np 2.生成 ...
- .net 6 使用 NEST 查询,时间字段传值踩坑
0x01业务描述 说明: 同事搭建的业务系统,最开始使用 log4net 记录到本地日志. 然后多个项目为了日志统一,全部记录在 Elasticsearch ,使用 log4net.Elastic ...
- ES6模块化之import的使用方式
1.引入外部文件: <script src='文件路径' type='module'><!--PS:这个type="module" 必须要写,否则浏览器会报错-- ...
- 一篇文章搞定什么是nodeJs它和NPM关系与应用
现在前端的入门门槛越来越高了,不再是单纯 html+css+js,各种前端框架 层出不穷,各种ui组件库层出不穷. 模块化,打包化,各种工具库层出不穷,前端变成大前端 ,甚至前端可以搞定整个项目,通过 ...
- 自创简易CSS Tab 选项卡
前段时间我注册了 w3c.run域名,打算做一个W3C相关技术在线试验工具.没错,就是在线编写html.css.js代码然后在线运行,查看效果. 在设计首页时,我打算首页提供三个代码编辑器,介于界面大 ...
- 2021-01-22:java中,HashMap的写流程是什么?
福哥答案2021-01-22:jdk1.7写流程:1.如果table数组为空,table数组初始化,调用inflateTable方法.2.如果key为null,调用putForNullKey()方法, ...
- vue全家桶进阶之路45:Vue3 Element Plus el_button组件
在 Vue 3 中,Element Plus 的 ElButton 组件提供了多种按钮类型和属性,可以用于实现不同的交互效果.下面是 ElButton 常用的作用和属性: 作用: 用于在页面上添加交互 ...
- ubuntu搜狗输入法显示简体中文,输入却是繁体中文问题解决方案
一.现场重现 我的ubuntu版本是20.04,搜狗输入法版本是2.4.在输入的时候发生了如下场景: 明明输入法上是简体中文,可是打出来就变成了繁体中文! 二.解决方案 1.尝试 网上许多答案都是按下 ...