Web フィンガープリント生成機構の逆解析と環境シミュレーション

ウェブセキュリティ対策として導入されるデバイス指紋識別システムについて、その生成ロジックの解析手法と、サーバー側での再現環境構築手順を技術的な観点から解説する。

パラメータ構造の解析

対象システムでは、認証リクエストに含まれる特定の識別子(blackbox)が重要となる。この値は固定ではなく、トークン ID とランダム要素、および環境情報に基づいて動的に生成される。

難読化されたソースコードを解読すると、以下の様な文字列操作が行われていることが確認できる。

function generateSignature(tokenId) {
    const charSet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
    const mappingTable = "0123456789abcdef";
    const shiftMap = "ghijklmnopqrstuv";

    // トークンの分割と変換
    const part1 = shiftMap.charAt(mappingTable.indexOf(tokenId.substring(0, 1)));
    const part2 = tokenId.substring(1, 4);
    const part3 = tokenId.substring(4, 14);
    const part4 = tokenId.substring(14, 22);
    const part5 = tokenId.substring(22, 23);

    // ランダム要素の挿入
    const randomChars = [
        charSet.charAt(Math.floor(Math.random() * 62)),
        charSet.charAt(Math.floor(Math.random() * 62)),
        charSet.charAt(Math.floor(Math.random() * 62))
    ];

    // 最終的な結合ロジック
    return part1 + part2 + randomChars[0] + part3 + randomChars[1] + part4 + randomChars[2] + part5;
}

この関数は、入力されたトークン ID を特定の規則で分割し、その合間にランダムな文字を挿入することで最終的な署名を生成する。

トークン ID の取得経路

署名生成に必要なトークン ID は、専用の API エンドポイントを通じて取得する。リクエストにはパートナー識別子やアプリケーション名、タイムスタンプなどが含まれる。

GET /web3_8/r.json?partner={id}&app_name={name}&token_id={temp}&idf={id}&v={version}...

レスポンスとして返却される JSON データ内に、後續の処理で必要なトークン値が含まれている。

実装アプローチの選定

加密ロジックを再現するには、主に二つの手法が考えられる。

コード抽出と AST 解析

難読化された JavaScript コードを AST(抽象構文木)を用いて整形し、核心となる加密関数を特定して抽出する手法。環境依存度が低い値を固定化し、必要な入力値を特定する必要がある。

環境シミュレーション(補環境)

Node.js などでブラウザ環境を模倣し、実際の JS ファイルを実行させる手法。ブラウザ固有のオブジェクト(window, document, navigator など)のモック実装が不可欠となる。

動的に変化するアルゴリズムに対処するには、環境シミュレーションの方が汎用性が高い場合が多い。

環境構築の詳細

実行環境を整備する際は、ブラウザの挙動との差異を最小限に抑えることが重要である。プロキシを活用して通信ログを確認し、不足している API やプロパティを順次実装していく。

特に、Canvas フィンガープリントや WebGL 情報、および標準組み込みオブジェクトの toString 値などが検知対象となる可能性があるため、注意深い実装が必要となる。

スクリプト読み込みフロー

実際のページでは、以下のような手順で指纹スクリプトがロードされる。

const config = {
    partner: 'example_partner',
    appName: 'example_web',
    token: `example-${Date.now()}-${Math.random().toString(16).substr(2)}`,
    fpHost: "https://fp.example.net"
};

// トラッキング用イメージの読み込み
const tracker = new Image();
tracker.src = `${config.fpHost}/fp/clear.png?partnerCode=${config.partner}&appName=${config.appName}&tokenId=${config.token}`;

// 本体スクリプトの動的挿入
const script = document.createElement('script');
script.async = true;
script.src = `${config.fpHost}/v3/fm.js?ver=0.1&t=${Math.floor(Date.now() / 3600000)}`;
document.head.appendChild(script);

このフローを再現し、コールバック関数で返却される値を取得することで、有効な指纹データを得ることができる。環境構築が完了していれば、生成された値を用いて認証プロセスを通過可能である。

タグ: javascript reverse-engineering fingerprinting nodejs web-security

5月21日 11:02 投稿