Files
boc/iom/quixzoom-auth-service/utils/device_fingerprint.py
T

156 lines
5.3 KiB
Python
Raw Normal View History

"""
Device fingerprinting utilities
Generates unique fingerprints for devices and browsers
"""
import hashlib
import json
from typing import Dict, Optional, Any
class DeviceFingerprint:
"""
Device fingerprinting for security
Creates unique fingerprints from device/browser characteristics
to detect anomalies and prevent replay attacks
"""
@staticmethod
def generate_browser_fingerprint(
user_agent: Optional[str] = None,
accept_language: Optional[str] = None,
screen_resolution: Optional[str] = None,
timezone: Optional[str] = None,
fonts: Optional[list] = None,
canvas_hash: Optional[str] = None,
webgl_hash: Optional[str] = None,
plugins: Optional[list] = None
) -> str:
"""
Generate browser fingerprint from available characteristics
Args:
user_agent: Browser user agent string
accept_language: Accept-Language header
screen_resolution: Screen resolution (e.g., "1920x1080")
timezone: Browser timezone
fonts: List of detected fonts
canvas_hash: Canvas fingerprinting hash
webgl_hash: WebGL fingerprinting hash
plugins: List of browser plugins
Returns:
str: SHA-256 hash of fingerprint components
"""
components = {
"user_agent": user_agent or "",
"accept_language": accept_language or "",
"screen_resolution": screen_resolution or "",
"timezone": timezone or "",
"fonts": sorted(fonts) if fonts else [],
"canvas_hash": canvas_hash or "",
"webgl_hash": webgl_hash or "",
"plugins": sorted(plugins) if plugins else []
}
# Create deterministic JSON string
fingerprint_json = json.dumps(components, sort_keys=True, separators=(',', ':'))
# Hash the fingerprint
return hashlib.sha256(fingerprint_json.encode()).hexdigest()
@staticmethod
def generate_device_fingerprint(
platform: str,
os_version: Optional[str] = None,
device_model: Optional[str] = None,
hardware_id: Optional[str] = None,
app_version: Optional[str] = None,
install_id: Optional[str] = None
) -> str:
"""
Generate mobile device fingerprint
Args:
platform: Device platform (ios/android)
os_version: OS version
device_model: Device model
hardware_id: Hardware identifier
app_version: App version
install_id: Unique installation ID
Returns:
str: SHA-256 hash of device components
"""
components = {
"platform": platform.lower(),
"os_version": os_version or "",
"device_model": device_model or "",
"hardware_id": hardware_id or "",
"app_version": app_version or "",
"install_id": install_id or ""
}
fingerprint_json = json.dumps(components, sort_keys=True, separators=(',', ':'))
return hashlib.sha256(fingerprint_json.encode()).hexdigest()
@staticmethod
def generate_simple_fingerprint(
user_agent: Optional[str] = None,
ip_address: Optional[str] = None,
accept_headers: Optional[Dict[str, str]] = None
) -> str:
"""
Generate simple fingerprint from request headers
Used as fallback when detailed fingerprinting is not available
"""
components = {
"user_agent": user_agent or "",
"ip_address": ip_address or "",
"accept": accept_headers.get("accept", "") if accept_headers else "",
"accept_language": accept_headers.get("accept-language", "") if accept_headers else "",
"accept_encoding": accept_headers.get("accept-encoding", "") if accept_headers else ""
}
fingerprint_json = json.dumps(components, sort_keys=True, separators=(',', ':'))
return hashlib.sha256(fingerprint_json.encode()).hexdigest()
@staticmethod
def compare_fingerprints(
fingerprint1: str,
fingerprint2: str,
tolerance: float = 0.0
) -> bool:
"""
Compare two fingerprints
Args:
fingerprint1: First fingerprint
fingerprint2: Second fingerprint
tolerance: Similarity threshold (0.0 = exact match)
Returns:
bool: True if fingerprints match within tolerance
"""
if tolerance == 0.0:
return fingerprint1 == fingerprint2
# For fuzzy matching, we could implement similarity algorithms
# For now, exact match only
return fingerprint1 == fingerprint2
@staticmethod
def extract_fingerprint_components(fingerprint_hash: str) -> Dict[str, Any]:
"""
Extract components from a fingerprint (if stored separately)
Note: This is a placeholder - in production, components would be
stored alongside the hash for analysis
"""
return {
"hash": fingerprint_hash,
"algorithm": "sha256",
"components_stored": False
}