浏览器指纹校验
parent
0f845df8dd
commit
6900cc8a25
|
|
@ -5,7 +5,7 @@ import router from '@/router'
|
|||
import WHITELIST from "./whiteList"
|
||||
import moment from 'moment-timezone';
|
||||
import { encryptConfig } from "@/utils/encrypt"
|
||||
import { customAgent } from './fingerprint'
|
||||
import SystemInfo from "@/utils/systemInfo";
|
||||
const ROUTER = require('@/router');
|
||||
axios.defaults.withCredentials = false
|
||||
const service = axios.create({
|
||||
|
|
@ -27,8 +27,41 @@ service.interceptors.request.use(
|
|||
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['TimeZoneId'] = moment.tz.guess()
|
||||
let fingerprint = await customAgent()
|
||||
config.headers['BrowserFingerprint'] = fingerprint.visitorId
|
||||
const systemInfo = new SystemInfo();
|
||||
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) {
|
||||
try {
|
||||
config = await encryptConfig(config)
|
||||
|
|
|
|||
|
|
@ -466,6 +466,217 @@ class SystemInfo {
|
|||
|
||||
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) {
|
||||
|
|
|
|||
Loading…
Reference in New Issue