- Safari 17은 비공개 모드에서 Audio API 샘플마다 무작위 노이즈를 더해 오디오 지문을 흔들지만, FingerprintJS는 이를 줄이는 새 지문 알고리듬으로 대응함
- 기존 방식은 500개 오디오 샘플의 합을 식별자로 쓰기 때문에 Safari의 노이즈 범위가 브라우저 간 차이보다 커져 안정성을 잃음
- 새 방식은 같은 오디오 샘플의 노이즈 사본을 대량으로 만들고
(min+max)/2와 유효숫자 반올림으로 값의 흔들림을 줄임 - square
OscillatorNode,DynamicsCompressorNode,BiquadFilterNode를 연결해 브라우저 간 차이를 키웠고, 선택한 브라우저들의 3396번째 샘플 최소 차이를0.0014%까지 늘림 - 새 알고리듬은 FingerprintJS 4.2.0부터 기존 오디오 지문을 대체했으며, 계산 시간은 1.5~2배 늘지만 저사양 기기에서도 짧은 시간 안에 끝남
Safari 17이 오디오 지문을 흔드는 방식
- 오디오 지문 인식은 브라우저의 Audio API와 OfflineAudioContext로 오디오 신호를 렌더링한 뒤, 샘플을 합산해 하나의 식별자 숫자로 만드는 방식임
- 이 식별자는 쿠키 삭제나 시크릿 모드 전환에도 바뀌지 않는 안정성을 가지지만, 많은 사용자가 같은 값을 공유할 수 있어 고유성은 높지 않음
- Safari 17의 고급 지문 보호는 기본적으로 비공개 모드에서 켜지고 일반 모드에서는 꺼지며, 데스크톱과 모바일 모두에 적용됨
- 보호 기능은 Screen API와 Canvas API에도 영향을 주지만, 여기서는 Audio API만 다룸
- 보호 기능이 켜지면 Safari는 각 오디오 샘플에 개별 무작위 노이즈를 곱함
- 노이즈가 적용된 샘플은
sample*(1-magnitude)와sample*(1+magnitude)사이에 있음 - 분포는 균등분포임
- Safari 개발이 계속 진행 중이므로 구현 세부사항은 시간이 지나면 달라질 수 있음
- 노이즈가 적용된 샘플은
노이즈가 적용되는 Audio API 지점
- Safari는 오디오 신호를 읽을 수 있는 여러 인터페이스에서 노이즈를 적용함
- AudioWorkletNode: magnitude
0.001 - AudioBuffer::getChannelData: magnitude
0.001 - AudioBuffer::copyFromChannel: magnitude
0.001 - RealtimeAnalyser::getFloatFrequencyData: magnitude
0.25
- AudioWorkletNode: magnitude
- 노이즈는 적용될 때마다 달라지므로 Safari 17 비공개 모드에서는 오디오 지문이 계산할 때마다 바뀜
- M1 MacBook Air의 Safari 17에서 지문은
124.03516~124.04545사이에서 변동하며, 차이는 약0.008%임 - 브라우저별 기존 오디오 지문 차이 중 가장 작은 값은
0.0000023%로, Safari의 노이즈 범위보다 훨씬 작음 - 노이즈를 없애려면 소수점 한 자리 수준으로 반올림해야 하지만, 6자리보다 적게 남기면 일부 브라우저를 구분하기 어려워 고유성이 낮아짐
새 알고리듬의 3단계
- FingerprintJS의 새 오디오 지문 알고리듬은 Safari가 추가한 노이즈를 줄이기 위해 세 단계를 거침
- 노이즈의 분산을 줄임
- 브라우저 식별자 숫자 간 거리를 늘림
- 남은 노이즈를 반올림으로 제거함
- 기존 오디오 지문은 500개 오디오 샘플의 합이므로, 각 샘플에 균등분포 노이즈가 더해지면 전체 지문 노이즈는 정규분포에 가까워짐
- 정규분포 평균은 많은 샘플의 평균으로 추정해야 하지만, 균등분포 평균은
min과max를 사용한(min+max)/2로 더 적은 샘플에서 정밀하게 추정할 수 있음 - 실험 코드에서는 같은 정밀도 조건에서 정규분포는
524,288개 샘플이 필요했고, 균등분포는4,096개 샘플이면 충분했음 - 새 방식은 합산 지문 대신 단일 오디오 샘플만 수집해 균등분포 노이즈를 다루도록 바꿈
- 이 변경 때문에 새 지문은 기존 지문과 호환되지 않으며, 방문자 식별자를 잃지 않고 전환하려면 별도 접근이 필요함
같은 오디오 샘플의 노이즈 사본 만들기
AudioBuffer인스턴스에서getChannelData를 여러 번 호출하는 방식은 작동하지 않음- 노이즈는 각
AudioBuffer인스턴스마다 한 번 적용됨 - 같은 인스턴스의
getChannelData는 같은 신호를 반환함
- 노이즈는 각
- 전체 오디오 신호 생성 과정을 여러 번 실행하면 많은
AudioBuffer인스턴스를 만들 수 있지만, 지문 계산용으로는 너무 느림- 6,000개 노이즈 샘플은 M1 MacBook에서 가장 빠른 시간이 7초였음
- 60,000개에서는 Safari가 작업을 끝내지 못했음
- 더 나은 방식은 같은 오디오 신호를 반복하는
AudioBuffer인스턴스를 만드는 것임- 첫 번째 오디오 신호를 렌더링하되
getChannelData는 호출하지 않음 - 더 긴 두 번째 OfflineAudioContext를 만들고 원본 신호를 AudioBufferSourceNode로 사용함
loop,loopStart,loopEnd로 원본 신호 일부를 반복함- 반복 후 Safari가 노이즈를 추가하므로 같은 오디오 샘플에 서로 다른 노이즈가 적용된 사본을 얻음
- 첫 번째 오디오 신호를 렌더링하되
- 이 방식은 오디오 렌더링 2번만으로 필요한 수의 노이즈 사본을 만들 수 있음
- 노이즈가 완전히 사라지지는 않지만, 원본 오디오 샘플보다 분산이 작아짐
8,192개 사본: 100회 실행 결과 범위0.000387%, M1 MacBook 기준2.6ms65,536개 사본:0.0000123%,4.1ms262,144개 사본:0%,7.5ms
브라우저 간 오디오 샘플 차이 키우기
- 사본 수를 줄이면 성능은 좋아지지만 결과 분산이 커지므로, 브라우저 간 오디오 샘플 차이를 키우기 위해 기본 신호를 바꿈
- 여러 내장 오디오 노드를 실험한 결과, 브라우저 간 샘플 차이가 커지는 신호 생성 체인은 다음과 같음
- square OscillatorNode
- DynamicsCompressorNode
allpass타입 BiquadFilterNode
- 오디오 신호의 3396번째 샘플이 브라우저 간 차이가 가장 컸으며, 여러 브라우저의 모든 샘플을 비교해 찾은 값임
- 선택한 브라우저 표본에서 이 새 샘플의 가장 작은 차이는
0.0014%였음- 기존 지문의 가장 작은 차이
0.0000023%보다 큼 - 덕분에 더 거친 노이즈 제거와 반올림을 적용할 수 있음
- 기존 지문의 가장 작은 차이
반올림으로 지문 안정화
- 단일 샘플의 노이즈 범위가 작아져도 값은 여전히 흔들리므로, 최종 지문으로 쓰려면 반올림이 필요함
- 노이즈는 절대값이 아니라 오디오 샘플 값에 상대적으로 적용되기 때문에, 소수점 자리수가 아니라 유효숫자를 기준으로 반올림함
- 선택한 브라우저들을 구분하는 데는 유효숫자 5개가 충분했지만, 전체 브라우저와 향후 변화를 모두 확인할 수 없으므로 더 많은 자릿수를 사용함
- Safari 17 비공개 모드에서 반올림 정밀도별 안정화에 필요한 사본 수는 다음과 같음
- 유효숫자 6개:
15,000개, Safari 17 on M1 MacBook warm 기준3ms - 유효숫자 7개이되 마지막 자리를 5의 배수로 반올림:
30,000개,4ms - 유효숫자 7개이되 마지막 자리를 가장 가까운 짝수로 반올림:
70,000개,6ms - 유효숫자 7개 이상:
400,000개,12ms
- 유효숫자 6개:
- 최종 선택은 유효숫자 7개이되 마지막 자리를
0또는5로 만드는 방식이며, 안정성을 높이기 위해 사본 수를40,000개로 늘림 - 이렇게 반올림된 숫자는 Safari 17 고급 지문 보호가 켜져 있어도 바뀌지 않는 새 오디오 지문이 됨
- 새 지문은 기존 오디오 지문과 같은 고유성을 가진 것으로 평가됨
성능과 실행 제약
- 빈 페이지의 warm 브라우저 기준 새 알고리듬은 기존보다 대체로 느림
- MacBook Air 2020 Safari 17.3: 기존
2ms, 새 방식4ms - MacBook Air 2020 Chrome 120: 기존
5ms, 새 방식8ms - iPhone 13 mini Safari 17.3: 기존
8ms, 새 방식12ms - Galaxy J7 Prime Chrome 120: 기존
33ms, 새 방식45ms - BrowserStack Windows 11 Firefox 121: 기존
10ms, 새 방식18ms
- MacBook Air 2020 Safari 17.3: 기존
- 새 알고리듬의 성능은 기존 대비 1.5~2배 나빠지지만, 저사양 기기에서도 계산 시간은 짧음
- 브라우저가 일부 작업을
OfflineAudioRender스레드에 위임하므로, 오디오 지문 계산 대부분 동안 페이지는 반응성을 유지함 - Web Audio API는 web workers에서 사용할 수 없어 오디오 지문을 워커에서 계산할 수 없음
- 성능을 개선하려면 사용자 에이전트 문자열로 Safari 17 이상 여부를 확인하고, Safari 17 이상에서만 새 알고리듬을 쓰며 다른 브라우저에서는 기존 알고리듬을 유지할 수 있음
Tor와 Brave의 차이
- Tor는 Web Audio API를 완전히 비활성화하므로 오디오 지문 인식이 불가능함
- Brave는 Safari 17처럼 오디오 신호에 노이즈를 추가하지만 방식이 다름
- Safari는 각 오디오 샘플마다 별도 무작위 값을 곱함
- Brave는
fudge factor라는 무작위 배수를 한 번 만들고 모든 오디오 샘플에 같은 값을 곱함- 이 값은 페이지 안에서 유지됨
- 새 일반 세션이나 시크릿 세션에서만 바뀜
- Brave에서는 아무리 많은 오디오 샘플 사본을 만들어도 모든 사본에 같은 노이즈가 적용되므로, Safari용 수학적 노이즈 제거 방식이 작동하지 않음
- 다만 이전 Brave 노이즈 제거 방식은 계속 작동하며, 브라우저 간 지문 차이를 키우는 새 신호 생성 방법은 오차 허용 범위를 늘릴 수 있음
FingerprintJS 적용
- 새 오디오 지문 알고리듬은 FingerprintJS에서 기존 방식을 대체했으며, 4.2.0에서 처음 공개됨
- 전체 구현 코드는 FingerprintJS의 GitHub 저장소에 있음
- 오디오 지문은 오픈소스 라이브러리가 브라우저 지문을 만들 때 사용하는 여러 신호 중 하나임
- FingerprintJS는 브라우저에서 얻을 수 있는 모든 신호를 무조건 포함하지 않고, 각 신호의 안정성과 고유성을 따로 분석해 지문 정확도에 미치는 영향을 판단함
- 오디오 지문은 고유성에는 조금만 기여하지만 안정성이 높아 전체 지문 정확도를 약간 높이는 신호로 평가됨