この記事は後半です。前半は Qiita にあります: WAFとサーバーでURLの“道筋”が違うとき——自動車メーカー認証基盤に潜んだ穴の入口
この件の面白さは、攻撃が派手なバイパスではなく、URLの解釈差だったことにある。WAFは「危ないパス」として止めるが、Java側は正規化した別のパスとして受け取る。さらにアプリ層でも、同じ文字列を別のルールで読む。結果として、外では静的ファイルに見えるリクエストが、内側では /openidm や /system/console に化ける。

画像: samcurry.net より
調査者は /static のような見かけの前置きに、エンコードされたスラッシュやドットセグメント、セミコロンを混ぜて試した。これでWAFの目をすり抜ける形が見つかると、今度はオリジン側で別のルーティングが起きる。ここで大事なのは、「WAFを無効化した」のではなく、「WAFが見た世界」と「サーバーが見た世界」が一致していなかったことだ。
OpenIDMの管理系パスは通常なら塞がれていた。ところが、正規化のズレを使うと、ヘルスチェックや管理コンソールの一部が到達可能になった。FelixのWeb Consoleでは、認証後にバンドル一覧まで見えている。つまり、単なる404のすり抜けではなく、Javaプロセスの内側にある管理面をのぞける状態だった。

画像: samcurry.net より
この話が危険なのは、ログイン画面の脆弱性では終わらない点にある。スマホアプリはForgeRockの認証フローを通り、セッションを得て、そのあとモバイルアプリ用のトークンへ交換する。ブランドごとに入口は違って見えても、裏では同じ認証基盤を使っていた。だから、ひとつの穴が複数ブランドへ広がる。
調査者が目指したのは、管理画面への侵入そのものではなく、そこから任意の顧客セッションを作れるかどうかだった。もしそれができれば、車両APIが使う権限まで届く。実際、報告文では、そのセッションから車両の位置情報やテレメトリ、ドアロック、エンジン始動と停止まで可能だったとされる。認証の問題に見えて、実態は車の遠隔操作の入口だったわけだ。
ここでの限界もはっきりしている。調査は複数地域にまたがるサービスに及んでいたが、完全なチェーンを確認したのは米国アカウントと車両だった。つまり、「理屈の上でどこまで広がるか」と「実際に証明した範囲」は分けて読むべきだ。こういう事案では、盛って解釈しないことがむしろ重要になる。
報告後およそ2時間で修正と資格情報のローテーションが行われた、というのがこの話の締めだ。短い時間だが、裏を返すと、それだけ緊急度の高い欠陥だったとも言える。管理用の隠しパスが見えるだけならまだしも、認証基盤の中で顧客セッションを作れるとなると、影響は一気に広がる。
ただ、速く直ったから安全だった、とは言い切れない。重要なのは、短時間で止められたのではなく、止めざるを得ない形だったことだ。認証、WAF、管理画面、トークン交換が一本の線でつながっていた以上、どこか一箇所の設定修正だけでは不十分になる。資格情報を回す判断が入るのも自然だ。
自分ならこの話を、車の話としてよりも「境界でURLを解釈し直す設計の危うさ」として読む。とくに、WAF、リバースプロキシ、サーブレット、アプリが別々にURLを扱う構成では、正規化の差分を前提に防御を置くべきではない。静的パスの下に管理機能をぶら下げる発想も、いったん外に出た瞬間に危ない。
実務で似た構成に当たったら、私なら最初に「同じURLを何回も読ませていないか」を見る。WAFで弾いたはずのパスが、別の正規化後に生き返る余地がないか。管理画面だけを隠しているつもりで、実は認証基盤の入口を広く開けていないか。ここを先に疑うだけで、見落としはかなり減る。
そして、connected car のように複数ブランド、複数地域、複数管理画面が混ざるサービスでは、入口の見た目が違っても中核が同じことを疑ったほうがいい。今回のように、番号からアカウント、アカウントからトークン、トークンから車両操作へ進むなら、脆弱性は一つではなく連結の中にある。そこを切り分けて見ないと、穴は最後まで見えない。