Saltar al contenido principal
en/blog/obscura/research/audio-fingerprinting/

obscura/research/audio-fingerprinting

2 min read

Overview

Audio fingerprinting uses the Web Audio API (AudioContext) to generate a unique identifier based on how the device's audio hardware and software process a generated signal.

Mechanism

  1. Create an AudioContext
  2. Generate an oscillator signal (sine wave at a specific frequency)
  3. Process through DynamicsCompressorNode
  4. Extract the processed signal via getChannelData()
  5. Hash the resulting floating-point array
const ctx = new AudioContext()
const osc = ctx.createOscillator()
const compressor = ctx.createDynamicsCompressor()
osc.connect(compressor)
compressor.connect(ctx.destination)

// Compressor settings
compressor.threshold.value = -50
compressor.knee.value = 40
compressor.ratio.value = 12
compressor.reduction.value = -20
osc.frequency.value = 1000
osc.type = 'sawtooth'

// Process and extract
const analyser = ctx.createAnalyser()
const buffer = new Float32Array(analyser.fftSize)
analyser.getFloatFrequencyData(buffer)
const hash = md5(buffer) // unique per audio stack

Entropy Sources

Source Variability
Audio driver and hardware High
Sample rate support Medium
Dynamics processing implementation Medium
OS audio stack (PulseAudio, ALSA, CoreAudio, WASAPI) High
Audio channel count Low

Mitigation

At the proxy

The AudioContext runs entirely in the browser the proxy cannot modify its output.

Via injected JS

Override AudioContext.prototype.getChannelData or AnalyserNode.prototype.getFloatFrequencyData to return generic/flat data.

// Injected override
const originalGetFloatFrequencyData = AnalyserNode.prototype.getFloatFrequencyData
AnalyserNode.prototype.getFloatFrequencyData = function(array) {
  originalGetFloatFrequencyData.call(this, array)
  // Flat/noise the output
  for (let i = 0; i < array.length; i++) {
    array[i] = -100 // flat signal
  }
}

Problem: The site can detect tampering by checking if the output is too uniform vs. real hardware output.

Conclusions

  • Audio fingerprinting is CPU/OS/hardware specific
  • Cannot be spoofed at proxy level
  • JS injection can blunt it but not fully
  • Best approach: override + consistent noise via injected JS