前言
在我们日常漏洞挖掘的过程中,可能会碰见数据包中的referer带有一些信息的情况,如token、sessionid,key和phoneNumber等,对于这些信息,我们如何去窃取呢?这里可以使用img标签去进行信息的窃取。
场景如下:
A为url,其值为https://test.com/index.html?token=xxxxxx,当我们访问A时进入到的页面为B,B的html中有一个<img>标签,这个标签的src属性是我们可以随意控制的,且这个B页面启用了unsafe-url。
默认情况下,unsafe-url是不启用的,不启用时默认referer的内容为协议、主机名和端口,不携带参数,这是Referrer Policy,后面我会提到。
真实环境场景:
一切<img>标签的src属性可控的点都有可能。
例如:
- 论坛站点,用户的头像
url可控,对应于img中的src可控。 - 视频播放站点,存在评论区,用户头像
url可控。
攻击场景演示
攻击效果: 受害者会带着自己的
token,就是这里的A,访问到页面B,B中的img标签的src属性我们可控,设置为攻击者监听数据包的脚本,监听的数据包中包含有敏感信息的referer,进而实现信息的窃取。
下面来演示一下敏感信息的窃取。
A为URL:http://127.0.0.1:3000/index.html?token=xxxxxxB为这个index.html页面,其中img标签的src属性我们可控,其页面启用了unsafe-url。
B的index.html页面如下,其中的http://127.0.0.1:3001/logo.png为攻击者嵌入的监听数据包脚本。
1 |
|
这个http://127.0.0.1:3001/logo.png的后端nodejs脚本main.js如下:
1 | const http = require('http'); |
攻击者在自己的vps上运行脚本main.js,受害者访问到的页面为http://127.0.0.1:3000/index.html。
本地使用python启动一个HTTP服务,模拟受害者访问的页面。
在index.html同目录下执行命令python -m http.server 3000,此时攻击者node main.js启动监听脚本。
此时受害者访问到A,受害者的token成功被攻击者窃取。

再来看一下不启用unsafe-url的情况。
修改index.html为index2.html如下,切换为默认情况。
1 |
|
此时访问http://localhost:3000/index2.html?token=xxxxx,这里发现referer中的token就会消失了。此处测试使用的浏览器为Chrome 135.0.7049.115(正式版本) (arm64)。出现这种情况是由于referrer-policy的关系。

Referrer-policy
介绍一下 referrer-policy。它是一个 HTTP 头部,用于控制在用户导航到其他网页时,浏览器在 HTTP 请求的 Referer 头部中发送哪些信息。Referer 头部包含了前一个页面的 URL,这对于分析用户来源、安全性和内容定制等方面非常有用。然而,出于隐私和安全考虑,开发者可能需要限制甚至完全阻止 Referer 信息的发送。referrer-policy 就是为了实现这种控制而生的。
为什么需要 referrer-policy?
- 隐私保护: 有些页面的 URL 可能包含用户的敏感信息(例如,会话 ID、用户名等)。不加限制地发送
Referer可能会泄露这些信息给第三方网站。 - 安全性: 恶意网站可能会利用
Referer信息进行某些攻击,例如跨站请求伪造(CSRF)的变种。 - 数据分析的精细化控制: 开发者可能希望更精确地控制哪些来源信息可以被分析工具收集。
referrer-policy 的取值
referrer-policy 头部可以设置多个不同的值,这些值定义了在不同场景下 Referer 头部应该如何发送。
以下是一些常见的取值及其含义:
no-referrer: 这是最严格的策略。无论在任何情况下,都不会发送Referer头部。no-referrer-when-downgrade: 这是默认策略。只有在从HTTPS页面导航到HTTP页面时,才会不发送Referer头部。在其他情况下(例如,HTTPS到HTTPS,HTTP到HTTP,HTTP到HTTPS),会发送完整的来源URL。这个策略旨在防止HTTPS页面上的敏感信息通过不安全的HTTP连接泄露。same-origin: 只有当目标网站与当前网站具有相同的源(协议、域名和端口都相同)时,才会发送完整的Referer头部。对于跨域请求,不会发送Referer头部。origin: 在任何情况下,都会发送来源的协议和主机名(不包含路径和查询字符串)。例如,如果当前页面是https://example.com/page.html,那么Referer头部的值将是https://example.com/。strict-origin: 与origin类似,但在从 HTTPS 页面导航到 HTTP 页面时,不会发送Referer头部。origin-when-cross-origin: 对于同源请求,发送完整的Referer头部。对于跨域请求,只发送来源的协议和主机名。strict-origin-when-cross-origin: 对于同源请求,发送完整的Referer头部。对于跨域请求,只发送来源的协议和主机名。并且在从 HTTPS 页面导航到 HTTP 页面时,不会发送Referer头部。unsafe-url: 这是最宽松的策略。无论在任何情况下,都会发送完整的Referer头部,包括协议、主机名、路径和查询字符串。强烈建议避免使用此策略,因为它可能会暴露敏感信息。
如何设置 referrer-policy?
设置 referrer-policy 有几种方式:
- HTTP 头部: 这是最常用和推荐的方式。服务器在 HTTP 响应头中添加
Referrer-Policy字段并设置相应的值。例如:
1 | Referrer-Policy: strict-origin-when-cross-origin |
- HTML
<meta>标签: 在 HTML 文档的<head>部分使用<meta>标签设置referrer-policy:
1 |
|
- HTML 元素的
referrerpolicy属性: 为特定的<a>,<area>, 和<form>元素设置referrerpolicy属性,覆盖全局设置:
1 | <a href="https://example.com" referrerpolicy="origin">Visit Example</a> |
- 在
AJAX中配置referrer-policy: 对于通过JavaScript发起的AJAX请求:
-
使用
fetchAPI: 在fetch请求的配置对象中,使用referrerPolicy选项设置特定的策略。例如:1
2
3
4
5fetch('/api/data', {
method: 'GET',
referrerPolicy: 'origin-when-cross-origin'
})
// ...此设置会覆盖全局的
referrer-policy。 -
使用
XMLHttpRequest:XMLHttpRequest本身没有直接的referrerPolicy属性。你需要依赖全局的referrer-policy设置(HTTP 头部或<meta>标签)。
- 在内容安全策略 (CSP) 中配置
referrer-policy:
referrer-policy 可以作为 CSP 指令的一部分在 HTTP 响应头或 HTML <meta> 标签中设置。
- HTTP 头部中的 CSP:
1 | Content-Security-Policy: referrer-policy origin-when-cross-origin |
- HTML
<meta>标签中的 CSP:
1 |
|
在 CSP 中设置 referrer-policy 会强制整个文档及其发起的请求遵循该策略,但会被更具体的设置(如 fetch API 中的 referrerPolicy 或 HTML 元素的 referrerpolicy 属性)覆盖。