惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Jina AI
Jina AI
云风的 BLOG
云风的 BLOG
人人都是产品经理
人人都是产品经理
T
The Blog of Author Tim Ferriss
阮一峰的网络日志
阮一峰的网络日志
罗磊的独立博客
J
Java Code Geeks
博客园 - 聂微东
B
Blog
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
WordPress大学
WordPress大学
腾讯CDC
L
LangChain Blog
Apple Machine Learning Research
Apple Machine Learning Research
Microsoft Azure Blog
Microsoft Azure Blog
D
DataBreaches.Net
The GitHub Blog
The GitHub Blog
美团技术团队
博客园 - Franky
Google DeepMind News
Google DeepMind News
V
V2EX
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
月光博客
月光博客
The Cloudflare Blog

博客园 - papering

由于系统缓冲区空间不足或队列已满,不能执行套接字上的操作 string byte 内存 硬盘 CAS ABA AtomicLong mysql 索引长度限制 docker network FTP Connection Modes (Active vs. Passive) 字符长度 mysql 【车载架构】AUTOSAR CP系列之27:系统内核之 WdgM 看门狗管理 单目录文件数限制 在联表 join 时 使用 case when 按不同的条件关联不同的行 JDK21 Process Reaper TLS 栈溢出循环故障深度分析 栈溢出 写入相邻的内存区域 GCC 的 -fstack-protector 会在每个函数的栈帧底部放一个随机“金丝雀值”,函数返回前检查它是否被改掉,以此检测栈缓冲区溢出。 潜伏5年!GitLab高危RCE漏洞爆发,低权限即可控服 Redis 漏洞分析——lua 脚本篇 Redis guarantees the script's atomic execution. AMQP 0-9-1 连接通过 信道 进行多路复用,信道可以被认为是“共享单一 TCP 连接的轻量级连接”。 WSAETIMEDOUT WSAEACCES This module supports asynchronous I/O on multiple file descriptors. 设置其优先级值的线程的句柄 QT 主线程 优化 卡顿 主线程上的同步重活 防重入:进行中直接 return,避免连点双开。 把「一次性任务」收到 ThreadPoolExecutor(max_workers=2~3),限制峰值线程数 统一 Activity 浮层 去掉连环成功弹窗 为 with语句上下文提供的工具 懒加载 IDE发现 import 魔改chromium源码——CDP(Chrome DevTools Protocol)检测01 whether the browser environment is controlled by a robot. chromium指纹魔改 对拷线 rpa 任务编排 a JSON formatted stream to ``fp`` “幽灵字符”问题 浏览器背后的黑科技 多进程 多线程 callback technique: signals and slots
Canvas 指纹
papering · 2026-06-28 · via 博客园 - papering

深入浅出 Canvas 指纹技术:原理、局限与防御优化实战

魔改chromium源码——canvas指纹修改 第一节在进行以下操作之前,请确保已完成之前文章中提到的 源码拉取及编译 - 掘金

在src\third_party\blink\renderer\modules\canvas\canvas2d\canvas_2d_recorder_context.cc目录中,找到底下这段函数的源码。

我们以修改 canvas 的 fillStyle 值为例进行说明。对于其他属性的随机化处理,可以参考同样的思路:找到对应的代码位置,并按照类似的方式调整逻辑。这里不再逐一演示,但方法思路是通用的。


 
#ifndef RANDOM_COLOR_H
#define RANDOM_COLOR_H

#include <array>
#include <random>
#include <string>
#include "base/time/time.h"  // 用于动态种子

namespace content {
    // 声明并定义 getRandomColorCode 函数
    inline std::string getRandomColorCode() {
        // 十六进制字符集合
        const std::array<char, 17> hexChars = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f', '\0'};
        // 静态字符数组,用于存储颜色代码('#' + 6个字符 + '\0')
        static thread_local std::array<char, 8> colorCode;
        // 初始化伪随机数生成器
        static thread_local std::mt19937 gen(static_cast<unsigned>(base::Time::Now().ToTimeT()));
        static std::uniform_int_distribution<> dis(0, 15); // 生成 [0, 15] 范围内的随机数
        // 构造颜色代码字符串
        colorCode[0] = '#'; // 设置第c一个字符为 '#'
        for (int i = 1; i < 7; ++i) {
            colorCode[i] = hexChars[dis(gen)]; // 随机选择一个十六进制字符
        }
        colorCode[7] = '\0'; // 添加字符串终止符
        return colorCode.data(); // 返回指向静态数组的指针
    }
}

#endif // RANDOM_COLOR_H

先将v8::Localv8::String v8_string = value.Asv8::String();这行注释掉,然后新增底下两行代码。

image

修改完了之后保存,然后执行以下命令编译

autoninja -C out/Default chrome
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=0">
    <title>canvas</title>
</head>
<body>
    <canvas class="" id="myCanvas1" width="100" height="100"></canvas>
    <canvas class="" id="myCanvas2" width="100" height="100"></canvas>
    <script>
        function canvasFingerprint (urlStr) {
            var e = 3735928559
            // 基于数据 URL 计算哈希值
            for (var i = 0; i < 32; i++) {
                e = (65599 * e + urlStr.charCodeAt(e % urlStr.length)) >>> 0;
            }
            return e; // 返回最终的指纹值
        }

        const canvas = document.getElementById('myCanvas1');
        const ctx = canvas.getContext('2d');
        ctx.fillStyle = 'blue';
        ctx.fillRect(0, 0, 100, 100);

        const canvas2 = document.getElementById('myCanvas2');
        const ctx2 = canvas2.getContext('2d');
        ctx2.fillStyle = 'blue';
        ctx2.fillRect(0, 0, 100, 100);
        const urlStr1 = canvas.toDataURL();
        const urlStr2 = canvas2.toDataURL();
        // 调用函数生成指纹
        console.log(canvasFingerprint(urlStr1));
        console.log(canvasFingerprint(urlStr2));
    </script>
</body>
</html>

 

  在编译好的chromium中打开,就可以看到,每次刷新,他的颜色都不一样,已经被我们修改的源码给hook掉了。