浏览器指纹(Browser Fingerprinting)

浏览器指纹(Browser Fingerprinting)

浏览器指纹是一种识别和跟踪用户的技术,通过收集用户浏览器和设备的各种特征来创建一个独特的标识符。以下是实现浏览器指纹的一些常见方法:

  1. 用户代理字符串(User Agent String)
    用户代理字符串包含浏览器名称、版本、操作系统类型和版本等信息。虽然这一信息比较容易伪造,但结合其他特征可以增加指纹的唯一性。

  2. 浏览器插件和扩展(Browser Plugins and Extensions)
    不同用户安装的插件和扩展通常不同。通过检测浏览器中安装的插件列表,可以增加指纹的唯一性。

  3. 屏幕分辨率和颜色深度(Screen Resolution and Color Depth)
    屏幕分辨率和颜色深度是与用户设备硬件相关的参数,这些参数在不同设备上通常不同。

  4. HTTP 标头(HTTP Headers)
    浏览器发送的 HTTP 请求头中包含了很多信息,例如 Accept-Language、Accept-Encoding、Referer 等,可以用来进一步区分用户。

  5. 浏览器设置(Browser Settings)
    例如启用或禁用 cookies、Do Not Track 设置、是否允许 JavaScript、是否启用广告拦截等,这些设置通常因用户而异。

  6. 字体(Fonts)
    检测系统和浏览器中安装的字体。不同系统和用户安装的字体可能不同,通过字体列表可以增加唯一性。

  7. Canvas 指纹(Canvas Fingerprinting)
    利用 HTML5 Canvas 元素绘制一个图形,不同的浏览器、操作系统、显卡、配置等绘制出的图形会略有不同。这种微小的差异可以用于指纹识别。

  8. WebGL 指纹(WebGL Fingerprinting)
    类似于 Canvas 指纹,WebGL 指纹通过绘制复杂的 3D 图形来检测显卡和驱动的差异。

  9. 时区和语言(Timezone and Language)
    用户所在的时区和浏览器的语言设置也可以作为指纹的一部分。

  10. 媒体设备(Media Devices)
    获取用户的音频、视频输入输出设备信息,如麦克风和摄像头的列表。

示例

以下是一个简单的示例,收集部分浏览器指纹信息:

function getBrowserFingerprint() {
    let fingerprint = '';
    
    // User Agent
    fingerprint += navigator.userAgent;
    
    // Screen Resolution
    fingerprint += screen.width + 'x' + screen.height + screen.colorDepth;
    
    // Plugins
    fingerprint += Array.from(navigator.plugins).map(plugin => plugin.name).join(',');

    // Timezone
    fingerprint += Intl.DateTimeFormat().resolvedOptions().timeZone;
    
    // Language
    fingerprint += navigator.language;

    // Canvas Fingerprint
    const canvas = document.createElement('canvas');
    const ctx = canvas.getContext('2d');
    ctx.textBaseline = 'top';
    ctx.font = '14px Arial';
    ctx.fillText('Browser Fingerprint', 2, 2);
    fingerprint += canvas.toDataURL();
    
    return md5(fingerprint);
}

console.log(getBrowserFingerprint()); // '4ce1fad627cec0fa2ad0495bf3ec6189'

准确率

可以通过更加细致和深入的特征收集来提高识别率例如:

  1. Canvas 指纹和 WebGL 指纹
function getCanvasFingerprint() {
    const canvas = document.createElement('canvas');
    const ctx = canvas.getContext('2d');
    ctx.textBaseline = 'top';
    ctx.font = '14px Arial';
    ctx.fillText('Browser Fingerprint', 2, 2);
    return canvas.toDataURL();
}

function getWebGLFingerprint() {
    const canvas = document.createElement('canvas');
    const gl = canvas.getContext('webgl') || canvas.getContext('experimental-webgl');
    if (!gl) return null;

    const debugInfo = gl.getExtension('WEBGL_debug_renderer_info');
    const vendor = gl.getParameter(debugInfo.UNMASKED_VENDOR_WEBGL);
    const renderer = gl.getParameter(debugInfo.UNMASKED_RENDERER_WEBGL);
    
    return vendor + '|' + renderer;
}
  1. 音频指纹(Audio Fingerprinting)
function getAudioFingerprint() {
    const audioCtx = new (window.AudioContext || window.webkitAudioContext)();
    const oscillator = audioCtx.createOscillator();
    const analyser = audioCtx.createAnalyser();
    const gain = audioCtx.createGain();
    const scriptProcessor = audioCtx.createScriptProcessor(4096, 1, 1);

    let fingerprint = '';
    scriptProcessor.onaudioprocess = function(event) {
        const array = new Uint8Array(analyser.frequencyBinCount);
        analyser.getByteFrequencyData(array);
        fingerprint = array.join('');
        audioCtx.close();
    };

    oscillator.type = 'triangle';
    oscillator.connect(analyser);
    analyser.connect(scriptProcessor);
    scriptProcessor.connect(gain);
    gain.connect(audioCtx.destination);
    oscillator.start(0);

    return fingerprint;
}
  1. 硬件并行性(Hardware Concurrency)
function getHardwareConcurrency() {
    return navigator.hardwareConcurrency;
}
  1. 内存信息
function getDeviceMemory() {
    return navigator.deviceMemory;
}
  1. 电池状态
async function getBatteryStatus() {
    const battery = await navigator.getBattery();
    return battery.level + '|' + battery.charging;
}
  1. 传感器数据
    利用设备传感器数据,如加速度计、陀螺仪等
function getSensorData() {
    let sensorData = '';
    if ('DeviceOrientationEvent' in window) {
        window.addEventListener('deviceorientation', (event) => {
            sensorData = event.alpha + '|' + event.beta + '|' + event.gamma;
        });
    }
    return sensorData;
}
  1. 更细致的浏览器和操作系统信息
    即使是相同型号的手机和相同版本的浏览器,浏览器的具体配置和环境也可能略有不同。例如浏览器缓存、历史记录、Cookie 等。
function getDetailedBrowserInfo() {
    return {
        userAgent: navigator.userAgent,
        appVersion: navigator.appVersion,
        platform: navigator.platform,
        languages: navigator.languages,
        cookieEnabled: navigator.cookieEnabled,
        javaEnabled: navigator.javaEnabled(),
        doNotTrack: navigator.doNotTrack,
        hardwareConcurrency: navigator.hardwareConcurrency,
        deviceMemory: navigator.deviceMemory,
    };
}
  1. WebRTC 本地 IP
function getLocalIPs(callback) {
        const ips = [];
        const RTCPeerConnection = window.RTCPeerConnection || window.mozRTCPeerConnection || window.webkitRTCPeerConnection;
        if (!RTCPeerConnection) return;
        const pc = new RTCPeerConnection({ iceServers: [] });
        pc.createDataChannel('');
        pc.onicecandidate = function(e) {
            if (!e.candidate) { // All ICE candidates have been delivered
                callback(ips);
                return;
            }
            const ip = e.candidate.candidate.split(' ')[4];
            if (!ips.includes(ip)) ips.push(ip);
        };
        pc.createOffer().then(offer => pc.setLocalDescription(offer)).catch(err => console.error(err));
    }
    
getLocalIPs((ips) => {
        console.log(ips.join('|')); // 输出ip
    });

9.时间戳
利用用户访问的精确时间戳进行区分。即使两个人同时访问网站,精确到毫秒的时间戳也会有所不同。

10.服务端去重
利用用户上报的特征值进行筛选去重,最终获得更为精确的匿名id返回给客户端作为唯一标识。
考虑到动态变化对指纹稳定性的影响。可以考虑将动态特征和静态特征分开处理,动态特征可以作为辅助信息,给不同特征分配不同的权重,同时设定一个阈值来判断特征变化是否在可接受范围内

不同的设置可能会产生独特的结果,从而更精确地识别其用户

确定特征权重:

  • User Agent: 10%
  • Screen Resolution: 5%
  • Plugins: 10%
  • Timezone: 5%
  • Language: 5%
  • Canvas Fingerprint: 15%
  • WebGL Fingerprint: 15%
  • Audio Fingerprint: 15%
  • Network Information: 10%
  • Local IP via WebRTC: 10%
from flask import Flask, request, jsonify
import hashlib
import sqlite3

app = Flask(__name__)

# 创建数据库连接
def get_db_connection():
    conn = sqlite3.connect('fingerprints.db')
    conn.row_factory = sqlite3.Row
    return conn

# 创建表
def create_table():
    conn = get_db_connection()
    conn.execute('''
        CREATE TABLE IF NOT EXISTS fingerprints (
            id INTEGER PRIMARY KEY AUTOINCREMENT,
            user_agent TEXT,
            screen_resolution TEXT,
            plugins TEXT,
            timezone TEXT,
            language TEXT,
            canvas_fingerprint TEXT,
            webgl_fingerprint TEXT,
            audio_fingerprint TEXT,
            network_info TEXT,
            local_ip TEXT,
            anonymous_id TEXT
        )
    ''')
    conn.commit()
    conn.close()

# 计算特征相似度
def calculate_similarity(fingerprint1, fingerprint2, weights):
    score = 0
    total_weight = sum(weights.values())

    for key in weights:
        if fingerprint1.get(key) == fingerprint2.get(key):
            score += weights[key]

    return score / total_weight

@app.route('/api/fingerprint', methods=['POST'])
def fingerprint():
    data = request.json
    fingerprint = {
        'user_agent': data.get('user_agent'),
        'screen_resolution': data.get('screen_resolution'),
        'plugins': data.get('plugins'),
        'timezone': data.get('timezone'),
        'language': data.get('language'),
        'canvas_fingerprint': data.get('canvas_fingerprint'),
        'webgl_fingerprint': data.get('webgl_fingerprint'),
        'audio_fingerprint': data.get('audio_fingerprint'),
        'network_info': data.get('network_info'),
        'local_ip': data.get('local_ip')
    }

    weights = {
        'user_agent': 0.1,
        'screen_resolution': 0.05,
        'plugins': 0.1,
        'timezone': 0.05,
        'language': 0.05,
        'canvas_fingerprint': 0.15,
        'webgl_fingerprint': 0.15,
        'audio_fingerprint': 0.15,
        'network_info': 0.1,
        'local_ip': 0.1
    }

    conn = get_db_connection()
    cursor = conn.execute('SELECT * FROM fingerprints')
    rows = cursor.fetchall()

    matched_id = None
    highest_score = 0
    threshold = 0.7  # 设置一个阈值,超过此阈值则认为是同一用户

    for row in rows:
        db_fingerprint = {
            'user_agent': row['user_agent'],
            'screen_resolution': row['screen_resolution'],
            'plugins': row['plugins'],
            'timezone': row['timezone'],
            'language': row['language'],
            'canvas_fingerprint': row['canvas_fingerprint'],
            'webgl_fingerprint': row['webgl_fingerprint'],
            'audio_fingerprint': row['audio_fingerprint'],
            'network_info': row['network_info'],
            'local_ip': row['local_ip']
        }

        score = calculate_similarity(fingerprint, db_fingerprint, weights)
        if score > highest_score:
            highest_score = score
            matched_id = row['anonymous_id']

    if highest_score >= threshold:
        anonymous_id = matched_id
    else:
        anonymous_id = hashlib.md5((str(fingerprint) + str(highest_score)).encode()).hexdigest()
        conn.execute('INSERT INTO fingerprints (user_agent, screen_resolution, plugins, timezone, language, canvas_fingerprint, webgl_fingerprint, audio_fingerprint, network_info, local_ip, anonymous_id) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)',
                     (fingerprint['user_agent'], fingerprint['screen_resolution'], fingerprint['plugins'], fingerprint['timezone'], fingerprint['language'], fingerprint['canvas_fingerprint'], fingerprint['webgl_fingerprint'], fingerprint['audio_fingerprint'], fingerprint['network_info'], fingerprint['local_ip'], anonymous_id))
        conn.commit()

    conn.close()

    return jsonify({'anonymousId': anonymous_id})

if __name__ == '__main__':
    create_table()
    app.run()

相关文章

Read more

Flutter入门指南

Flutter入门指南

Flutter 是一个由 Google 开发的开源移动应用开发框架。它允许开发者使用一套代码同时构建 iOS 和 Android 应用,并且提供了丰富的 UI 组件和高效的开发工具,使得开发者能够快速构建出高性能的跨平台应用。 一、Flutter 的实现原理 Flutter 的核心在于其自带的高性能渲染引擎 Skia。不同于其他框架依赖于原生的 UI 组件,Flutter 直接通过 Skia 渲染引擎将所有组件绘制到屏幕上。这种方式保证了跨平台应用在 iOS 和 Android 上的表现完全一致。 1.1 结构概览 Flutter 的架构分为三层: 1. Framework(框架层): 这部分主要由 Dart 编写,提供了 Flutter 的各种 UI 组件(Widget)、手势检测、渲染层以及动画等。

By Lewis
Certbot Let's Encrypt 证书自动续期

Certbot Let's Encrypt 证书自动续期

安装 Certbot yum install epel-release -y yum install certbot -y certbot certonly //生成证书 certbot renew //续期 certbot certificates //查看证书 域名验证插件 https://github.com/ywdblog/certbot-letencrypt-wildcardcertificates-alydns-au 下载 $ git clone https://github.com/ywdblog/certbot-letencrypt-wildcardcertificates-alydns-au $ cd certbot-letencrypt-wildcardcertificates-alydns-au $ chmod 0777 au.sh 配置 DNS API 密钥: 这个 API 密钥什么意思呢?由于需要通过 API 操作阿里云 DNS,

By Lewis