UNPKG

fingerprint-web

Version:

A blazing-fast, dependency-free browser fingerprinting library to uniquely identify devices using entropy data. Designed for high performance, privacy-respecting analytics, bot detection, and session tracking in modern web apps.

779 lines (619 loc) 22.3 kB
# Web-Based Fingerprint ![Version](https://img.shields.io/badge/version-1.1.0-indianred.svg) ![License](https://img.shields.io/badge/license-MIT-skyblue.svg) ![Size](https://img.shields.io/badge/size-2KB_minified-success.svg) A lightweight, deterministic browser fingerprinting library that generates consistent device signatures without cookies or storage. Perfect for enhancing security, preventing fraud, or implementing robust user identification systems. [![Developer](https://img.shields.io/badge/Developer-Jafran_Hasan-fff.svg?style=for-the-badge) ](https://fb.com/iamjafran) ## Table of Contents - [Features](#features) - [Installation](#installation) - [Quick Start](#quick-start) - [How It Works](#how-it-works) - [Complete Customization Guide](#complete-customization-guide) - [Common Use Cases](#common-use-cases) - [API Reference](#api-reference) - [Custom Components](#custom-components) - [Entropy Sources](#entropy-sources) - [Browser Support](#browser-support) - [Security & Privacy](#security--privacy) - [License](#license) - [Contributing](#contributing) ## Features - **Forever FREE & Unlimited** - No dependency, no server cost, runs on regular browser - **Stable & Deterministic** - Same fingerprint across page loads and sessions - **Zero Dependencies** - Only 2KB minified - **Multiple Hash Formats** - SHA-256, SHA-512, SHA-1, or custom length - **Customizable Components** - Enable/disable specific entropy sources - **Multiple Output Formats** - Hex, Base64, Integer, or Binary - **Cross-Browser Compatible** - Works in all modern browsers - **Privacy-Friendly** - No cookies, localStorage, or server components - **Extensible Architecture** - Add custom entropy sources ## Installation ### Using NPM/Yarn ```bash # NPM npm install fingerprint-web # Yarn yarn add fingerprint-web ``` ### Using CDN ```html <!-- Direct script include --> <script src="https://unpkg.com/fingerprint-web@latest/dist/fingerprint.min.js"></script> <!-- Now available globally as Fingerprint --> <script> const fingerprinter = new Fingerprint(); fingerprinter.get().then(hash => { console.log("Browser fingerprint:", hash); }); </script> ``` ### Direct Download You can also download the library directly from the [GitHub repository](https://github.com/yourusername/fingerprint-web/releases) and include it in your project: ```html <script src="path/to/fingerprint.min.js"></script> ``` ## Quick Start ```javascript import Fingerprint from 'fingerprint-web'; // Create fingerprinter and get device signature const fingerprinter = new Fingerprint(); fingerprinter.get().then(fingerprint => { console.log('Fingerprint:', fingerprint); // e.g. "3f4e591c86c9c5f734fc4b54d5322549bf85ec34b4c2f36310490b3e187b733d" }); ``` ## How It Works Web-Based Fingerprint generates deterministic device signatures by combining multiple stable browser and hardware characteristics: 1. **Data Collection**: The library collects various entropy sources that remain consistent between browser sessions: - Hardware identifiers (screen resolution, color depth, CPU cores) - Browser configuration (user agent, language, plugins) - Rendering capabilities (canvas, WebGL, color gamut) - System settings (timezone, fonts, preferences) 2. **Component Processing**: Each data point is normalized to ensure consistency: - Canvas rendering uses controlled drawing parameters - WebGL details include vendor and renderer information - Font detection identifies system fonts without accessing the file system - Plugin details are sorted and normalized 3. **Weighting System**: More reliable components can be given higher weight 4. **Cryptographic Hashing**: All collected data points are combined and processed through cryptographic hashing (SHA-256 by default) 5. **Format Conversion**: The resulting hash can be represented in various formats (hex, base64, integer) The fingerprint remains consistent across browser sessions because it's based on stable device and browser characteristics rather than stored data. ### Detailed Fingerprinting Process 1. **Browser Information Collection**: - User agent string is captured exactly as provided by the browser - Language preferences are normalized to ensure consistent format - Do Not Track setting is captured as a boolean value 2. **Hardware Information Collection**: - Screen dimensions and color depth are captured in a consistent format - CPU core count and device memory are included when available - Touch point capability helps distinguish mobile from desktop devices 3. **Advanced Fingerprinting Techniques**: - Canvas fingerprinting draws specific shapes and text with controlled parameters - WebGL fingerprinting captures graphics hardware details - Font availability detection uses width comparison techniques - Audio context processing creates a unique audio signature (optional) 4. **Data Processing**: - All components are joined using a configurable separator - The combined string is hashed using a cryptographic algorithm - The resulting hash can be truncated or formatted as needed ## Complete Customization Guide The library offers extensive customization options for different use cases: ### Component Selection Choose which entropy sources to include: ```javascript const fingerprinter = new Fingerprint({ components: { // Browser basics userAgent: true, language: true, doNotTrack: true, // Hardware identifiers screen: true, hardware: true, touchPoints: true, // Advanced sources canvas: true, webGL: true, colorGamut: true, // Additional sources plugins: true, fonts: true, timezone: true, // Optional (more volatile) audio: false } }); ``` ### Hash Algorithm & Length Choose cryptographic algorithm and result length: ```javascript // SHA-512 with custom length output const fingerprinter = new Fingerprint({ hashAlgorithm: 'SHA-512', // 'SHA-1', 'SHA-256', 'SHA-384', 'SHA-512' hashLength: 32 // First 32 characters only (default: 0 = full length) }); ``` ### Component Weighting Give more weight to more reliable components: ```javascript const fingerprinter = new Fingerprint({ weights: { // Higher values = more influence on final fingerprint canvas: 3, // Canvas has 3x normal weight webGL: 2, // WebGL has 2x normal weight userAgent: 2, // User agent has 2x normal weight // All other components have default weight of 1 } }); ``` ### Custom Entropy Sources Add your own data sources: ```javascript const fingerprinter = new Fingerprint({ customComponents: [ // Check for specific browser features function() { return { speechSynthesis: 'speechSynthesis' in window, bluetooth: 'bluetooth' in navigator, serviceWorker: 'serviceWorker' in navigator }; }, // Connection information function() { const connection = navigator.connection || navigator.mozConnection || navigator.webkitConnection; return connection ? connection.effectiveType : 'unknown'; } ] }); ``` ### Runtime Configuration Override Change options at runtime without creating new instances: ```javascript const fingerprinter = new Fingerprint(); // First get standard fingerprint fingerprinter.get().then(standardHash => { console.log('Standard fingerprint:', standardHash); // Then get a shorter SHA-1 fingerprint with the same instance return fingerprinter.get({ hashAlgorithm: 'SHA-1', hashLength: 16 }); }).then(shortHash => { console.log('Short SHA-1 fingerprint:', shortHash); }); ``` ### Excluding Volatile Components For maximum stability across sessions: ```javascript const stableFingerprinter = new Fingerprint({ // Exclude all potentially volatile components excludeVolatile: true, // Disable specific volatile components individually components: { audio: false, plugins: false } }); ``` ### Font Detection Customization Control how fonts are detected: ```javascript const fingerprinter = new Fingerprint({ // Enable or disable font detection entirely enableFonts: true, // Font detection is included in components components: { fonts: true } }); ``` ### Custom Separator Change how components are joined: ```javascript const fingerprinter = new Fingerprint({ // Use a different separator between components separator: ':::' // Default is '||' }); ``` ## Common Use Cases ### 1. Minimal Stable Fingerprint ```javascript // Only use the most stable components for maximum consistency const minimalFingerprint = new Fingerprint({ components: { userAgent: true, screen: true, language: true, canvas: true, webGL: true, // Disable less stable components fonts: false, plugins: false, timezone: false, colorGamut: false, touchPoints: false, hardware: false, doNotTrack: false }, hashLength: 32 // Shorter output }); ``` ### 2. Different Output Formats ```javascript // Get fingerprint in different formats fingerprinter.get().then(hash => { // Different representations of the same fingerprint console.log('Hex:', hash); console.log('Base64:', fingerprinter.formatHash(hash, 'base64')); console.log('Integer:', fingerprinter.formatHash(hash, 'int')); console.log('Binary:', fingerprinter.formatHash(hash, 'binary').substring(0, 64) + '...'); }); ``` ### 3. Maximum Entropy ```javascript // Maximum entropy configuration const enhancedFingerprint = new Fingerprint({ // Use stronger hash algorithm hashAlgorithm: 'SHA-512', // Include all components including audio components: { /* ... all components enabled ... */ audio: true }, // Include less stable components excludeVolatile: false, // Prioritize the most reliable components weights: { canvas: 3, // Canvas has 3x normal influence webGL: 2 // WebGL has 2x normal influence } }); ``` ### 4. Real-World Example: Fraud Prevention ```javascript // Create a fingerprint instance const fingerprinter = new Fingerprint({ // Balance between stability and uniqueness components: { userAgent: true, screen: true, language: true, timezone: true, canvas: true, webGL: true, plugins: true, fonts: true, // Disable less stable components audio: false } }); // When user logs in or makes a purchase async function verifyUser(userId, transaction) { // Get current device fingerprint const deviceFingerprint = await fingerprinter.get(); // Check against known devices for this user const isKnownDevice = await checkDeviceDatabase(userId, deviceFingerprint); if (!isKnownDevice && transaction.amount > 1000) { // Require additional verification for large transactions on new devices return requestAdditionalVerification(userId, transaction); } else { // Proceed with transaction return processTransaction(userId, transaction, deviceFingerprint); } } ``` ### 5. Browser Bot Detection ```javascript // Create a high-entropy fingerprinter const botDetectionFingerprinter = new Fingerprint({ components: { userAgent: true, language: true, timezone: true, screen: true, canvas: true, webGL: true, fonts: true, plugins: true, audio: true }, excludeVolatile: false, customComponents: [ // Add bot detection heuristics function() { return { // Check for inconsistencies typical in bots navigatorPrototype: Object.getOwnPropertyNames(Navigator.prototype).length, windowKeys: Object.keys(window).length, // Automation detection webdriver: navigator.webdriver, automation: window.navigator.webdriver || window.document.documentElement.getAttribute("webdriver") || window.callPhantom || window._phantom }; } ] }); // Check if current client is likely a bot async function detectBot() { const fingerprint = await botDetectionFingerprinter.get(); const rawData = await botDetectionFingerprinter.getRawData(); // Analyze fingerprint and raw data for bot indicators const botScore = calculateBotScore(fingerprint, rawData); return { isBot: botScore > 0.7, confidence: botScore, fingerprint: fingerprint }; } ``` ## API Reference ### Constructor Options ```javascript new Fingerprint({ // Core settings hashAlgorithm: 'SHA-256', // 'SHA-1', 'SHA-256', 'SHA-384', 'SHA-512' hashLength: 0, // 0 = full length, or specify character count enableFonts: true, // Include font detection excludeVolatile: true, // Exclude less stable components // Enable/disable specific components components: { userAgent: true, // User agent string language: true, // Browser language screen: true, // Screen dimensions and color depth timezone: true, // System timezone touchPoints: true, // Touch point capability hardware: true, // CPU cores and device memory doNotTrack: true, // Do Not Track setting canvas: true, // Canvas fingerprinting webGL: true, // WebGL vendor and renderer colorGamut: true, // Color gamut capabilities plugins: true, // Browser plugins fonts: true, // System fonts audio: false // Audio processing (off by default) }, // Component weight factors (higher = more influence) weights: { userAgent: 1, language: 1, screen: 1, timezone: 1, touchPoints: 1, hardware: 1, doNotTrack: 1, canvas: 1, webGL: 1, colorGamut: 1, plugins: 1, fonts: 1, audio: 1 }, // Custom entropy sources customComponents: [], // Data separator separator: '||' }); ``` ### Core Methods | Method | Description | Return Type | Example | |--------|-------------|-------------|---------| | `get([overrideOptions])` | Generates fingerprint hash | `Promise<string>` | `fingerprinter.get()` | | `getRawData()` | Returns raw component data | `Promise<Array>` | `fingerprinter.getRawData()` | | `formatHash(hash, format)` | Converts hash format | `string\|number` | `fingerprinter.formatHash(hash, 'base64')` | | `static createComponent(fn)` | Creates reusable component | `Function` | `Fingerprint.createComponent(fn)` | ### Method Details #### `get([overrideOptions])` Generates and returns the fingerprint hash. **Parameters**: - `overrideOptions` (Object, optional): Runtime options that override constructor options **Returns**: `Promise<string>` - The fingerprint hash **Example**: ```javascript // Basic usage fingerprinter.get().then(hash => console.log(hash)); // With runtime options fingerprinter.get({ hashAlgorithm: 'SHA-1', hashLength: 16 }).then(hash => console.log(hash)); ``` #### `getRawData()` Returns the raw fingerprint data before hashing. **Returns**: `Promise<Array>` - Array of collected data points **Example**: ```javascript fingerprinter.getRawData().then(data => { console.log('Raw fingerprint components:', data); // Analyze components data.forEach((component, index) => { console.log(`Component ${index}:`, component); }); }); ``` #### `formatHash(hash, format)` Converts the fingerprint hash to various output formats. **Parameters**: - `hash` (String): The fingerprint hash to convert - `format` (String, optional): Output format (default: 'hex') - 'hex': Hexadecimal format (default) - 'base64': Base64 encoding - 'int': Integer representation (first 53 bits) - 'binary': Binary string (0s and 1s) **Returns**: The formatted hash (String or Number) **Example**: ```javascript fingerprinter.get().then(hash => { console.log('Hex:', hash); console.log('Base64:', fingerprinter.formatHash(hash, 'base64')); console.log('Integer:', fingerprinter.formatHash(hash, 'int')); console.log('Binary:', fingerprinter.formatHash(hash, 'binary')); }); ``` #### `static createComponent(fn)` Creates a reusable component function that can be added to customComponents. **Parameters**: - `fn` (Function): Function that returns a fingerprint component value **Returns**: Properly formatted component function **Example**: ```javascript const screenOrientationComponent = Fingerprint.createComponent(function() { return screen.orientation ? screen.orientation.type : 'orientation_unsupported'; }); const fingerprinter = new Fingerprint({ customComponents: [screenOrientationComponent] }); ``` ### Output Formats ```javascript // Available formats fingerprinter.formatHash(hash, 'hex'); // Default hexadecimal format fingerprinter.formatHash(hash, 'base64'); // Base64 encoding fingerprinter.formatHash(hash, 'int'); // Integer representation (first 53 bits) fingerprinter.formatHash(hash, 'binary'); // Binary string (0s and 1s) ``` ## Custom Components Add your own entropy sources: ```javascript const fingerprinter = new Fingerprint({ customComponents: [ // Check for browser features function() { return { speechSynthesis: 'speechSynthesis' in window, bluetooth: 'bluetooth' in navigator, serviceWorker: 'serviceWorker' in navigator }; }, // Any function returning string or object function() { return navigator.connection?.effectiveType || 'unknown'; } ] }); // Creating reusable components const mediaDeviceComponent = Fingerprint.createComponent(async function() { if (!navigator.mediaDevices || !navigator.mediaDevices.enumerateDevices) { return 'media_api_unsupported'; } try { const devices = await navigator.mediaDevices.enumerateDevices(); const counts = { audioinput: 0, audiooutput: 0, videoinput: 0 }; devices.forEach(device => { if (counts[device.kind] !== undefined) { counts[device.kind]++; } }); return `media_${counts.audioinput}_${counts.audiooutput}_${counts.videoinput}`; } catch (e) { return 'media_error'; } }); // Use the reusable component const enhancedFingerprinter = new Fingerprint({ customComponents: [mediaDeviceComponent] }); ``` ### Advanced Custom Component Examples #### LocalStorage Detection ```javascript const storageComponent = Fingerprint.createComponent(function() { const storageTypes = { localStorage: false, sessionStorage: false, indexedDB: false }; try { // Test localStorage localStorage.setItem('test', 'test'); localStorage.removeItem('test'); storageTypes.localStorage = true; } catch (e) {} try { // Test sessionStorage sessionStorage.setItem('test', 'test'); sessionStorage.removeItem('test'); storageTypes.sessionStorage = true; } catch (e) {} try { // Test indexedDB storageTypes.indexedDB = !!window.indexedDB; } catch (e) {} return storageTypes; }); ``` #### Font Metrics ```javascript const fontMetricsComponent = Fingerprint.createComponent(function() { const testString = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'; const testElement = document.createElement('span'); testElement.style.position = 'absolute'; testElement.style.left = '-9999px'; testElement.style.fontSize = '72px'; testElement.textContent = testString; document.body.appendChild(testElement); // Test with different fonts const fonts = ['monospace', 'sans-serif', 'serif']; const metrics = {}; fonts.forEach(font => { testElement.style.fontFamily = font; metrics[font] = { width: testElement.offsetWidth, height: testElement.offsetHeight }; }); document.body.removeChild(testElement); return metrics; }); ``` ## Entropy Sources The library combines these stable browser/hardware characteristics: ### Core Browser Data - **User Agent**: Complete browser and OS identification string - **Language**: Browser language preferences - **Do Not Track**: User's tracking preference setting ### Hardware Information - **Screen Properties**: Resolution, color depth, pixel ratio - **CPU & Memory**: Core count and device memory (when available) - **Touch Capability**: Maximum touch points supported - **Timezone**: User's geographical timezone ### Graphics Fingerprinting - **Canvas Rendering**: How the browser renders specific shapes and text - **WebGL Information**: Graphics card vendor and renderer details - **Color Gamut**: Display's color reproduction capabilities ### Software Enumeration - **Browser Plugins**: Installed browser extensions and plugins - **Font Availability**: System fonts detection - **Audio Processing**: How the device processes audio signals (optional) ### Custom Sources - Any additional entropy sources added through custom components ## Browser Support | Browser | Version | Support Level | |---------|---------|---------------| | Chrome | 49+ | Full | | Firefox | 52+ | Full | | Safari | 11+ | Full | | Edge | 79+ | Full | | Opera | 36+ | Full | | IE | 11 | ⚠️ Basic (no audio fingerprinting) | | Chrome for Android | 49+ | Full | | Safari iOS | 11+ | Full | | Samsung Internet | 5+ | Full | | UC Browser | 12+ | Full | ### Browser Compatibility Notes - **Internet Explorer**: Limited support. WebGL and some canvas features may be unreliable. - **Safari**: Full support, but some font detection features may behave differently. - **Mobile Browsers**: Full support on modern mobile browsers. - **Privacy Modes**: Fingerprinting works in incognito/private browsing modes. ## 📝 License MIT License - feel free to use and modify as needed. --- Developed by [Jafran Hasan](https://jafran.online), Sr Software Developer at [WPPOOL](https://wppool.dev).