Canvas 指纹追踪揭秘:为什么你换了 IP 和 浏览器,网站还能认出你是谁?(附 Python 检测脚本)
👻 前言:无痕模式的“谎言”
你是否遇到过这种情况:
你在京东看了一双鞋,没登录账号,然后清除了浏览器 Cookies,换了 IP 地址,打开了 Chrome 的“无痕模式”。
结果,当你打开另一个新闻网站时,广告栏里赫然推荐着刚才那双鞋。
这是因为网站不再通过 Cookies(身份证)来识别你,而是通过 Canvas 指纹(生物特征) 认出了你。在反爬虫领域,这也是区分“真浏览器”和“Selenium 脚本”的致命杀招。
🎨 一、 核心原理:显卡的“笔迹”
Canvas 指纹的核心逻辑非常巧妙:利用硬件的物理差异。
1. 并没有完美的“标准”
虽然 HTML5 的 <canvas> 代码是标准的,但在不同的操作系统(Windows/Mac)、不同的浏览器内核(Chrome/Firefox)、不同的显卡(NVIDIA/AMD/Intel)上,具体的渲染结果是微小不同的。
2. 抗锯齿 (Anti-aliasing) 的差异
当你要求浏览器在 Canvas 上画一行字或一个 3D 图形时,显卡需要处理边缘的“锯齿”。
- 有的显卡会把边缘像素混合成浅灰色。
- 有的显卡混合的算法稍微偏深一点点。
- 有的显卡受操作系统字体平滑设置(ClearType)的影响。
这种像素级的肉眼不可见的差异,提取出来就是你的“指纹”。
指纹生成流程图 (Mermaid):
🧪 二、 实战演示:浏览器是如何“出卖”你的?
一段典型的 Canvas 指纹追踪代码通常包含以下步骤:
- 创建一个隐藏的画布。
- 绘制一段包含文字、表情符号(Emoji)和 渐变色 的复杂图形。
- 为什么要画 Emoji? 因为不同系统的 Emoji 字体差异巨大。
- 调用
canvas.toDataURL()获取图片的 Base64 字符串。 - 计算这个字符串的 Hash 值。
即使用户清除了 Cookies,只要他的硬件没变,这个 Hash 值永远不变。
🐍 三、 Python 实战:提取并验证 Canvas 指纹
虽然 Python 运行在后端,无法直接产生 Canvas 指纹,但我们可以使用 Selenium 模拟浏览器行为,去执行 JS 代码,看看机器人的指纹长什么样。
依赖安装:
pip install selenium webdriver_manager
Python 检测脚本 (canvas_sniffer.py):
import hashlib
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.chrome.service import Service
from webdriver_manager.chrome import ChromeDriverManager
def get_canvas_fingerprint(headless=True):
# 1. 配置浏览器选项
chrome_options = Options()
if headless:
chrome_options.add_argument("--headless") # 无头模式
chrome_options.add_argument("--no-sandbox")
# 2. 注入的指纹生成 JS 代码 (核心 Payload)
canvas_js = """
var canvas = document.createElement('canvas');
var ctx = canvas.getContext('2d');
var txt = 'BrowserLeaks, <canvas> 1.0';
ctx.textBaseline = "top";
ctx.font = "14px 'Arial'";
ctx.textBaseline = "alphabetic";
ctx.fillStyle = "#f60";
ctx.fillRect(125,1,62,20);
ctx.fillStyle = "#069";
ctx.fillText(txt, 2, 15);
ctx.fillStyle = "rgba(102, 204, 0, 0.7)";
ctx.fillText(txt, 4, 17);
// 获取 Base64 数据
return canvas.toDataURL();
"""
print(f"[*] 正在启动浏览器 (Headless={headless})...")
driver = webdriver.Chrome(service=Service(ChromeDriverManager().install()), options=chrome_options)
try:
# 打开一个空白页
driver.get("about:blank")
# 执行 JS
base64_str = driver.execute_script(canvas_js)
# 3. 计算哈希 (模拟指纹 ID)
fingerprint = hashlib.md5(base64_str.encode('utf-8')).hexdigest()
print(f"[+] 捕获 Canvas Base64 长度: {len(base64_str)}")
print(f"[+] 计算出的指纹 ID: {fingerprint}")
return fingerprint
except Exception as e:
print(f"[-] 发生错误: {e}")
finally:
driver.quit()
if __name__ == "__main__":
# 第一次:无头模式 (模拟爬虫)
fp1 = get_canvas_fingerprint(headless=True)
# 第二次:有头模式 (模拟正常用户,注意:某些配置下无头和有头渲染结果可能不同!)
fp2 = get_canvas_fingerprint(headless=False)
print("-" * 30)
if fp1 == fp2:
print("⚠️ 警告:该环境的指纹非常稳定,极易被追踪!")
else:
print("✅ 提示:无头模式与正常模式指纹不同,存在被反爬检测的风险(指纹不一致也是一种特征)。")
🛡️ 四、 防御与对抗:如何隐藏自己?
既然知道了原理,我们该如何防御?
- Tor Browser (洋葱浏览器):
- 这是目前最有效的防御手段。Tor 浏览器统一了所有用户的 Canvas 渲染输出(要么禁止,要么返回纯白图片),让所有人的指纹看起来都一样。
- 浏览器插件 (CanvasBlocker):
- 原理:“噪声注入” (Noise Injection)。
- 当网页请求 Canvas 数据时,插件会随机修改生成的像素数据(比如把某个像素的 RGB 值微调 1)。
- 结果:每次刷新页面,你的指纹 Hash 都会变化,网站就无法追踪你了。
- 禁用硬件加速:
- 在浏览器设置中关闭“硬件加速”,改用纯软件渲染。虽然会降低网页性能,但能抹除 GPU 的物理特征。
📝 总结
Canvas 指纹追踪是 Web 技术发展的双刃剑。
- 对于开发者:它是对抗恶意爬虫、防止账号被批量注册的利器。
- 对于用户:它是隐私泄露的隐形杀手。
作为技术人员,我们需要理解这种“由于硬件物理缺陷而产生的唯一性”,才能在未来的攻防战中立于不败之地。
(觉得硬核?点赞、收藏,下期教你《如何用 Python 识别加密流量中的恶意行为》!)
更多推荐



所有评论(0)