1 ポイント 投稿者 GN⁺ 2024-03-11 | 1件のコメント | WhatsAppで共有
  • Safari 17はプライベートブラウズモードでAudio APIの各サンプルにランダムノイズを加えてオーディオフィンガープリントを揺らすが、FingerprintJSはこれを低減する新しいフィンガープリントアルゴリズムで対抗した
  • 従来方式は500個のオーディオサンプルの合計を識別子として使うため、Safariのノイズ幅がブラウザ間の差より大きくなり、安定性を失う
  • 新方式は同じオーディオサンプルのノイズ付きコピーを大量に作り、(min+max)/2有効数字での丸めによって値の揺れを抑える
  • square OscillatorNodeDynamicsCompressorNodeBiquadFilterNodeを接続してブラウザ間の差を大きくし、選択したブラウザ群の3396番目のサンプルの最小差を0.0014%まで拡大した
  • 新アルゴリズムはFingerprintJS 4.2.0から従来のオーディオフィンガープリントを置き換えており、計算時間は1.5〜2倍に増えるが、低性能デバイスでも短時間で完了する

Safari 17がオーディオフィンガープリントを揺らす仕組み

  • オーディオフィンガープリンティングは、ブラウザのAudio APIOfflineAudioContextでオーディオ信号をレンダリングした後、サンプルを合算して1つの識別子数値を作る方式
  • この識別子はCookieの削除やシークレットモードへの切り替えでも変わらない安定性を持つ一方、多くのユーザーが同じ値を共有しうるため一意性はそれほど高くない
  • Safari 17の高度なフィンガープリント保護は、デフォルトでプライベートブラウズモードでは有効、通常モードでは無効で、デスクトップとモバイルの両方に適用される
  • この保護機能はScreen APIやCanvas APIにも影響するが、ここではAudio APIのみを扱う
  • 保護機能が有効になると、Safariは各オーディオサンプルに個別のランダムノイズを乗算する
    • ノイズが適用されたサンプルはsample*(1-magnitude)sample*(1+magnitude)の間にある
    • 分布は一様分布
    • Safariの開発は継続中のため、実装の詳細は今後変わる可能性がある

ノイズが適用されるAudio APIのポイント

  • Safariは、オーディオ信号を読み取れる複数のインターフェースでノイズを適用する
  • ノイズは適用されるたびに変わるため、Safari 17のプライベートブラウズモードではオーディオフィンガープリントが計算のたびに変化する
  • M1 MacBook AirのSafari 17では、フィンガープリントは124.03516124.04545の範囲で変動し、差は約0.008%
  • ブラウザごとの従来のオーディオフィンガープリント差のうち最小値は0.0000023%で、Safariのノイズ幅よりはるかに小さい
  • ノイズを消すには小数点1桁レベルまで丸める必要があるが、6桁未満しか残さないと一部のブラウザを区別しにくくなり、一意性が低下する

新アルゴリズムの3段階

  • FingerprintJSの新しいオーディオフィンガープリントアルゴリズムは、Safariが追加したノイズを減らすために3つの段階を踏む
    • ノイズの分散を減らす
    • ブラウザ識別子数値どうしの距離を広げる
    • 残ったノイズを丸めで取り除く
  • 従来のオーディオフィンガープリントは500個のオーディオサンプルの合計なので、各サンプルに一様分布ノイズが加わると、全体のフィンガープリントノイズは正規分布に近づく
  • 正規分布の平均は多くのサンプルの平均で推定する必要があるが、一様分布の平均はminmaxを使った(min+max)/2で、より少ないサンプルから高精度に推定できる
  • 実験コードでは、同じ精度条件で正規分布は524,288個のサンプルが必要だったのに対し、一様分布は4,096個で十分だった
  • 新方式は合算フィンガープリントの代わりに単一のオーディオサンプルだけを収集し、一様分布ノイズを扱うように変更した
  • この変更により新しいフィンガープリントは従来のフィンガープリントと互換性がなく、訪問者識別子を失わずに移行するには別のアプローチが必要になる

同じオーディオサンプルのノイズ付きコピーを作る

  • AudioBufferインスタンスでgetChannelDataを複数回呼び出す方法は機能しない
    • ノイズは各AudioBufferインスタンスごとに1回だけ適用される
    • 同じインスタンスのgetChannelDataは同じ信号を返す
  • オーディオ信号生成プロセス全体を何度も実行すれば多くのAudioBufferインスタンスを作れるが、フィンガープリント計算用としては遅すぎる
    • 6,000個のノイズサンプルではM1 MacBookで最速でも7秒だった
    • 60,000個ではSafariが処理を終えられなかった
  • より良い方法は、同じオーディオ信号を繰り返すAudioBufferインスタンスを作ること
    • 1つ目のオーディオ信号をレンダリングするが、getChannelDataは呼び出さない
    • より長い2つ目のOfflineAudioContextを作り、元の信号をAudioBufferSourceNodeとして使う
    • looploopStartloopEndで元の信号の一部を繰り返す
    • 繰り返しの後でSafariがノイズを加えるため、同じオーディオサンプルに異なるノイズが適用されたコピーを得られる
  • この方法なら、オーディオレンダリング2回だけで必要な数のノイズ付きコピーを作れる
  • ノイズが完全に消えるわけではないが、元のオーディオサンプルより分散は小さくなる
    • 8,192個のコピー: 100回実行結果の範囲 0.000387%、M1 MacBook基準 2.6ms
    • 65,536個のコピー: 0.0000123%4.1ms
    • 262,144個のコピー: 0%7.5ms

ブラウザ間のオーディオサンプル差を大きくする

  • コピー数を減らすと性能は良くなるが結果の分散が大きくなるため、ブラウザ間のオーディオサンプル差を拡大する目的でベース信号を変更する
  • 複数の組み込みオーディオノードを試した結果、ブラウザ間のサンプル差が大きくなる信号生成チェーンは次の通り
  • オーディオ信号の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
  • 最終的な選択は有効数字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
  • 新アルゴリズムの性能は従来比で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というランダムな乗数を1回生成し、すべてのオーディオサンプルに同じ値を乗算する
    • この値はページ内で維持される
    • 新しい通常セッションまたはシークレットセッションでのみ変わる
  • Braveでは、どれだけ多くのオーディオサンプルのコピーを作っても全コピーに同じノイズが適用されるため、Safari向けの数学的ノイズ除去方式は機能しない
  • ただし以前のBrave向けノイズ除去方式は引き続き機能し、ブラウザ間のフィンガープリント差を大きくする新しい信号生成方法は許容誤差を広げられる

FingerprintJSへの適用

  • 新しいオーディオフィンガープリントアルゴリズムはFingerprintJSで従来方式を置き換えており、4.2.0で初めて公開された
  • 実装全体のコードはFingerprintJSのGitHubリポジトリにある
  • オーディオフィンガープリントは、オープンソースライブラリがブラウザフィンガープリントを作る際に使う複数のシグナルの1つ
  • FingerprintJSは、ブラウザから取得できるあらゆるシグナルを無条件に含めるのではなく、各シグナルの安定性と一意性を個別に分析し、フィンガープリント精度への影響を判断している
  • オーディオフィンガープリントは一意性への寄与は小さいが、安定性が高く、全体のフィンガープリント精度をわずかに高めるシグナルと評価されている

1件のコメント

 
GN⁺ 2024-03-11
Hacker News のコメント
  • オンラインでユーザーを識別する別の興味深い手法として GPU フィンガープリンティングがあり、2022年に「DrawnApart」というコードネームで紹介された
    WebGL で GPU の実行ユニット数と速度を数え、頂点レンダリングの完了時間や stall 関数の処理などを測定する方式

    1. https://www.bleepingcomputer.com/news/security/researchers-u...
    • ブラウザは基本的に ソフトウェアレンダラーを使うべきで、ハードウェア GPU のレンダリング経路を開くときは、マイクやカメラのようにサイトがユーザーの許可を求めるべき
  • 最近は特に サイドチャネル攻撃への関心を見ると、データが漏れる値に一様ノイズを加える方式は、ほぼ当然ながら効かないと思う
    サンプルを多く集めればノイズを除去できるから。Safari がなぜこれを入れたのか分からない。フィンガープリンティングを面倒にはできるかもしれないが、この記事のように結局は何らかの形でおおむね突破可能に見える

    • Apple の最近の プライバシー機能の多くは、マーケティングに近いと思う
      技術的に効果があるかよりも、大衆にそれらしい話をできるかが重要になった プライバシー劇場のように感じる
  • そもそも、なぜ結果が違ってくるのか説明してもらえる? たとえば オーディオフィンガープリンティングがなぜ可能なのか気になる

    • 核心は、Web Audio API には多くの数学演算を行うアルゴリズムがあり、ブラウザごとに実装が少しずつ異なり、正確な結果が OS と CPUにも依存するところにあるように見える
      Web Audio API で小さな信号を作ると、どのブラウザもほぼ同じ結果を出すが、ごく小さな差を使って相互に識別できる
    • WebGL で使われる似た手法のように、PC の グラフィックカードドライバーとハードウェア自体から多くのエントロピーが出てくるのと似ていると思う
      ブラウザ開発者がこれを防ぐために、オーディオバッファ処理にノイズを加えなければならないのは残念
    • 自分も最初にそう思ったし、ここでより詳しく扱われている: https://fingerprint.com/blog/audio-fingerprinting/#why-the-a...
      要約すると、同じコードベース内でも異なるコードパス、たとえば SIMD 版が微妙に異なる 浮動小数点結果を生み得る。浮動小数点演算は演算順序などに予想以上に敏感だという点に関係していそう
    • 実装の詳細と コンパイラ最適化が原因である可能性が高い。たとえば浮動小数点の加算は交換法則が成り立たない
      同じアルゴリズムと同じ公式を正しく実装しても、結果が少しずつ異なることがある
  • 間違っていたら直してほしい。ここでフィンガープリンティング回避が成功する理由は、Web Audio API の仕様で OscillatorNode のアンチエイリアシング処理方法をこのように開いた選択にしたことに帰着するように思う
    「このエイリアシングを避けるために実装が取り得る実用的なアプローチはいくつもある。アプローチにかかわらず、理想的な離散時間デジタルオーディオ信号は数学的によく定義されている。実装上のトレードオフは、CPU 使用量という面での実装コストと、この理想にどれだけ忠実に到達するかにある。実装がこの理想を達成するためにある程度注意を払うことは期待されるが、低性能ハードウェアでは、より低品質で低コストなアプローチを検討するのが妥当である」
    私には、これはここで悪用している OscillatorNode の出力が、ブラウザ間で、さらには同じブラウザでも異なるハードウェア上ではほぼ確実に決定的ではないという意味に見える。非決定性は、ブラウザが選んだアンチエイリアシング方式、またはハードウェアに応じて同じブラウザ内で選択される複数の経路に基づく。同じアンチエイリアシングアルゴリズムの変更や修正も含まれる
    なぜアンチエイリアシングをブラウザに任せたのかはよく分からない。高品質なオーディオアプリやライブラリは、自分が生成する信号のエイリアシング回避方法を完全に制御したがるだろうし、標準のオシレーターは使わないはず。逆に、任意のアンチエイリアシングアルゴリズムとそれに伴うブラウザごとの差を受け入れる Web アプリなら、そのアルゴリズムがハードコードされた SIMD 命令であれ、20MB の JavaScript Web Audio ヘルパーフレームワークであれ、あまり気にしない可能性が高い
    1: https://webaudio.github.io/web-audio-api/#OscillatorNode
    HTML5 パーサーを標準化するときに Hixie が使ったのと同じ解法を、ここに適用できるのかも気になる。特定分野の専門家が十分良好に動作する正確で決定的なアンチエイリアシングアルゴリズムを指定し、その後すべてのブラウザがそれを使う、という形だ。測定可能な性能低下は、標準のアンチエイリアシング付きオシレーターで信号を生成する Web Audio API チュートリアルくらいでしか見えなさそう

    • 高品質な アンチエイリアシングはコストが高い
      だから、利用可能な演算リソースやバッテリーなどに応じて、実装がどれだけ使うかを決められるようにしたいのだと思う
  • ブラウザに ノードグラフ型のオーディオ APIを入れたのは愚かだった。AudioWorklet だけがあるべきだった

    • Mozilla が提案していたオーディオ API のほうが単純ではなかった? 自分の理解では、人々がより豊富な API とより低いレイテンシを望んだため、Google 側の提案に押された
      https://web.archive.org/web/20120505042746/https://developer...
    • なぜそう思う?
  • 気持ち悪い

    • 私もまさにそう思う。興味深いけど気持ち悪い
      そもそも、なぜ音声 API がウェブサイトの権限なしに使えるのか分からない。「このサイトがサウンドデバイスを使用しようとしています」のような簡単なダイアログで簡単に直せそうに見える
    • 今のネットワークスタックをこれから100年使い続けていいのか、と考えさせられる
      現在の形のインターネットは、パーソナルコンピューティングの夢をかなり台無しにした。企業や国家が個人に比べてあまりにも非対称に強いからだ。自分の技術が明示的な承認なしにサーバーへデータを送れるべきなのだろうか?
    • その通り。この人たちがこれを誇らしげにしているのが信じられない
      一方で、ブラウザキャッシュを消して VPN を有効にしたら、私を新規訪問者だと誤認してはいた。それでもビジネスモデルは卑劣だ
    • fingerprint.com という点に、ある程度の皮肉があると思った。税負担を避ける抜け穴を広めるウェブサイトが現れて、世の中が気持ち悪がってその抜け穴を塞ぐようになるのに似ている
      たとえ希望的観測だとしても、こうした研究を公開して表に出すことには大きな価値がある。特定ブランドの緑色のバックパックが窃盗に役立つという記事が出たからといって、みんながもっと盗むようになるのではと心配するより、店側がその手口により気づきやすくなる可能性に賭けたい
  • 各サンプルにランダムな値を加える代わりに、Safari は毎時変わるキーに基づく決定論的ノイズを加えることもできそうだ
    音声サンプルとキーの関数にすれば、同じセッションではノイズが同じだが、1時間後の追跡には役に立たなくなる

    • そういうサンプルを10個平均すれば、結局デバイスの実際の値に近づく。サンプルが多いほどさらに近づくだろう
      これを直すには情報漏えいそのものをなくす必要があり、ランダムな偏差の層で覆い隠すだけでは不十分だ
    • 追加されるノイズが**オリジン(origin)**を基準に決定論的なら役に立つのでは? そうすれば過剰にサンプリングして平均しても取り除けない
      例えば RNG_SEED = HMAC_SHA256(PERSISTENT_SECRET,Location.origin) のような方式だ
  • いよいよ本当に JavaScript をオフにしてウェブを見る「そういう人」になる準備ができた

    • 問題は、そうやって「そういう人」になるだけでも識別に10ビット以上を渡してしまう可能性があることだ
      ほかの場所から数ビットかき集めるだけで、一意に識別され得る。それでも私の基準では、この人たちは広告技術業界の残りと一緒に Golgafrinchan Ark B に乗せて送り出していい
    • 幸運を祈る。最近のウェブに、まともな昔ながらの HTML がどれほど少ないかには驚くほどだ
      少し前に訪れたウェブサイトはマークアップを使ってはいたが、それを HTML にコンパイルして静的に配信するのではなく、クライアント側 JavaScript でレンダリングしていた。WTF
    • 一緒にやろう。実際にやればいい。uMatrix という優れた Firefox 拡張機能があり、サイト単位だけでなくサブドメイン単位でも JavaScript を簡単にオフにでき、JavaScript なしでは壊れるサイトではオンに戻すのも簡単だ
    • 幸運を祈る。最近この戦いを諦めた。訪問するほぼすべてのウェブサイトで、コンテンツを見るには JavaScript を再び有効にする必要があったからだ
      Cloudflare のような DDoS チェックだけでなく、今ではページ HTML の中にあるべきものまで JavaScript で読み込まれる
    • まさにこういう理由で Tor Browser は JavaScript をオフにすべきなのだ
      インターネットがますます敵対的になるほど、この選択はますます正しい方向になる
  • この方法で数千以上の固有の組み合わせを作れるというのが、よく理解できない
    ブラウザ種別 × ブラウザバージョン × OS バージョン × アクセラレータのバージョン × …あと何がある? リモートで一意だと言えるほどの変動が十分にあるようには見えない

    • 組合せ論は厳しい女主人だ
  • この手法は、音声処理におけるハードウェア、ドライバ、OS の違いを基準にフィンガープリントを取るものなのか、それとも単にブラウザソフトウェアだけを見ているのか?
    下位のグラフィックデバイスの違いを露出する似たような手法があった、あるいは今もあると思う

    • 似たような仕組みだ。音声アルゴリズムはしばしばOS 関数を呼び出し、CPU 最適化を利用する
      記事で挙げられている例の1つが高速フーリエ変換(FFT)だ。すべての OS にはこの関数のバージョンがあるが、時間とともに最適化される傾向があり、利用可能な SIMD 命令によって CPU ごとに異なる動作をすることが多い