@aientrophy/sdk 0.3.1 → 0.3.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/anti-debug-BWiEU1_V.cjs +1 -0
- package/dist/{anti-debug-CRuvY4WC.js → anti-debug-Cf0ePnTv.js} +65 -0
- package/dist/console-DYd8RaPC.cjs +1 -0
- package/dist/{console-DbZZ4Ctg.js → console-n38-3CrG.js} +2 -1
- package/dist/core.js +1 -1
- package/dist/npm/index.cjs.js +1 -1
- package/dist/npm/index.es.js +528 -3
- package/dist/sri-hashes.json +2 -2
- package/dist/types/core/index.d.ts +2 -0
- package/dist/types/detectors/ScriptInjectionDetector.d.ts +56 -0
- package/dist/types/detectors/WorkerIntegrityDetector.d.ts +26 -0
- package/dist/types/protection/anti-debug.d.ts +7 -0
- package/package.json +1 -1
- package/dist/anti-debug-CYwG4s7P.cjs +0 -1
- package/dist/console-aIpHQlgP.cjs +0 -1
- package/dist/index.d.ts +0 -21
package/dist/npm/index.es.js
CHANGED
|
@@ -211,7 +211,9 @@ const THREAT_EVENTS = /* @__PURE__ */ new Set([
|
|
|
211
211
|
"init_signals",
|
|
212
212
|
"automation_detected",
|
|
213
213
|
"cross_context_mismatch",
|
|
214
|
-
"headless_probe"
|
|
214
|
+
"headless_probe",
|
|
215
|
+
"script_injection",
|
|
216
|
+
"worker_integrity"
|
|
215
217
|
]);
|
|
216
218
|
class CallbackManager {
|
|
217
219
|
constructor() {
|
|
@@ -2360,6 +2362,516 @@ class HeadlessProbeDetector {
|
|
|
2360
2362
|
});
|
|
2361
2363
|
}
|
|
2362
2364
|
}
|
|
2365
|
+
class ScriptInjectionDetector {
|
|
2366
|
+
constructor(transmitter) {
|
|
2367
|
+
__publicField(this, "transmitter");
|
|
2368
|
+
__publicField(this, "hasRun", false);
|
|
2369
|
+
__publicField(this, "injectedScriptCount", 0);
|
|
2370
|
+
__publicField(this, "cspViolations", []);
|
|
2371
|
+
this.transmitter = transmitter;
|
|
2372
|
+
}
|
|
2373
|
+
start() {
|
|
2374
|
+
if (this.hasRun || typeof window === "undefined") return;
|
|
2375
|
+
this.hasRun = true;
|
|
2376
|
+
this.startDOMObserver();
|
|
2377
|
+
this.startCSPMonitor();
|
|
2378
|
+
setTimeout(() => this.detect(), 1500);
|
|
2379
|
+
}
|
|
2380
|
+
detect() {
|
|
2381
|
+
const signals = {};
|
|
2382
|
+
let score = 0;
|
|
2383
|
+
try {
|
|
2384
|
+
const nativeIntegrity = this.checkNativeFunctionIntegrity();
|
|
2385
|
+
if (nativeIntegrity.issues.length > 0) {
|
|
2386
|
+
signals.nativeFunctionIntegrity = nativeIntegrity.issues;
|
|
2387
|
+
score += 25;
|
|
2388
|
+
}
|
|
2389
|
+
} catch (e) {
|
|
2390
|
+
}
|
|
2391
|
+
try {
|
|
2392
|
+
const overrides = this.checkPropertyOverrides();
|
|
2393
|
+
if (overrides.issues.length > 0) {
|
|
2394
|
+
signals.propertyOverrides = overrides.issues;
|
|
2395
|
+
score += 30;
|
|
2396
|
+
}
|
|
2397
|
+
} catch (e) {
|
|
2398
|
+
}
|
|
2399
|
+
if (this.injectedScriptCount > 0) {
|
|
2400
|
+
signals.domScriptInjection = {
|
|
2401
|
+
count: this.injectedScriptCount
|
|
2402
|
+
};
|
|
2403
|
+
score += 20;
|
|
2404
|
+
}
|
|
2405
|
+
if (this.cspViolations.length > 0) {
|
|
2406
|
+
signals.cspViolations = this.cspViolations.slice(0, 10);
|
|
2407
|
+
score += 15;
|
|
2408
|
+
}
|
|
2409
|
+
try {
|
|
2410
|
+
const globals = this.checkGlobalPollution();
|
|
2411
|
+
if (globals.length > 0) {
|
|
2412
|
+
signals.globalPollution = globals;
|
|
2413
|
+
score += 20;
|
|
2414
|
+
}
|
|
2415
|
+
} catch (e) {
|
|
2416
|
+
}
|
|
2417
|
+
try {
|
|
2418
|
+
const protoIssues = this.checkPrototypeIntegrity();
|
|
2419
|
+
if (protoIssues.length > 0) {
|
|
2420
|
+
signals.prototypeIntegrity = protoIssues;
|
|
2421
|
+
score += 20;
|
|
2422
|
+
}
|
|
2423
|
+
} catch (e) {
|
|
2424
|
+
}
|
|
2425
|
+
if (score > 0) {
|
|
2426
|
+
this.transmitter.send("script_injection", {
|
|
2427
|
+
signals,
|
|
2428
|
+
score,
|
|
2429
|
+
timestamp: Date.now()
|
|
2430
|
+
});
|
|
2431
|
+
}
|
|
2432
|
+
}
|
|
2433
|
+
/**
|
|
2434
|
+
* 1. Native Function Integrity
|
|
2435
|
+
* Checks if navigator.webdriver descriptor, navigator getters, and
|
|
2436
|
+
* Function.prototype.toString have been tampered with.
|
|
2437
|
+
*/
|
|
2438
|
+
checkNativeFunctionIntegrity() {
|
|
2439
|
+
const issues = [];
|
|
2440
|
+
try {
|
|
2441
|
+
const desc = Object.getOwnPropertyDescriptor(navigator, "webdriver");
|
|
2442
|
+
if (desc) {
|
|
2443
|
+
if (desc.configurable === true) {
|
|
2444
|
+
issues.push("webdriver_descriptor_configurable");
|
|
2445
|
+
}
|
|
2446
|
+
if (desc.get) {
|
|
2447
|
+
const getterStr = Function.prototype.toString.call(desc.get);
|
|
2448
|
+
if (!/\[native code\]/.test(getterStr)) {
|
|
2449
|
+
issues.push("webdriver_non_native_getter");
|
|
2450
|
+
}
|
|
2451
|
+
}
|
|
2452
|
+
}
|
|
2453
|
+
} catch (e) {
|
|
2454
|
+
}
|
|
2455
|
+
try {
|
|
2456
|
+
const propsToCheck = ["userAgent", "platform", "languages", "hardwareConcurrency"];
|
|
2457
|
+
for (const prop of propsToCheck) {
|
|
2458
|
+
const protoDesc = Object.getOwnPropertyDescriptor(Navigator.prototype, prop);
|
|
2459
|
+
if (protoDesc && protoDesc.get) {
|
|
2460
|
+
const getterStr = Function.prototype.toString.call(protoDesc.get);
|
|
2461
|
+
if (!/\[native code\]/.test(getterStr)) {
|
|
2462
|
+
issues.push(`navigator_${prop}_non_native`);
|
|
2463
|
+
}
|
|
2464
|
+
}
|
|
2465
|
+
}
|
|
2466
|
+
} catch (e) {
|
|
2467
|
+
}
|
|
2468
|
+
try {
|
|
2469
|
+
const toStringStr = Function.prototype.toString.call(Function.prototype.toString);
|
|
2470
|
+
if (!/\[native code\]/.test(toStringStr)) {
|
|
2471
|
+
issues.push("function_tostring_overridden");
|
|
2472
|
+
}
|
|
2473
|
+
} catch (e) {
|
|
2474
|
+
}
|
|
2475
|
+
return { issues };
|
|
2476
|
+
}
|
|
2477
|
+
/**
|
|
2478
|
+
* 2. Property Override Detection
|
|
2479
|
+
* Checks for Object.defineProperty abuse on navigator,
|
|
2480
|
+
* proxy wrappers, and spoofed navigator.plugins.
|
|
2481
|
+
*/
|
|
2482
|
+
checkPropertyOverrides() {
|
|
2483
|
+
const issues = [];
|
|
2484
|
+
try {
|
|
2485
|
+
const navigatorStr = Object.prototype.toString.call(navigator);
|
|
2486
|
+
if (navigatorStr !== "[object Navigator]") {
|
|
2487
|
+
issues.push("navigator_proxy_or_spoofed");
|
|
2488
|
+
}
|
|
2489
|
+
} catch (e) {
|
|
2490
|
+
}
|
|
2491
|
+
try {
|
|
2492
|
+
if (navigator.plugins) {
|
|
2493
|
+
const pluginsStr = Object.prototype.toString.call(navigator.plugins);
|
|
2494
|
+
if (pluginsStr !== "[object PluginArray]") {
|
|
2495
|
+
issues.push("plugins_spoofed");
|
|
2496
|
+
}
|
|
2497
|
+
if (Array.isArray(navigator.plugins)) {
|
|
2498
|
+
issues.push("plugins_is_array");
|
|
2499
|
+
}
|
|
2500
|
+
}
|
|
2501
|
+
} catch (e) {
|
|
2502
|
+
}
|
|
2503
|
+
try {
|
|
2504
|
+
if (navigator.mimeTypes) {
|
|
2505
|
+
const mimeStr = Object.prototype.toString.call(navigator.mimeTypes);
|
|
2506
|
+
if (mimeStr !== "[object MimeTypeArray]") {
|
|
2507
|
+
issues.push("mimetypes_spoofed");
|
|
2508
|
+
}
|
|
2509
|
+
}
|
|
2510
|
+
} catch (e) {
|
|
2511
|
+
}
|
|
2512
|
+
try {
|
|
2513
|
+
const descStr = Function.prototype.toString.call(Object.getOwnPropertyDescriptor);
|
|
2514
|
+
if (!/\[native code\]/.test(descStr)) {
|
|
2515
|
+
issues.push("getOwnPropertyDescriptor_overridden");
|
|
2516
|
+
}
|
|
2517
|
+
} catch (e) {
|
|
2518
|
+
}
|
|
2519
|
+
return { issues };
|
|
2520
|
+
}
|
|
2521
|
+
/**
|
|
2522
|
+
* 3. DOM Script Injection Monitoring
|
|
2523
|
+
* Sets up MutationObserver to watch for dynamically added <script> tags.
|
|
2524
|
+
*/
|
|
2525
|
+
startDOMObserver() {
|
|
2526
|
+
try {
|
|
2527
|
+
if (typeof MutationObserver === "undefined") return;
|
|
2528
|
+
const observer = new MutationObserver((mutations) => {
|
|
2529
|
+
for (const mutation of mutations) {
|
|
2530
|
+
for (let i = 0; i < mutation.addedNodes.length; i++) {
|
|
2531
|
+
const node = mutation.addedNodes[i];
|
|
2532
|
+
if (node.nodeName === "SCRIPT") {
|
|
2533
|
+
const script = node;
|
|
2534
|
+
if (!script.src) {
|
|
2535
|
+
this.injectedScriptCount++;
|
|
2536
|
+
}
|
|
2537
|
+
}
|
|
2538
|
+
}
|
|
2539
|
+
}
|
|
2540
|
+
});
|
|
2541
|
+
observer.observe(document.documentElement, {
|
|
2542
|
+
childList: true,
|
|
2543
|
+
subtree: true
|
|
2544
|
+
});
|
|
2545
|
+
setTimeout(() => {
|
|
2546
|
+
try {
|
|
2547
|
+
observer.disconnect();
|
|
2548
|
+
} catch (e) {
|
|
2549
|
+
}
|
|
2550
|
+
}, 1e4);
|
|
2551
|
+
} catch (e) {
|
|
2552
|
+
}
|
|
2553
|
+
}
|
|
2554
|
+
/**
|
|
2555
|
+
* 4. CSP Violation Monitoring
|
|
2556
|
+
* Listens for securitypolicyviolation events indicating injection attempts.
|
|
2557
|
+
*/
|
|
2558
|
+
startCSPMonitor() {
|
|
2559
|
+
try {
|
|
2560
|
+
const handler = (event) => {
|
|
2561
|
+
try {
|
|
2562
|
+
const entry = `${event.violatedDirective}|${event.blockedURI || "inline"}`;
|
|
2563
|
+
this.cspViolations.push(entry);
|
|
2564
|
+
} catch (e) {
|
|
2565
|
+
}
|
|
2566
|
+
};
|
|
2567
|
+
document.addEventListener("securitypolicyviolation", handler);
|
|
2568
|
+
setTimeout(() => {
|
|
2569
|
+
try {
|
|
2570
|
+
document.removeEventListener("securitypolicyviolation", handler);
|
|
2571
|
+
} catch (e) {
|
|
2572
|
+
}
|
|
2573
|
+
}, 1e4);
|
|
2574
|
+
} catch (e) {
|
|
2575
|
+
}
|
|
2576
|
+
}
|
|
2577
|
+
/**
|
|
2578
|
+
* 5. Global Variable Pollution
|
|
2579
|
+
* Checks for known automation framework globals and CDP-injected patterns.
|
|
2580
|
+
*/
|
|
2581
|
+
checkGlobalPollution() {
|
|
2582
|
+
const found = [];
|
|
2583
|
+
const w = window;
|
|
2584
|
+
const d = document;
|
|
2585
|
+
const checks = [
|
|
2586
|
+
["__webdriver_evaluate", () => !!d.__webdriver_evaluate],
|
|
2587
|
+
["__selenium_evaluate", () => !!d.__selenium_evaluate],
|
|
2588
|
+
["__webdriver_script_function", () => !!d.__webdriver_script_function],
|
|
2589
|
+
["__webdriver_script_func", () => !!d.__webdriver_script_func],
|
|
2590
|
+
["__webdriver_script_fn", () => !!d.__webdriver_script_fn],
|
|
2591
|
+
["_Selenium_IDE_Recorder", () => !!w._Selenium_IDE_Recorder],
|
|
2592
|
+
["__lastWatirAlert", () => !!w.__lastWatirAlert],
|
|
2593
|
+
["__lastWatirConfirm", () => !!w.__lastWatirConfirm],
|
|
2594
|
+
["__lastWatirPrompt", () => !!w.__lastWatirPrompt],
|
|
2595
|
+
["_phantom", () => !!w._phantom],
|
|
2596
|
+
["callPhantom", () => !!w.callPhantom],
|
|
2597
|
+
["__nightmare", () => !!w.__nightmare],
|
|
2598
|
+
// Buffer and process should not exist in browser context
|
|
2599
|
+
["Buffer", () => typeof w.Buffer === "function" && typeof w.Buffer.alloc === "function"],
|
|
2600
|
+
["process", () => !!w.process && !!w.process.versions],
|
|
2601
|
+
// global redefined (in normal browsers, window.global is undefined)
|
|
2602
|
+
["global_redefined", () => !!w.global && w.global !== w && typeof w.global === "object"],
|
|
2603
|
+
// emit on window (frameworks sometimes attach this)
|
|
2604
|
+
["window_emit", () => typeof w.emit === "function"]
|
|
2605
|
+
];
|
|
2606
|
+
for (const [name, check] of checks) {
|
|
2607
|
+
try {
|
|
2608
|
+
if (check()) found.push(name);
|
|
2609
|
+
} catch (e) {
|
|
2610
|
+
}
|
|
2611
|
+
}
|
|
2612
|
+
try {
|
|
2613
|
+
const keys = Object.keys(document);
|
|
2614
|
+
for (const key of keys) {
|
|
2615
|
+
if (/^cdc_|^__cdc_/.test(key)) {
|
|
2616
|
+
found.push(`cdc:${key}`);
|
|
2617
|
+
}
|
|
2618
|
+
}
|
|
2619
|
+
} catch (e) {
|
|
2620
|
+
}
|
|
2621
|
+
try {
|
|
2622
|
+
const wKeys = Object.keys(window);
|
|
2623
|
+
for (const key of wKeys) {
|
|
2624
|
+
if (/^cdc_|^__cdc_/.test(key)) {
|
|
2625
|
+
found.push(`cdc_window:${key}`);
|
|
2626
|
+
}
|
|
2627
|
+
}
|
|
2628
|
+
} catch (e) {
|
|
2629
|
+
}
|
|
2630
|
+
return found;
|
|
2631
|
+
}
|
|
2632
|
+
/**
|
|
2633
|
+
* 6. Prototype Chain Integrity
|
|
2634
|
+
* Verifies HTMLElement.prototype, document.createElement, and Event constructor.
|
|
2635
|
+
*/
|
|
2636
|
+
checkPrototypeIntegrity() {
|
|
2637
|
+
const issues = [];
|
|
2638
|
+
try {
|
|
2639
|
+
const htmlProto = HTMLElement.prototype;
|
|
2640
|
+
const htmlProtoKeys = Object.getOwnPropertyNames(htmlProto);
|
|
2641
|
+
for (const key of htmlProtoKeys) {
|
|
2642
|
+
if (/^__selenium|^__webdriver|^__playwright|^__puppeteer/.test(key)) {
|
|
2643
|
+
issues.push(`htmlelement_proto_${key}`);
|
|
2644
|
+
}
|
|
2645
|
+
}
|
|
2646
|
+
} catch (e) {
|
|
2647
|
+
}
|
|
2648
|
+
try {
|
|
2649
|
+
const div = document.createElement("div");
|
|
2650
|
+
if (!(div instanceof HTMLDivElement)) {
|
|
2651
|
+
issues.push("createElement_not_genuine");
|
|
2652
|
+
}
|
|
2653
|
+
const divStr = Object.prototype.toString.call(div);
|
|
2654
|
+
if (divStr !== "[object HTMLDivElement]") {
|
|
2655
|
+
issues.push("createElement_wrong_tostring");
|
|
2656
|
+
}
|
|
2657
|
+
} catch (e) {
|
|
2658
|
+
}
|
|
2659
|
+
try {
|
|
2660
|
+
const evt = new Event("test");
|
|
2661
|
+
if (!(evt instanceof Event)) {
|
|
2662
|
+
issues.push("event_not_instance");
|
|
2663
|
+
}
|
|
2664
|
+
const evtStr = Object.prototype.toString.call(evt);
|
|
2665
|
+
if (evtStr !== "[object Event]") {
|
|
2666
|
+
issues.push("event_wrong_prototype");
|
|
2667
|
+
}
|
|
2668
|
+
} catch (e) {
|
|
2669
|
+
}
|
|
2670
|
+
try {
|
|
2671
|
+
const createStr = Function.prototype.toString.call(document.createElement);
|
|
2672
|
+
if (!/\[native code\]/.test(createStr)) {
|
|
2673
|
+
issues.push("createElement_overridden");
|
|
2674
|
+
}
|
|
2675
|
+
} catch (e) {
|
|
2676
|
+
}
|
|
2677
|
+
return issues;
|
|
2678
|
+
}
|
|
2679
|
+
}
|
|
2680
|
+
class WorkerIntegrityDetector {
|
|
2681
|
+
constructor(transmitter) {
|
|
2682
|
+
__publicField(this, "transmitter");
|
|
2683
|
+
__publicField(this, "hasRun", false);
|
|
2684
|
+
this.transmitter = transmitter;
|
|
2685
|
+
}
|
|
2686
|
+
start() {
|
|
2687
|
+
if (this.hasRun || typeof window === "undefined") return;
|
|
2688
|
+
this.hasRun = true;
|
|
2689
|
+
setTimeout(() => this.detect(), 2e3);
|
|
2690
|
+
}
|
|
2691
|
+
async detect() {
|
|
2692
|
+
try {
|
|
2693
|
+
if (typeof Worker === "undefined" || typeof Blob === "undefined") return;
|
|
2694
|
+
const mainValues = {
|
|
2695
|
+
webdriver: !!navigator.webdriver,
|
|
2696
|
+
userAgent: navigator.userAgent || "",
|
|
2697
|
+
platform: navigator.platform || "",
|
|
2698
|
+
languages: JSON.stringify(navigator.languages || []),
|
|
2699
|
+
hardwareConcurrency: navigator.hardwareConcurrency || 0,
|
|
2700
|
+
dateNow: Date.now(),
|
|
2701
|
+
perfNow: performance.now(),
|
|
2702
|
+
toStringNative: false
|
|
2703
|
+
};
|
|
2704
|
+
try {
|
|
2705
|
+
mainValues.toStringNative = /\[native code\]/.test(
|
|
2706
|
+
Function.prototype.toString.call(Array.prototype.push)
|
|
2707
|
+
);
|
|
2708
|
+
} catch (_e) {
|
|
2709
|
+
mainValues.toStringNative = false;
|
|
2710
|
+
}
|
|
2711
|
+
const workerResult = await this.runWorker(mainValues);
|
|
2712
|
+
if (!workerResult) return;
|
|
2713
|
+
const signals = {};
|
|
2714
|
+
let score = 0;
|
|
2715
|
+
const navMismatches = [];
|
|
2716
|
+
if (!mainValues.webdriver && workerResult.webdriver === true) {
|
|
2717
|
+
navMismatches.push("webdriver_spoofed");
|
|
2718
|
+
score += 40;
|
|
2719
|
+
} else if (workerResult.webdriver !== mainValues.webdriver) {
|
|
2720
|
+
navMismatches.push("webdriver_mismatch");
|
|
2721
|
+
score += 30;
|
|
2722
|
+
}
|
|
2723
|
+
if (workerResult.userAgent !== mainValues.userAgent) {
|
|
2724
|
+
navMismatches.push("userAgent_mismatch");
|
|
2725
|
+
score += 30;
|
|
2726
|
+
}
|
|
2727
|
+
if (workerResult.platform !== mainValues.platform) {
|
|
2728
|
+
navMismatches.push("platform_mismatch");
|
|
2729
|
+
score += 30;
|
|
2730
|
+
}
|
|
2731
|
+
if (workerResult.languages !== mainValues.languages) {
|
|
2732
|
+
navMismatches.push("languages_mismatch");
|
|
2733
|
+
score += 30;
|
|
2734
|
+
}
|
|
2735
|
+
if (workerResult.hardwareConcurrency !== mainValues.hardwareConcurrency) {
|
|
2736
|
+
navMismatches.push("hardwareConcurrency_mismatch");
|
|
2737
|
+
score += 30;
|
|
2738
|
+
}
|
|
2739
|
+
if (navMismatches.length > 0) {
|
|
2740
|
+
signals.navigatorMismatch = navMismatches;
|
|
2741
|
+
}
|
|
2742
|
+
const benchmarkMs = workerResult.benchmarkMs;
|
|
2743
|
+
if (typeof benchmarkMs === "number") {
|
|
2744
|
+
if (benchmarkMs < 1 || benchmarkMs > 500) {
|
|
2745
|
+
signals.benchmarkAnomaly = {
|
|
2746
|
+
benchmarkMs,
|
|
2747
|
+
reason: benchmarkMs < 1 ? "abnormally_fast" : "abnormally_slow"
|
|
2748
|
+
};
|
|
2749
|
+
score += 20;
|
|
2750
|
+
}
|
|
2751
|
+
}
|
|
2752
|
+
if (workerResult.cryptoEntropy === false) {
|
|
2753
|
+
signals.cryptoMock = {
|
|
2754
|
+
entropy: false,
|
|
2755
|
+
values: workerResult.cryptoValues
|
|
2756
|
+
};
|
|
2757
|
+
score += 15;
|
|
2758
|
+
}
|
|
2759
|
+
const timeDelta = Math.abs(workerResult.dateNow - mainValues.dateNow);
|
|
2760
|
+
if (timeDelta > 1e3) {
|
|
2761
|
+
signals.timeManipulation = {
|
|
2762
|
+
mainDateNow: mainValues.dateNow,
|
|
2763
|
+
workerDateNow: workerResult.dateNow,
|
|
2764
|
+
deltaMs: timeDelta
|
|
2765
|
+
};
|
|
2766
|
+
score += 15;
|
|
2767
|
+
}
|
|
2768
|
+
if (!workerResult.toStringNative || !mainValues.toStringNative) {
|
|
2769
|
+
const toStringSignals = [];
|
|
2770
|
+
if (!workerResult.toStringNative) toStringSignals.push("worker_tampered");
|
|
2771
|
+
if (!mainValues.toStringNative) toStringSignals.push("main_tampered");
|
|
2772
|
+
signals.toStringTampering = toStringSignals;
|
|
2773
|
+
score += 20;
|
|
2774
|
+
}
|
|
2775
|
+
if (score > 0) {
|
|
2776
|
+
this.transmitter.send("worker_integrity", {
|
|
2777
|
+
signals,
|
|
2778
|
+
score,
|
|
2779
|
+
timestamp: Date.now()
|
|
2780
|
+
});
|
|
2781
|
+
}
|
|
2782
|
+
} catch (_e) {
|
|
2783
|
+
}
|
|
2784
|
+
}
|
|
2785
|
+
/**
|
|
2786
|
+
* Spawn an inline Web Worker via Blob URL and collect integrity signals.
|
|
2787
|
+
* Returns null if Worker is not supported or times out.
|
|
2788
|
+
*/
|
|
2789
|
+
runWorker(mainValues) {
|
|
2790
|
+
return new Promise((resolve) => {
|
|
2791
|
+
try {
|
|
2792
|
+
const workerCode = `
|
|
2793
|
+
self.onmessage = function(e) {
|
|
2794
|
+
var results = {};
|
|
2795
|
+
|
|
2796
|
+
// 1. Navigator check
|
|
2797
|
+
try {
|
|
2798
|
+
results.webdriver = !!navigator.webdriver;
|
|
2799
|
+
results.userAgent = navigator.userAgent || '';
|
|
2800
|
+
results.platform = navigator.platform || '';
|
|
2801
|
+
results.languages = JSON.stringify(navigator.languages || []);
|
|
2802
|
+
results.hardwareConcurrency = navigator.hardwareConcurrency || 0;
|
|
2803
|
+
} catch(ex) {
|
|
2804
|
+
results.webdriver = false;
|
|
2805
|
+
results.userAgent = '';
|
|
2806
|
+
results.platform = '';
|
|
2807
|
+
results.languages = '[]';
|
|
2808
|
+
results.hardwareConcurrency = 0;
|
|
2809
|
+
}
|
|
2810
|
+
|
|
2811
|
+
// 2. Performance benchmark
|
|
2812
|
+
try {
|
|
2813
|
+
var start = performance.now();
|
|
2814
|
+
var sum = 0;
|
|
2815
|
+
for (var i = 0; i < 1000000; i++) sum += i;
|
|
2816
|
+
results.benchmarkMs = performance.now() - start;
|
|
2817
|
+
} catch(ex) {
|
|
2818
|
+
results.benchmarkMs = -1;
|
|
2819
|
+
}
|
|
2820
|
+
|
|
2821
|
+
// 3. Crypto check
|
|
2822
|
+
try {
|
|
2823
|
+
var arr = new Uint32Array(4);
|
|
2824
|
+
crypto.getRandomValues(arr);
|
|
2825
|
+
results.cryptoEntropy = arr[0] !== arr[1] && arr[1] !== arr[2] && arr[0] !== 0;
|
|
2826
|
+
results.cryptoValues = Array.from(arr);
|
|
2827
|
+
} catch(ex) {
|
|
2828
|
+
results.cryptoEntropy = false;
|
|
2829
|
+
results.cryptoValues = [];
|
|
2830
|
+
}
|
|
2831
|
+
|
|
2832
|
+
// 4. Time check
|
|
2833
|
+
results.dateNow = Date.now();
|
|
2834
|
+
results.perfNow = performance.now();
|
|
2835
|
+
|
|
2836
|
+
// 5. toString integrity
|
|
2837
|
+
try {
|
|
2838
|
+
results.toStringNative = /\\[native code\\]/.test(
|
|
2839
|
+
Function.prototype.toString.call(Array.prototype.push)
|
|
2840
|
+
);
|
|
2841
|
+
} catch(ex) {
|
|
2842
|
+
results.toStringNative = false;
|
|
2843
|
+
}
|
|
2844
|
+
|
|
2845
|
+
self.postMessage(results);
|
|
2846
|
+
};
|
|
2847
|
+
`;
|
|
2848
|
+
const blob = new Blob([workerCode], { type: "application/javascript" });
|
|
2849
|
+
const url = URL.createObjectURL(blob);
|
|
2850
|
+
const worker = new Worker(url);
|
|
2851
|
+
const timeout = setTimeout(() => {
|
|
2852
|
+
worker.terminate();
|
|
2853
|
+
URL.revokeObjectURL(url);
|
|
2854
|
+
resolve(null);
|
|
2855
|
+
}, 5e3);
|
|
2856
|
+
worker.onmessage = (e) => {
|
|
2857
|
+
clearTimeout(timeout);
|
|
2858
|
+
worker.terminate();
|
|
2859
|
+
URL.revokeObjectURL(url);
|
|
2860
|
+
resolve(e.data);
|
|
2861
|
+
};
|
|
2862
|
+
worker.onerror = () => {
|
|
2863
|
+
clearTimeout(timeout);
|
|
2864
|
+
worker.terminate();
|
|
2865
|
+
URL.revokeObjectURL(url);
|
|
2866
|
+
resolve(null);
|
|
2867
|
+
};
|
|
2868
|
+
worker.postMessage({ mainValues });
|
|
2869
|
+
} catch (_e) {
|
|
2870
|
+
resolve(null);
|
|
2871
|
+
}
|
|
2872
|
+
});
|
|
2873
|
+
}
|
|
2874
|
+
}
|
|
2363
2875
|
const COOKIE_NAME = "__aie_token";
|
|
2364
2876
|
const RENEWAL_MARGIN_MS = 5 * 60 * 1e3;
|
|
2365
2877
|
class CrawlProtect {
|
|
@@ -2541,6 +3053,8 @@ class SecuritySDK {
|
|
|
2541
3053
|
__publicField(this, "cloudEnvironmentDetector");
|
|
2542
3054
|
__publicField(this, "crossContextDetector");
|
|
2543
3055
|
__publicField(this, "headlessProbeDetector");
|
|
3056
|
+
__publicField(this, "scriptInjectionDetector");
|
|
3057
|
+
__publicField(this, "workerIntegrityDetector");
|
|
2544
3058
|
__publicField(this, "crawlProtect", null);
|
|
2545
3059
|
__publicField(this, "initialized", false);
|
|
2546
3060
|
__publicField(this, "wasmService");
|
|
@@ -2562,6 +3076,8 @@ class SecuritySDK {
|
|
|
2562
3076
|
this.cloudEnvironmentDetector = new CloudEnvironmentDetector(this.transmitter);
|
|
2563
3077
|
this.crossContextDetector = new CrossContextDetector(this.transmitter);
|
|
2564
3078
|
this.headlessProbeDetector = new HeadlessProbeDetector(this.transmitter);
|
|
3079
|
+
this.scriptInjectionDetector = new ScriptInjectionDetector(this.transmitter);
|
|
3080
|
+
this.workerIntegrityDetector = new WorkerIntegrityDetector(this.transmitter);
|
|
2565
3081
|
}
|
|
2566
3082
|
async init(config) {
|
|
2567
3083
|
var _a, _b;
|
|
@@ -2583,9 +3099,16 @@ class SecuritySDK {
|
|
|
2583
3099
|
}
|
|
2584
3100
|
const devtoolsEnabled = ((_b = config.serverConfig) == null ? void 0 : _b.devtoolsDetection) ?? !config.debug;
|
|
2585
3101
|
if (devtoolsEnabled) {
|
|
2586
|
-
import("../anti-debug-
|
|
3102
|
+
import("../anti-debug-Cf0ePnTv.js").then(({ AntiDebug }) => {
|
|
2587
3103
|
AntiDebug.start();
|
|
2588
|
-
|
|
3104
|
+
AntiDebug.setOnDevtoolsMaxed(() => {
|
|
3105
|
+
this.transmitter.send("devtools_force_close", {
|
|
3106
|
+
reason: "devtools_threshold_exceeded",
|
|
3107
|
+
detectionCount: 3,
|
|
3108
|
+
maxThreat: true
|
|
3109
|
+
});
|
|
3110
|
+
});
|
|
3111
|
+
import("../console-n38-3CrG.js").then(({ ConsoleDetector }) => {
|
|
2589
3112
|
new ConsoleDetector(() => {
|
|
2590
3113
|
this.transmitter.send("devtools_open", { detected: true });
|
|
2591
3114
|
}).start();
|
|
@@ -2639,6 +3162,8 @@ class SecuritySDK {
|
|
|
2639
3162
|
this.cloudEnvironmentDetector.start();
|
|
2640
3163
|
this.crossContextDetector.start();
|
|
2641
3164
|
this.headlessProbeDetector.start();
|
|
3165
|
+
this.scriptInjectionDetector.start();
|
|
3166
|
+
this.workerIntegrityDetector.start();
|
|
2642
3167
|
}
|
|
2643
3168
|
}
|
|
2644
3169
|
const securitySDK = new SecuritySDK();
|
package/dist/sri-hashes.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
|
-
"generated": "2026-03-
|
|
2
|
+
"generated": "2026-03-20T07:11:02.283Z",
|
|
3
3
|
"algorithm": "sha384",
|
|
4
4
|
"hashes": {
|
|
5
|
-
"core.js": "sha384-
|
|
5
|
+
"core.js": "sha384-6X6rQ1r2g8Xe7Ip9yTnbfB4yCg1NJ4eQBROEDFGAHLDngu98b3ed7XTzR5zTVWx4",
|
|
6
6
|
"core.wasm": "sha384-fPJjZg5frGy3uptl1c6t4ekPOoQRQPquQVQEbrMf09T7mCur5iJVX4gGqkRfu93q",
|
|
7
7
|
"loader.js": "sha384-0v1eaWmQUDG7Xzh8ujnAFroO2azUb0n547CCqAL1opB0WUltJC8WMyV8e1XoKf2R"
|
|
8
8
|
}
|
|
@@ -33,6 +33,8 @@ declare class SecuritySDK {
|
|
|
33
33
|
private cloudEnvironmentDetector;
|
|
34
34
|
private crossContextDetector;
|
|
35
35
|
private headlessProbeDetector;
|
|
36
|
+
private scriptInjectionDetector;
|
|
37
|
+
private workerIntegrityDetector;
|
|
36
38
|
private crawlProtect;
|
|
37
39
|
private initialized;
|
|
38
40
|
private wasmService;
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { Transmitter } from '../transport';
|
|
2
|
+
/**
|
|
3
|
+
* ScriptInjectionDetector — Detects script injection attacks.
|
|
4
|
+
*
|
|
5
|
+
* Defends against SeleniumBase's insertScript, Puppeteer's evaluateOnNewDocument,
|
|
6
|
+
* and similar techniques that inject JavaScript before or after page load.
|
|
7
|
+
*
|
|
8
|
+
* Detection layers:
|
|
9
|
+
* 1. Native function integrity (navigator property tampering)
|
|
10
|
+
* 2. Property override detection (defineProperty / Proxy on navigator)
|
|
11
|
+
* 3. DOM script injection monitoring (MutationObserver)
|
|
12
|
+
* 4. CSP violation monitoring (securitypolicyviolation events)
|
|
13
|
+
* 5. Global variable pollution (automation framework globals)
|
|
14
|
+
* 6. Prototype chain integrity (HTMLElement, Event, createElement)
|
|
15
|
+
*/
|
|
16
|
+
export declare class ScriptInjectionDetector {
|
|
17
|
+
private transmitter;
|
|
18
|
+
private hasRun;
|
|
19
|
+
private injectedScriptCount;
|
|
20
|
+
private cspViolations;
|
|
21
|
+
constructor(transmitter: Transmitter);
|
|
22
|
+
start(): void;
|
|
23
|
+
private detect;
|
|
24
|
+
/**
|
|
25
|
+
* 1. Native Function Integrity
|
|
26
|
+
* Checks if navigator.webdriver descriptor, navigator getters, and
|
|
27
|
+
* Function.prototype.toString have been tampered with.
|
|
28
|
+
*/
|
|
29
|
+
private checkNativeFunctionIntegrity;
|
|
30
|
+
/**
|
|
31
|
+
* 2. Property Override Detection
|
|
32
|
+
* Checks for Object.defineProperty abuse on navigator,
|
|
33
|
+
* proxy wrappers, and spoofed navigator.plugins.
|
|
34
|
+
*/
|
|
35
|
+
private checkPropertyOverrides;
|
|
36
|
+
/**
|
|
37
|
+
* 3. DOM Script Injection Monitoring
|
|
38
|
+
* Sets up MutationObserver to watch for dynamically added <script> tags.
|
|
39
|
+
*/
|
|
40
|
+
private startDOMObserver;
|
|
41
|
+
/**
|
|
42
|
+
* 4. CSP Violation Monitoring
|
|
43
|
+
* Listens for securitypolicyviolation events indicating injection attempts.
|
|
44
|
+
*/
|
|
45
|
+
private startCSPMonitor;
|
|
46
|
+
/**
|
|
47
|
+
* 5. Global Variable Pollution
|
|
48
|
+
* Checks for known automation framework globals and CDP-injected patterns.
|
|
49
|
+
*/
|
|
50
|
+
private checkGlobalPollution;
|
|
51
|
+
/**
|
|
52
|
+
* 6. Prototype Chain Integrity
|
|
53
|
+
* Verifies HTMLElement.prototype, document.createElement, and Event constructor.
|
|
54
|
+
*/
|
|
55
|
+
private checkPrototypeIntegrity;
|
|
56
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { Transmitter } from '../transport';
|
|
2
|
+
/**
|
|
3
|
+
* WorkerIntegrityDetector — Web Worker 격리 환경을 이용한 브라우저 무결성 검증.
|
|
4
|
+
*
|
|
5
|
+
* SeleniumBase/Puppeteer의 insertScript는 메인 스레드에만 영향을 주므로,
|
|
6
|
+
* Worker 내부에서 독립적으로 브라우저 상태를 검증하면 스푸핑을 탐지할 수 있음.
|
|
7
|
+
*
|
|
8
|
+
* Detection:
|
|
9
|
+
* 1. Navigator 일관성 — Worker vs 메인 스레드 navigator 속성 비교
|
|
10
|
+
* 2. Performance 벤치마크 — 마이크로 벤치마크로 비정상 실행 속도 탐지
|
|
11
|
+
* 3. Crypto API 검증 — crypto.getRandomValues 엔트로피 확인
|
|
12
|
+
* 4. Date/Time 일관성 — Worker vs 메인 스레드 시간 불일치 탐지
|
|
13
|
+
* 5. Function.prototype.toString 무결성 — 네이티브 함수 변조 탐지
|
|
14
|
+
*/
|
|
15
|
+
export declare class WorkerIntegrityDetector {
|
|
16
|
+
private transmitter;
|
|
17
|
+
private hasRun;
|
|
18
|
+
constructor(transmitter: Transmitter);
|
|
19
|
+
start(): void;
|
|
20
|
+
private detect;
|
|
21
|
+
/**
|
|
22
|
+
* Spawn an inline Web Worker via Blob URL and collect integrity signals.
|
|
23
|
+
* Returns null if Worker is not supported or times out.
|
|
24
|
+
*/
|
|
25
|
+
private runWorker;
|
|
26
|
+
}
|
|
@@ -3,10 +3,17 @@ export declare class AntiDebug {
|
|
|
3
3
|
private static intervalId;
|
|
4
4
|
static start(): void;
|
|
5
5
|
static stop(): void;
|
|
6
|
+
/** Set callback for when DevTools detection exceeds threshold (called by SDK core). */
|
|
7
|
+
static setOnDevtoolsMaxed(callback: () => void): void;
|
|
8
|
+
/** Called by ConsoleDetector or size detection when DevTools is detected. */
|
|
9
|
+
static reportDevtoolsDetection(): void;
|
|
6
10
|
/** Returns saved original console methods (bound to console). */
|
|
7
11
|
static getOriginalConsole(): Record<string, Function>;
|
|
12
|
+
private static handleDevtoolsMaxed;
|
|
8
13
|
private static saveConsole;
|
|
9
14
|
private static preventDevTools;
|
|
10
15
|
private static debuggerCheck;
|
|
16
|
+
/** Block F12, Ctrl+Shift+I/J/C, Ctrl+U and right-click */
|
|
17
|
+
private static blockDevToolsKeys;
|
|
11
18
|
private static disableConsole;
|
|
12
19
|
}
|