=kthrtty/(+blog)

最近旅してないフルスタックサラリーマンジャーマネの旅行の記録

思わず天を仰いでしまうID関連システムトラブル

こんにちは。アドカレ12/24の記事を簡単にではありますが書かせていただきました。(25日のポストで遅刻ですが)

Digital Identity技術勉強会 #iddanceのカレンダー | Advent Calendar 2023 - Qiita

はじめに

本日のテーマ:思わず天を仰いでしまうID関連システムトラブル

本日のテーマは、みんな大好き「トラブル」の話です。CIAM(Consumer Identity and Access Management)領域のさまざまなシステムにさまざまな立場で関わり、さまざまなトラブルに遭遇してきた経験を踏まえて、クリスマスの合間の気楽な読み物として記載しましたので、一息ついていただければ幸いです。

今回はトラブルの中でも思わず「天を仰いでしまう」激ヤバトラブルにフォーカスして、私的ランキング形式でお届けしたいと思います。

 

天を仰ぐトラブルとは?

私の経験の範疇ですが、事象の初報を聞いた、あるいはトラブルメールが届いた際、その瞬間に「あぁ最悪だ終わった」という気持ちで天を仰いでしまうようなトラブルです。オフィスチェアに座っている場合は、背もたれでのけぞって精一杯「終わった」感を表現します。

緊急召集をかけ、対策室として他チームの予定でぎっしりの会議室を強引に確保させてもらい、全体統括、お客様との渉外担当、時系列の記録係、本番アクセスログ分析、アプリ分析担当など分担を決めて対処していきます。

全社のトラブル経営連絡MLにも投げ込みます。しばらくするとどこかの部門から突如横槍がはいります。予想通りです。関係性が良くない役員がいたりした場合「ほらみたことか、あのシステムはやばいから注意して見ておけ」などというバイアスまみれの事前吹聴により、本社セキュリティ部門から謎の連絡要員がやってくることもあるでしょう。別にいいです受け入れます。バイアスなく冷静にみてくれるのであれば。

お客様が「30分に1回」進捗を報告せよ、と仰る気持ちは理解しつつも、対策室には「短すぎて進捗ないよ・・・」と暗い雰囲気が立ち込めます。数時間のうちにお客様側では基幹システム停止時などに開催される緊急役員会議が開催され、報告できるほど状況が整理しきれていなくても報告をしに行きます。トラブル耐性の強い社長あるいは担当役員であれば自ら「人質」を買って出てくれることでしょう。短期的なトラブル解決に直接作用するわけではありませんが、アイコニックな存在としてお客様の経営に「本気」を伝えつつ、強力な緩衝帯として機能してくれます。こうありたいと思います。時にはテンパリ過ぎて恫喝傾向が出る人がいたりと、強いプレッシャーに曝されることによる人間の本質が垣間見えることもあります。こうありたくはないと思います。

数日は寝れない&帰れないかもしれません。クリスマスのデートや長期休暇の旅行をキャンセルする人もいるかもしれません。さすがに休暇の特別な予定を返上させるようなことのない組織と体制であれと常々思います。

 

長く仕事をしていれば、そういうトラブルに対処しなければならないことありますよね。

 

注意事項

なお、今回掲載しているトラブルは、一部の明らかな事実への参照を除いて全てフィクションです。現実の出来事、人物、所属する組織とは一切関係ありません。バグは存在する、トラブルは起きることを前提としています。

 

どいういうバックグランドで書いているか

主にCIAM領域で10年超の経験を持ちます。内容は営業・企画・コンサル・開発・運用まで様々でした。およそ15年前にOpenID 2.0のDraft版に関わってからの縁で、OpenID Foundation Japanの法人設立を進めたり、OP/IdPのSIをしたり、IDビジネスコンサルをしたり、Identity関連のデジタル犯罪のインシデント対応などをしていました。

その後は、がらり変わってWebセキュリティ診断、重要インフラや自動車セキュリティ事業を率いたのち、現在はクラウドのセキュリティ課題解決に日々勤しんでいます。

ご縁もあり、去年から紀尾井町方面のIdentity関連の会議に呼んで頂いており、世の中が少し良くなるようにと取り組んでいます。重鎮が多く視点も充実しているので寧ろ楽しんでいるきらいもあります。

トラブル

早速、勝手ながらランキング形式でお届けします。

 

第3位 任意のユーザーへのなりすましが可能

第3位はOWASP Top 10でも登場する、アクセス制御不備(Broken Access Control)を原因とした「任意のユーザーへのなりすまし」です。これ1位じゃないのと思う方がいるかもしれませんが、私が勝手に決めたランキングなので気にしないでください。

 

「大変です!多くの一般ユーザーの方から意図しない取引履歴があるというお問い合わせが殺到しているみたいです!」と一報がはいりました。天を仰ぎます。つらい。

 

この事象は、特にID関連システムの文脈で原因を考えると、以下が定番でしょう。

  • 認可機構と業務ロジックとの対象ユーザ不整合
    • 例えばOAuth/OIDCベースのAPI認可を採用しているシステムにおいて、アクセストークンを利用してAPI認可しているのに、業務ロジックではペイロードで指定されているID識別子だけをみて動作してしまい、誰でもいいからAPI認可さえ通過すればペイロードで指定した任意のユーザーに干渉できるというものです。よくIDOR(Insecure Direct Object Reference)脆弱性と言われたりするのを見かけたことがある方いるかもしれません。
  • 認証アサーションの検証不備
    • 認証アサーション(OIDCだとID Token)の署名チェックに不備があり、例えば自由に組み立てたID Token(JWT)に埋め込まれたユーザーのID識別子だけを見て動作してしまうので、任意のユーザーの認証アサーションを作成し、なりすませてしまうというものです。7payのケースでは似たような事例が報告されていますが、報道ではこの問題が原因ではないとされています。

 

内容自体はシンプルなのですが、いずれも根深い不具合です。

認可機構と業務ロジックとの対象ユーザ不整合

極めて単純で、共通の認可処理で特定できるユーザーと、ペイロードで指定された(おそらくユーザーの所有する)何らかのオブジェクトの識別子との関連性のビジネスルールをチェックすべきところをしていない、というものです。ただ、そうなってしまう気持ちはわかります。共通の認可処理と、個々のAPIの業務ロジックを作っている人が分業・あるいは認可処理がAPI Gatewayに分離されていたりすると、システムを組み上げた際の視点が乏しいコードレビューやテストケースでは抜けることもあるかもしれません。

勝手ながら私の好みでいうと、ユーザーの権限で動作するAPIについてはアクセストークンからユーザーを特定せざるを得ないようにペイロードにユーザーIDを入れないようにして、APIロジックの作成者にアクセストークンから特定されるユーザーを意識せざるを得なくする、あるいはAPIの操作対象のマイカーIDみたいなものをペイロードに入れたとしても、データベースのテーブル定義で最初から(ユーザーID, マイカーID)のタプルでなければ検索できないようにしてIDORが起こりにくいような"Fail Safe"なAPI設計は良いと思っています。

ただし、作り手への制約の付け方はチームの構成や開発スタイルに大きく依存するので、一例として記載するに留めておきます。制約を課す設計が大嫌いな先輩と口論になったことがあり、後輩には冷ややかな目で「またあいつらやってるよ」と思われてしまったようで反省しています。

冒頭に書いた通り、ちょっと前に自動車セキュリティをやっていたのですが、コネクテッドサービスのアプリでもIDORの脆弱性が話題になることを複数回見かけました。サイバーフィジカルなシステムにおいてはアクセスコントロールの不備は物理世界への干渉につながるので、下り(車両側)方向の制御というのは慎重に慎重を期して開発していくものだと常々考えています。IoTにアイデンティティレイヤー導入するサイバーフィジカルなコネクテッドサービスは本当に楽しいので、利用者の誰もがセキュリティを気にせず楽しいところだけ味わってもらえると良いですよね。

認証アサーションの検証不備

こちらもフェデレーションにおいては伝統的かつ影響の大きな問題です。SAMLでもOIDCでも時々見かけます。以下のようなイメージです。

  • アサーションが署名されておらず、チェックもしておらず、なりすましにつながる
  • アサーションが署名されているが、チェックしておらず、なりすましにつながる
  • アサーションが署名されており、チェックもしているが、署名範囲が誤っており、結局なりすましにつながる

 

今回は特にOIDCのID Tokenを取り上げます。今でこそセキュリティ診断を生業としている方達の中でも常識となりましたが、数年前はJWTのヘッダに "alg":"none" として署名なしを選択したJWTを作成し、ID Tokenを受け付けるエンドポイントに投げつけたりすると、署名なしを受け入れて、ペイロードに記載されたユーザーID識別子を署名未検証で信じて動く、なんてものもありました。

サービス仕様で「署名なしは選べない」 と明記しつつ、テストをしておけば良い話ではあるのですが、ライブラリに任せてよしなにやってもらうことの多い処理だったり、そもそもJWT/JWSの署名なしが可能ということ自体に知見がないなどの理由で、うっかり作り込んでしまうこともあるでしょう。

IdPを開発するチームであれば、当然落としたくない観点ですよね。

 

第2位 ユーザーの入れ替わりが発生

悩んだのですがこちらを2位にします。「ユーザーの入れ替わり」が発生してしまった話です。リクエスト毎のスコープで同期的に物事を処理していけば、そんなことが起きる実装には普通ならないと思うのですが、OAuth2/OIDCの認可コードフローなどリクエスト元がブラウザとサーバーなど混在したりする場合や、非同期処理が出てくるとやらかし事例が出てくることはあるかもしれません。

 

「大変です!キャンペーンメールの一斉配信でアクセス集中したころから、ユーザーの入れ替わりが起きてるとお客様から連絡がありました!」と一報がはいります。天を仰ぎます。つらい。

 

典型的な原因はレースコンディション(Race Condition)です。並行度の高いアクセス状態が継続すれば、影響範囲がどんどん拡大していきます。「ちょっとログを見たぐらいでは分からない」類の障害のため、判断に時間をかけている間に、ダメージが蓄積していくのでつらいです。自主事業であれば止める判断が比較的素早くできるかもしれませんが、お客様事業だと止める判断を(あとから内部で刺されないように段取りアレンジと正当化)するため「経緯と影響範囲をまとめろ」みたいなことを言われます。事象認知の初期段階でこれが正確にできる人・会社はおそらく存在しません。ふわっとした速報しか出せません。少ない情報での判断を躊躇している間に影響範囲は広がります。サービスを止める判断基準は、平時のうちに議論しておきたいですね。

レースコンディションは細かく見るとさまざまな実装上の不具合が根本原因ですが、私がパッと心当たりがある範囲では以下のようなイメージです。

  • スレッドセーフでないコンポーネントクリティカルセクションを設けずに利用する、あるいは排他制御にバグがあるライブラリ利用により、入れ替わりが発生する
  • 精度の低いタイムスタンプを用いた導出ロジックで、ノード内・ノード間でユーザーに関する識別子が競合する
  • 乱数生成器が適切なものではなかなったり、乱数のシードがリクエストの都度同じ値で初期化されて同じ疑似乱数が生成されるなどの利用方法の不備で、ノード内・ノード間でユーザーに関する識別子が競合する
  • 特定条件でユーザーに関する識別子の元ネタ変数がNullのまま動き、ユーザーに関連するID「0」と評価されて競合する
  • TOCTOU(Time of Check, Time of Use)の問題でユーザーに関する何らかの値が競合する


この手の問題の検出にはまず設計とコードレビュー等前段で打ち取れるのが望ましいとして、私は負荷テストとの合わせ技で打ち取るのが大好きです。後から慌てないようにWBSには負荷テスト入れておきましょう。その際、データを大量に積み込んで認証周りの負荷テストするのは当たり前に実施されていると思いますが、ユーザーの入れ替わりも検出できるようにしておくことをお勧めします。例えばOP/IdPであれば、認可コードフローを回しつつ、UserInfoを叩いてレスポンスをみてユーザー入れ替わりを検知するAssertを入れておくことで効果があるでしょう。

最近では、マイナンバーカードを利用したコンビニで他人の住民票を発行できてしまうケースが報道されていました。件数の大小に関わらずステークホルダーのボルテージが上がりやすいID関連のトラブルですので、気をつけたいものです。

 

第1位 Pay系サービスと金融機関との連携で不正に金銭が窃取された

これも独断と偏見ですが、「Pay系サービスと金融機関との連携で不正に金銭が窃取」を第1位にしました。有名すぎるが故に名前が上がってしまう象徴的なものとしてはドコモ口座事件が記憶にある方も多いのではないでしょうか。これは、Pay系アプリで決済をするために資金をチャージする手段の1つとして、自身の銀行口座を連携させて紐づけるような機能を有するサービスでした。この連携・紐付け部分の弱さを突かれ、一般ユーザーの資金が不正に窃取されたとされる事案です。なお、ドコモに限らず、その周辺では似たような事象が風の噂で色々と聞こえてきています。事前か事後かは知るところではありませんが、いくつかの類似サービスで銀行との連携を停止する、といった対応がなされていたのを思い出します。

 

「大変です!一般利用者からうちのアプリの名前で銀行から身に覚えのない金銭の引き出しが行われた問い合わせが殺到しているみたいです!」と一報がはいりました。天を仰ぎます。つらい。

 

細かく見るとさまざまな原因がありますが、典型的なものはチャージ(入金)元の銀行と連携する際に、口座番号とキャッシュカードの4桁PINで認証が成功し紐付けができてしまい、更に銀行とPay系サービスの間で業務取引(チャージ操作に伴う資金移動など)ができるようになる、という点です。通常お金を引き出す際にはキャッシュカード(Something you have:所持)と4桁PIN(Something you know:記憶)の2つの要素が必要ですが、事象が発生するPay系サービスの連携ではいくつかの金融機関では「お客様番号/口座番号」と4桁PINがあれば資金移動ができる、つまりキャッシュカード(≒カード所有者)不在かつインターネット経由で経由で大量に、あるいはすでに漏洩している他の情報と組み合わせて戦略的に試行を繰り返しやすい仕組みになっていた、というわけですね。この時、口座番号+4桁PIN認証(+名義)ではなく、ある程度実績があり日々の不正な試行に対する何らかの取り組みがなされているインターネットバンキングのユーザー認証への導線を提供していた金融機関では被害が発生していない、あるいは発生していたとしても話題になっていないと記憶しています。

では、そもそもなぜこのような連携・紐付けをするサービス設計になるのかですが、その根拠は犯収法における「依拠」が関係します。ざっくりいうと依拠というのは「すでに銀行などの金融機関が法律に則って身元確認(Identity Proofing)を実施してくれているので、銀行で当人認証(Authentication)が成功すれば、自分たちのサービスでも推移的に Identity Proofing したとみなしても良いだろう」ということです。しかし現実には「依拠」という定義が曖昧なものを曖昧なまま取り扱っては考慮不足が出てしまい、実はきちんとパターン分けをして、リスク分析をしていなければ望ましくないことが発生するものである、ということをシステム関係者は認識するきっかけになった出来事でした。

なお、ここで「依拠するための」銀行側の認証が強化されればそれで万事OKということではありません。手前味噌ですが参考に以前作った資料からの抜粋です。

身元確認(Identity Proofing)のレベル、当人認証(Authentication)のレベルがそれぞれPay系サービス側、連携する金融機関側の組み合わせを一通り見て、もし〜だったら、自分のサービスには何が起きるのだろう、と考えていただくのが検討の良いスタート地点です。

 

例えば、分かりやすい例だと、ポイント集約が挙げられます。好きなだけPay系サービスのアカウントを作成でき、新規登録ポイントキャンペーンをやっていると、万が一ポイントを知り合いに送る機能があったりすると、ポイント無限集約という経済的なダメージが生じるわけです。バーチャルクレジットカードのチャージをカスケードさせてポイント多重取りしようとする話も似たような類の話ですね。

 

この整理で出てくるIdentity Proofingのレベル(IAL)、あるいはAuthenticationのレベル(AAL)は、認証にまつわる米国政府機関向けのガイドラインであるNIST SP800-63 Digital Identity Guidelineを参照いただくと概念を理解するのに良いのですが、結構ボリュームがあってわかりづらいという声もよく聞きます。

そういった場合は、これまた手前味噌ですが以下の「認証にまつわるセキュリティの新常識 rev.3」も併せて見ていただけると理解が捗りやすいと思います。

speakerdeck.com

 

またIdentity Proofingの深淵を覗くべくアマゾンの奥地へ旅立っていきたい方は、これまた手前味噌ですが私の「NIST SP800-63-4 IPD 63A: Identity Proofing 概要紹介 - Speaker Deck」も参考にしてみてください。

speakerdeck.com

崎村御大の「本人確認のニューノーマル」も外せませんね。

 

あるいはOpenID Foundation Japan KYC WGのガイドラインも参考になります。

www.openid.or.jp

 

NIST SP800-63は現在Revision4の改訂作業中で、現行版であるRev.3ではサービス同士の連携プロトコルのセキュリティレベルとしてFederation Assuarance Level(FAL)というものも定義されるようになりました。第1位の論点については「これを見ればよいじゃん」と思われるかもしれませんが、業務的な観点はほぼなく、暗号化や署名をするしないの話が中心です。サービス同士の連携を考える場合は、FALは足回りのセキュリティの参考にしつつ、その上位レイヤにサービス同士の連携に伴う業務上のリスクを考慮した対処を載せていくと良いでしょう。

 

ここまで私的に好みの「天を仰いでしまう」トラブルを3つご紹介してきました。
サービスの実装をする人も、サービス仕様の設計をする人も、IDに関する考慮事項やアンチパターンは多々あります。今回のフィクションを参考に、皆様が面倒ごとに巻き込まれずに平和に過ごすことができれば幸いです。

 

おまけ 「さとみ1224事件」

石原さとみさんの誕生日は12月24日です。メリークリスマス。

 

あるセンシティブな業界向けのお客様のシステムで、「大変です!お客様からコールセンターに連絡があり、ログインしたところ別の人の情報が見えたみたいです!」と一報がはいったとします。天を仰ぎます。つらい。

 

他人に見られてしまったお客様のアカウント名は "satomi1224" というものだという情報が寄せられます。パスワードは平文で保存していませんので分かりません。ログを見ますが何もおかしいところはありません。エラーも出ていません。並行でログイン回りのマルチスレッド処理に問題がないかをチェックする人がアサインされ、あるのか分からないバグを探し始めます。原因が分からないことへのお客様の苛立ちはつのり、ただ再現もせず暗中模索で悶々とした時間が過ぎていきます。大きな取引先ですので、頼んでもいないのによその部門からプレッシャーをかけにくる連絡要員が対策室にくることがあるかもしれません。

 

事象をご報告いただいたエンドユーザーの方と連絡がとれ、コールセンター部門から追加の情報が入ります。見てしまったお客様のお名前は「さとみ」さんで誕生日は「12月24日」だというではありませんか。

 

もうお分かりですね。同名かつ同じ誕生日の別の2人の方が、間違えて別の方のID/PWに一発で直撃させてログインしてしまうことがある、という話です。パスワードにIDと同じ文字列や誕生日などが含まれないようにチェックする、というのは悪意のない方が引き起こす偶発的なトラブルの防止にも役立つ訳ですね。

 

原因がわかるとプレッシャーをかけ続けてきた人たちはそそくさと帰っていくでしょう。憤りと怒りはそっと胸にしまいこんで、心の中の⚪︎⚪︎リストに加えておくにとどめます。何事もなかったのであればそれでいいのです。

 

メリークリスマス。