浏览器指纹校验
parent
0f845df8dd
commit
6900cc8a25
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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) {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue