浏览器指纹校验

main
wangxiaoshuang 2026-01-16 11:36:10 +08:00
parent 0f845df8dd
commit 6900cc8a25
2 changed files with 247 additions and 3 deletions

View File

@ -5,7 +5,7 @@ import router from '@/router'
import WHITELIST from "./whiteList" import WHITELIST from "./whiteList"
import moment from 'moment-timezone'; import moment from 'moment-timezone';
import { encryptConfig } from "@/utils/encrypt" import { encryptConfig } from "@/utils/encrypt"
import { customAgent } from './fingerprint' import SystemInfo from "@/utils/systemInfo";
const ROUTER = require('@/router'); const ROUTER = require('@/router');
axios.defaults.withCredentials = false axios.defaults.withCredentials = false
const service = axios.create({ const service = axios.create({
@ -27,8 +27,41 @@ service.interceptors.request.use(
var language = zzSessionStorage.getItem('lang') var language = zzSessionStorage.getItem('lang')
config.headers['Accept-Language'] = language === 'en' ? 'en-US,en;q=0.5' : 'zh-CN,zh;q=0.9' config.headers['Accept-Language'] = language === 'en' ? 'en-US,en;q=0.5' : 'zh-CN,zh;q=0.9'
config.headers['TimeZoneId'] = moment.tz.guess() config.headers['TimeZoneId'] = moment.tz.guess()
let fingerprint = await customAgent() const systemInfo = new SystemInfo();
config.headers['BrowserFingerprint'] = fingerprint.visitorId const allInfo = systemInfo.getAllInfo();
let obj = {
browser: {
name: allInfo.browser.name,
version: allInfo.browser.version,
},
platform: allInfo.platform,
os: {
name: allInfo.os.name,
version: allInfo.os.version
},
hardware: {
logicalCores: allInfo.hardware.logicalCores,
deviceMemory: allInfo.hardware.deviceMemory
},
webgl: {
version: allInfo.webgl.version,
renderer: allInfo.webgl.renderer,
vendor: allInfo.webgl.vendor,
shadingLanguage: allInfo.webgl.shadingLanguage,
gpuType: {
type: allInfo.webgl.gpuType.type,
discrete: allInfo.webgl.gpuType.discrete,
},
performance: {
tier: allInfo.webgl.performance.tier,
},
extensions: {
length: allInfo.webgl.extensions.length,
}
}
}
let guid = await systemInfo.generateGuid(obj)
config.headers['BrowserFingerprint'] = guid
if (config.ENCRYPT) { if (config.ENCRYPT) {
try { try {
config = await encryptConfig(config) config = await encryptConfig(config)

View File

@ -466,6 +466,217 @@ class SystemInfo {
return html; return html;
} }
deepSortObject(obj) {
if (obj === null || typeof obj !== 'object') {
return obj;
}
if (Array.isArray(obj)) {
return obj.map(deepSortObject);
}
const sorted = {};
Object.keys(obj).sort().forEach(key => {
sorted[key] = this.deepSortObject(obj[key]);
});
return sorted;
}
getCanonicalString(obj) {
if (typeof obj !== 'object' || obj === null) {
return JSON.stringify(obj);
}
const sorted = this.deepSortObject(obj);
return JSON.stringify(sorted);
}
// 简单哈希函数
simpleHash(str) {
let hash = 0;
for (let i = 0; i < str.length; i++) {
const char = str.charCodeAt(i);
hash = ((hash << 5) - hash) + char;
hash = hash & hash;
}
return hash;
}
// 简单SHA-256模拟
simpleSHA256(str) {
let hash = 0;
for (let i = 0; i < str.length; i++) {
const char = str.charCodeAt(i);
hash = ((hash << 5) - hash) + char;
hash = hash & hash;
}
const hashArray = [];
for (let i = 0; i < 8; i++) {
hashArray[i] = (hash + i * 2654435761) >>> 0;
}
return hashArray;
}
// 格式化哈希为GUID
formatHashAsGuid(hashArray) {
const hexParts = hashArray.map(h => h.toString(16).padStart(8, '0'));
return `${hexParts[0]}${hexParts[1].substring(0, 4)}-${hexParts[1].substring(4)}-${hexParts[2].substring(0, 4)}-${hexParts[3].substring(0, 4)}-${hexParts[3].substring(4)}${hexParts[4]}${hexParts[5]}`;
}
// 1. 确定性哈希算法
objectToGuidDeterministic(obj) {
const canonicalString = this.getCanonicalString(obj);
const hash = this.simpleSHA256(canonicalString);
return this.formatHashAsGuid(hash).toUpperCase();
}
// 2. 伪随机算法
getSeedFromObject(obj) {
const str = JSON.stringify(obj);
return this.simpleHash(str);
}
createSeededRandom(seed) {
let state = seed;
return function () {
state = (state * 1664525 + 1013904223) >>> 0;
return (state & 0x3FFFFFFF) / 0x3FFFFFFF;
};
}
generateVersion4Guid(randomFn) {
let guid = '';
for (let i = 0; i < 32; i++) {
if (i === 8 || i === 12 || i === 16 || i === 20) {
guid += '-';
}
if (i === 12) {
guid += '4';
} else if (i === 16) {
const variant = Math.floor(randomFn() * 4);
guid += (8 + variant).toString(16).toUpperCase();
} else {
const randomHex = Math.floor(randomFn() * 16).toString(16);
guid += randomHex;
}
}
return guid.toUpperCase();
}
objectToGuidPseudorandom(obj) {
const seed = this.getSeedFromObject(obj);
const prng = this.createSeededRandom(seed);
return this.generateVersion4Guid(prng);
}
// 3. Crypto API算法同步版本
objectToGuidCryptoSync(obj) {
try {
const str = this.getCanonicalString(obj);
let hash = 0;
for (let i = 0; i < str.length; i++) {
const char = str.charCodeAt(i);
hash = ((hash << 5) - hash) + char;
hash = hash & hash;
}
const bytes = new Array(16);
for (let i = 0; i < 16; i++) {
bytes[i] = (hash + i * 2654435761) & 0xFF;
}
bytes[6] = (bytes[6] & 0x0F) | 0x40;
bytes[8] = (bytes[8] & 0x3F) | 0x80;
return bytes.map(b => b.toString(16).padStart(2, '0'))
.join('')
.replace(/(.{8})(.{4})(.{4})(.{4})(.{12})/, '$1-$2-$3-$4-$5')
.toUpperCase();
} catch (error) {
return this.objectToGuidDeterministic(obj);
}
}
// 4. 组合算法
combineComponents(deterministicHash, namespaceHash, timestamp, randomComponent) {
const hashDigits = deterministicHash.replace(/-/g, '');
const bytes = new Array(16);
for (let i = 0; i < 16; i++) {
const hashByte = parseInt(hashDigits.substr(i * 2, 2), 16) || 0;
const nsByte = (namespaceHash >> (i * 2)) & 0xFF;
const timeByte = (timestamp >> (i * 2)) & 0xFF;
const randomByte = parseInt(randomComponent.substr(i % 8, 1), 16) || 0;
bytes[i] = (hashByte ^ nsByte ^ timeByte ^ randomByte) & 0xFF;
}
bytes[6] = (bytes[6] & 0x0F) | 0x40;
bytes[8] = (bytes[8] & 0x3F) | 0x80;
return bytes.map(b => b.toString(16).padStart(2, '0'))
.join('')
.replace(/(.{8})(.{4})(.{4})(.{4})(.{12})/, '$1-$2-$3-$4-$5')
.toUpperCase();
}
objectToGuidCombined(obj, namespace = '') {
const deterministicHash = this.objectToGuidDeterministic(obj);
const namespaceHash = namespace ? this.simpleHash(namespace) : 0;
const timestamp = Date.now();
const randomComponent = Math.random().toString(16).substr(2, 8);
return this.combineComponents(deterministicHash, namespaceHash, timestamp, randomComponent);
}
// 主生成函数
async generateGuid(inputText, inputType, algorithmType = 'deterministic') {
let obj;
try {
if (inputType === 'json') {
obj = JSON.parse(inputText);
} else {
obj = inputText
}
} catch (error) {
return error;
}
let guid;
let algorithmName;
try {
switch (algorithmType) {
case 'deterministic':
guid = this.objectToGuidDeterministic(obj);
algorithmName = '确定性哈希算法';
break;
case 'pseudorandom':
guid = this.objectToGuidPseudorandom(obj);
algorithmName = '伪随机算法';
break;
case 'crypto':
guid = this.objectToGuidCryptoSync(obj);
algorithmName = 'Crypto API算法';
break;
case 'combined':
guid = this.objectToGuidCombined(obj, 'example-namespace');
algorithmName = '组合算法';
break;
default:
guid = '未知算法';
algorithmName = '未知';
}
return guid;
} catch (error) {
return error
}
}
} }
if (typeof module !== 'undefined' && module.exports) { if (typeof module !== 'undefined' && module.exports) {