2023年4月3日月曜日

2023年4月においてクリックジャッキング未対策のサイトはどの条件で被害を受けるか

サマリ

CookieやlocalStorage等でセッション管理しているウェブサイトがクリックジャッキング対策していない場合、どの条件で被害を受けるかを説明する。SameSite属性のないCookieでセッション管理しているウェブサイトは、主要ブラウザのデフォルト設定ではクリックジャッキングの影響を受けない。一方、loaclStorageにトークン類を格納するウェブサイトでは、Google Chrome等のブラウザでクリックジャッキングの影響がある。また、ブラウザの設定を変更した場合の影響についても説明する。

クリックジャッキングとは

クリックジャッキングとは、一言で説明すると「ウェブサイト利用者に意図しないクリック(タップ)をさせる」攻撃です。ウェブサイト上で意図しないクリックを勝手にさせられると、重大な結果になる場合があります。例えば、このURLを閲覧すると、以下のようにTwitterにて「犯行予告を投稿する」画面になり、「ツイートする」を押すと、押した人のアカウントで犯行予告をツイートする結果になります。Twitterのこの機能はウェブインテントと呼ばれます。

このような拙い「攻撃」だと、被害者は画面内容を見た結果ツイートボタンは押さないわけですが、これにiframeを用いた仕掛けを組み合わせて「知らない間にボタンを押させる攻撃」がクリックジャッキングです。具体的には、iframeを用いて、下図のようにボタンを押させるための罠と、Twitter等の掲示板の画面を重ねます。

この際、掲示板を手前に配置してCSS設定により透明にします。一方罠サイトは奥側に配置します。すると、見た目上は罠サイトだけが見えますが、ボタンをクリックすると手前側の掲示板のボタンを押したことになり、ログイン中の利用者のアカウントで意図しない投稿がされます。これがクリックジャッキングです。現実のTwitterはクリックジャッキング対策がされているので、この攻撃は成立しません。

この例では「意図しない投稿」でしたが、これ以外に、設定変更や退会など「クリックだけでできる操作」全てで影響がありえます。

クリックジャッキング対策には、以下のようなレスポンスヘッダを出力することで行われます。

Content-Security-Policy: frame-ancestors 'none';

上図はCSPを用いた対策ですが、伝統的なX-Frame-Optionsヘッダを用いた対策も有効です。

しかしながら、上記対策をしていない場合でも、モダンブラウザでは、iframe内のコンテンツからCookieおよびlocalStorageへのアクセスが制御されていて、クリックジャッキング攻撃ができないケースが多くなっています。
本稿では、モダンなブラウザの利用者がクリックジャッキング被害を受ける条件について説明します。

検証方法

今回は、クリックジャッキングの影響の有無を、iframe内のウェブページがCookieやlocalStorageの値を受け取れるかどうかで判断することにしました。もしもiframe内のページがCookieやlocalStorageにアクセスできない場合、ページはログイン状態にはならず、被害者のアカウントでの投稿や設定変更などはできないからです。
下図は検証環境の模式図です。サイトAがクリックジャッキング脆弱なサイト、サイトBは罠サイトです。

サイトAのログインを模して、CookieやlocalStorage、sessionStorageをセットします(図の左側)。この後サイトBに遷移しますが、サイトB内にiframeがあり、その中にサイトAのページがあります(図の右側)。このiframe内のサイトAのページでCookie、localStorage、sessionStorageの値を表示して、これらの値を受け取れているかを確認します。

CookieのSameSite属性は以下の3種類のものを用意しました。SameSite属性の意味についてはこちらの記事を参照ください。

  • SameSite属性なし
  • SameSite=None
  • SameSite=Lax

SameSite属性なしは伝統的なセッション管理を想定しています。SameSite=Laxの場合、iframe内のコンテンツにCookieは送信されないはずですが、比較のためテスト条件に加えました。

検証結果

検証結果を下表に示します。

結果の要約は下記の通りです。

  • SameSite属性のないCookieでセッション管理しているサイトは全てのブラウザにてクリックジャッキングの被害を受けない
  • localStorageでセッション管理しているサイトは、Google Chrome、Edge、Opera(デスクトップ、Android)のユーザが被害を受ける
  • Brave、Firefox、Safariの利用者はいずれのケースでもクリックジャッキングの被害を受けない

このように、ブラウザのセキュリティ機能の差により、クリックジャッキング被害の条件が変わっています。


各ブラウザのセキュリティ機能

次に、各ブラウザのセキュリティ機能がどのようにクリックジャッキングを防いでいるかを説明します。

Chromium系ブラウザの防御はデフォルトSameSite=Lax

CookieのSameSite属性にてLaxあるいはStrictを指定した場合、iframe内に置かれたページに対してはCookieは送信されません。これはすべてのブラウザに共通の仕様ですが、Chromium系のブラウザ(Google Chrome、Edge、Brave、Opera…)では、SameSite属性のないCookieはSameSite=Laxとして扱われます(参考)。
このため、SameSite=Noneを明示的に設定していないCookieは、iframe内のページには送信されないことになります。SameSite属性は、もともとはCSRF対策を意図した機能と思われますが、クリックジャッキング対策にも効果があります。
デフォルトSameSite=Laxの効果はCookieのみであるため、sessionStorageとlocalStorageには効果が及びません。

※注
SameSite属性のないCookieは、Cookieが生成されてから2分以内であれば、クロスサイトのPOSTリクエストに付与されます(参考)が、iframeの場合はこの2分間の猶予期間はなく、ただちにSameSite=Laxとして扱われます。

Firefoxは2022年1月11日にデフォルトSameSite=Laxを導入しましたが、非互換を理由に直後にキャンセルされました(参考)。現在でも、SameSiteのデフォルトは、SameSite=None相当です。
一方、Firefoxは2022年6月14日に包括的 Cookie 保護(Total Cookie Protection:TCP)と呼ばれる機能を投入しました。TCPはセキュリティ目的というよりはプライバシー保護を目的としたものですが、クリックジャッキング防御にも効果があります。

下図は包括的Cookie保護(TCP)のイメージ図です(引用元)。

従来は一つのCookieの入れ物(cookie jar)をすべてのサイトで共有していました(上図左)が、TCPが有効になるとサイト毎にcookie jarが独立するようになります(上図右)。これだけだと抽象的でわかりにくいので、サイトAがサイトB、サイトCのiframeにて表示されている様子を用いて説明します(下図)。

上図のように、サイトAのCookieは、単独で表示されている場合(左)、サイトBのiframe内で表示されている場合(中央)、サイトCのiframeで表示されている場合(右)で、それぞれ別の値となります。この機能はサードパーティCookieによるトラッキングを防ぐ目的で導入されたものですが、セッション管理のCookieもiframe内では分離・保護されるため、結果としてクリックジャッキングに対する防御として作用します。また、Cookieだけでなく、sessionStorageやlocalStorageもサイト毎に分離されます。

なお、実験による検証の結果、Braveブラウザにも包括的Cookie保護と同様の機能が実装されているようです(sessionStorageの挙動はFirefoxともSafariとも異なりますが、詳細は省略します)。BraveはChromiumベースのブラウザなので、デフォルトSameSite=Laxも実装されています。

Safariの防御機能はITP(Intelligent Tracking Prevention)

Safari(WebKit)にはITP(Intelligent Tracking Prevention)というトラッキング防止機能があります。これにより、結果としてクリックジャッキングも防御されています。
下図は、ITPによりiframe内のページのCookieがどうなるかを模式的に示しています。

サイトAでセットされたCookieは、サイトBにiframeで埋め込まれてもCookieは送信されず、またレスポンスのSet-Cookieも無視されます。すなわち、iframe内ではCookieの送信も受信もされないということになります。

一方、sessionStorageとlocalStorageについては、FirefoxのTCPのような挙動になります。すなわち、サイト毎に分離された形になります。この挙動はWebKitのドキュメントに記載されています。

Partitioned Third-Party Storage
Third-party LocalStorage and IndexedDB are partitioned per first-party website and also made ephemeral.
試訳: サードパーティのlocalStorageとindexedDBはファーストパーティのウェブサイト毎に分離され、またエフェメラル(一時的)なものになります。

すなわち、localStorage等については、iframe等に埋め込まれていた場合、ファーストパーティのウェブサイト毎に別の名前空間になります。
しかし、実験の結果はsessionStorageも上記の分離がなされていました。Safari 16.0まではsessionStorageは分離されておらず、Safari 16.1以降においてsessionStorageもlocalStorage同様のサイト毎の分離がされているようです。私はこの件についてのドキュメントを発見できていませんので、ドキュメントをご存知の方はぜひ教えてください。また、エフェメラルいうのは、ブラウザを終了すると削除されるという意味です。通常localStorageはブラウザを終了しても保持されますが、iframe等のサードパーティで保存されたlocalStorageはブラウザの終了と共に削除されます。一方、FirefoxのlocalStorageはサイト毎に分離されていますが、ブラウザを終了しても、localStorageの値は保持されます。


防御機能を無効化するとどうなるか

ここまで、ブラウザの提供する保護機能により、クリックジャッキング攻撃から防御される仕組みをご紹介しました。しかし、これらの機能は利用者が無効にすることができます。以下、利用者が保護機能を無効にした場合の影響を調べるため、まずはブラウザ毎にセキュリティ機能を無効化する方法を説明します。以下は、セキュリティを低下させる設定なので、検証以外では使用しないことをお勧めします。また試用した後は忘れずに戻しておいてください。

Google Chrome、Edgeの場合

Google Chrome等のChromium系ブラウザにて、デフォルトSameSite=Laxを無効化するには、Windowsの場合レジストリのLegacySameSiteCookieBehaviorEnabledForDomainListにて、無効化するドメインのリストを指定します。参考記事によると、この設定は暫定的なもので将来変更される見込みです。設定例を下図に示します。この設定では、すべてのドメインにてデフォルトSameSite=Laxを無効化しています。危険な設定なので、検証用途以外には使わないでください。


同じ方法でEdgeでも設定可能です。

Firefoxの場合

FirefoxのTCPを無効化するためには、設定|プライバシーとセキュリティから、強化型トラッキング防止機能から、カスタムを選択して、Cookieのチェックを外すか、その右のセレクトボックスで「クロスサイトトラッキングCookie(一番上)」を選択します。


Safari

SafariのITPを無効化するには、Safariの設定からプライバシーを選び、「サイト超えトラッキングを防ぐ」のチェックを外します。


結果

上記の設定変更をした結果を下表に示します。赤字で(*)付きで示した項は設定変更により条件が変わっていることを示します。


考察

前述の設定変更により、以下の状態となりました。

  • ブラウザ側の変更により、ほぼ全ての条件でクリックジャッキングの影響を受けるようになる
  • FirefoxのTCP、およびSafariのITPはプライバシー強化のための機能だが、セキュリティの効果もある
  • SameSite=Lax設定はクリックジャッキング対策としても効果が高い

各ブラウザの設定変更の中で、もっとも現実にありそうなものがSafariのITPの無効化です。「サイト超えトラッキングを防ぐ」でGoogle検索するとトップに表示されるのが、以下のYahoo! JAPANの記事です。

iOS 11以降では、「サイト越えトラッキングを防ぐ」がオン(有効)になっている場合があります。
「サイト越えトラッキングを防ぐ」がオンになっている場合、Cookie(クッキー)がSafari上に残らなくなります。
Yahoo! JAPANでは、複数のサービスでCookieを使用しているため、「サイト越えトラッキングを防ぐ」をオンにしていると、サービス内の機能が限定されるなど、一部のサービスを利用できません。
以下の手順を参考に、「サイト越えトラッキングを防ぐ」機能をオフにしてからYahoo! JAPANのサービスをご利用ください。
iPhone向けSafariで「サイト越えトラッキングを防ぐ」機能をオフにするより引用

しかし、当該の設定変更を行うと、Yahoo!以外のサイトでもセキュリティを弱くする結果になります。このページには以下のような記載もありますが、

注意
「サイト越えトラッキングを防ぐ」機能の設定変更は、お客様ご自身の責任において変更してください。

「お客様ご自身の責任において変更」と書いてありますが、変更による影響は何も説明されていないため、この書き方はいかがなものかという感想を持ちました。


まとめ

  • SameSite属性のないCookieによるセッション管理という伝統的なサイトはモダンなブラウザのデフォルト設定ではクリックジャッキング攻撃の影響はない
  • localStorageにトークン類を保存する実装の場合、Chromium系のブラウザ(Chrome、Edge、Opera)ではクリックジャッキング攻撃の影響がある
  • ブラウザのトラッキング機能を解除するとクリックジャッキング攻撃の影響を受けやすくなる
  • アプリケーション提供者は、ブラウザの設定によらずクリックジャッキングを防御するために、CSPやX-Frame-Optionsによりクリックジャッキング対策を実施すること
  • サイト運営者は、ブラウザの設定変更を促さないこと
  • サイト利用者は、ブラウザの設定を安易に変更しないこと

2023年3月27日月曜日

[書評] ハッキングAPI ―Web APIを攻撃から守るためのテスト技法

サマリ

ハッキングAPI―Web APIを攻撃から守るためのテスト技法(2023年3月27日発売)を読んだ。本書は、Web APIに対するセキュリティテストの全体像と具体的なテスト方法を記載している。ペンテスターは、APIの検出、APIエンドポイントの分析、攻撃(テスト)を行う必要があり、そのために必要な情報がすべて記載されている。また、実習のためのツールと「やられサイト」を複数紹介し、具体的なトレーニング方法を解説している。単にツールやサイトの使い方の説明にとどまらず、本格的なペネトレーションテストの考え方を説明している。
本書の想定読者はAPIのペネトレーションテストを実施するペンテスター及びペンテスターを目指す人であるが、API開発者やウェブアプリケーション脆弱性診断員にとっても有益な内容を多く含む。

重要事項説明

  • 本書の監修者の一人(洲崎俊氏)と評者は知人関係にある
  • 評者が読んだ書籍はご恵贈いただいたものである
  • この記事のリンクにはアフィリエイトが含まれる

APIセキュリティテストとは何か

まずは、本書の主題である「APIセキュリティテスト」を本書でどのように定義しているかを紹介しよう。以下は、本書p3からの引用である。

APIセキュリティテストは、一般的なペネトレーションテストともWebアプリケーション診断とも異なります。APIが持つ攻撃対象領域(Attack Surface)の幅広さと複雑さのため、多くのペンテスターはAPIセキュリティテストを独自サービスとして位置づけています。

通常のWebアプリケーション脆弱性診断でもAPIのテストは当然含まれるが、APIはウェブアプリケーションからだけ利用されるものではなく、IoT機器などからも呼び出される。この場合、IoTシステムとしてセキュリティテストあるいはAPI単体でのセキュリティテストが行われる。本書で説明されるAPIセキュリティテストは、脆弱性診断というよりはペネトレーションテストである。

APIのペネトレーションテストを業務で経験できるエンジニアは限られていると思うが、例えばバグバウンティプログラムに参加して、公開APIをテストするような機会は、意欲と技量さえあれば誰にでも与えらるし、本書はバグバウンティプログラムに参加するバグハンター向けの注意や心構えについても度々言及している。

本書の構成

ここで、本書の構成について紹介しよう。本書は4つの部、16の章で構成される。ここからも分かるように、本書は非常に広範囲のトピックについて扱っている。

第1部 API セキュリティの原理

「第1部 API セキュリティの原理」では、後述の章立てからもわかるように。Web APIの基礎知識と、0章としてAPIテストのスコープ(範囲)、顧客からテスト許可を取得することの必要性などを説明している。2章 Web APIの解剖学では、RESTful APIに加えてGraphQLについても簡単な説明をしている。JSON/XML/YAML等のデータ形式、APIの認証方式(BASIC認証、APIキー、JWT、HMAC、OAuth2.0…)について説明する。REST APIおよびGraphQLを前提とすることから、Cookieによるセッション管理は本書では取り扱われておらず、そのためかCSRF脆弱性やCookieのSameSite属性に関する説明は割愛されている。

  • 0章 セキュリティテストへの準備
  • 1章 Webアプリケーションの仕組み
  • 2章 Web APIの解剖学
  • 3章 一般的なAPI脆弱性

3章の「一般的なAPI脆弱性」としては以下が紹介されている。概ねOWASP API Security Top 10 2019と重なっているが、3.1 情報漏えいと3.11 ビジネスロジックの欠陥は独自に追加したものである。

  • 3.1 情報漏えい
  • 3.2 オブジェクトレベルの認可不備 (BOLA)
  • 3.3 ユーザ認証の不備
  • 3.4 過剰なデータ露出
  • 3.5 リソース不足とレート制限
  • 3.6 機能レベルの認可不備 (BFLA)
  • 3.7 マスアサインメント
  • 3.8 セキュリティ設定ミス
  • 3.9 インジェクション
  • 3.10 不適切な資産管理
  • 3.11 ビジネスロジックの欠陥

第2部 APIテストラボの構築

  • 4章 API ハッキングラボの構築
  • 5章 脆弱なAPIラボ環境の準備

第2部はAPIテストのための実習環境として、診断ツールと脆弱なAPI環境を準備する。診断ツールとしては、Burp Suite、Postman、Wfuzzが大活躍することになるが、これら以外にOWASP Amass、KiterunnerなどAPIを発見するためのツールも紹介されており興味深い。脆弱なAPI環境としてはcrAPIなど数種を紹介している。また、訳注の形で拙作のBad Todoも紹介頂いていた(APIではなく古典的なWebアプリケーションとして)。

第3部 APIへの攻撃

第3部は、いよいよAPIの実際のテスト(攻撃)を説明する。第3部の章立ては以下の通りである。

  • 6章 APIの検出
  • 7章 エンドポイント分析
  • 8章 認証への攻撃
  • 9章 ファジング
  • 10章 認可への攻撃
  • 11章 マスアサインメント
  • 12章 インジェクション攻撃

まず6章と7章でAPIの検出と分析を行うが、この2章は十分な紙面を使って詳しく説明されている。このあたりが、よくある「ハッカー入門」的な書籍とは異なり、本書が実務的な内容になっていることの表れのように思える。
6章 APIの検出では、OSINT的な手法を活用してAPIを検出する。通常の脆弱性診断ではAPIエンドポイントの情報は開示されるので、このステップは省略されるが、本書でいう「ブラックボックス型テスト」では、APIの検出から始まるのでこのステップが必要になる。

7章のエンドポイント分析は、APIの正常系の仕様を把握するステップであり、ウェブアプリケーション脆弱性診断のサイト巡回(クローリング)に相当する。APIの仕様はドキュメント化されている場合も多いが、そうでない場合、アプリケーション経由のAPI通信をキャプチャすることになる。このステップは本書ではリバースエンジニアリングと表現されている。通信のキャプチャはBurp Suite等の診断プロキシを用いることもできるが、本書では主にPostmanを使用する。Postmanのプロキシ機能(評者は本書を読むまで知らなかった)を用いて、API仕様を明確にする。7章の後半は情報漏洩や過剰なデータ露出等、ファジングを伴わない脆弱性検査を行う。

8章から12章はさまざまな攻撃によるセキュリティテストである。8章の前半はパスワード認証に対する辞書攻撃やパスワードスプレイなど古典的な攻撃だが、Hydraのようなパスワード解析専用ツールではなく、Burp Suite IntruderやWfuzz等のファジング用のツールを使っている。パスワードスプレイの場合、ユーザIDのリストが必要になるが、6章で解説した偵察や7章の過剰なデータ露出脆弱性を利用できるとする。8章の後半は、トークンやJWTに対する攻撃で、ブルートフォースを含む攻撃手法を解説している。

9章で説明されるファジングとは異常なデータをAPIに送信して意図しない結果を引き起こすことである。ファジングにはワイドファジング(広く浅く)とディープファジング(狭く深く)があり、前者にはPostmanのCollection Runnerを用い、後者にはBurp Suite IntruderやWfuzzを用いている。評者はPostmanを使ってはいたが、もっぱらAPIの機能的なテストの目的であり、ファジングに用いる発想がなかったので勉強になった。

10章は認可への攻撃である。認可脆弱性に関しては特に目新しいものではないが、テストの観点とツールの効果的な使い方は興味深い。ここでも、Postmanを効果的に使用している。

11章はマスアサインメントに対する攻撃である。マスアサインメント脆弱性とは、主に更新系のAPIで、「変更できてはいけない項目を変更できる」問題であり、過去のGithubの事例が有名である。例えば、利用者が自身のメールアドレスやパスワードを変更できるのは問題ないが、テーブル上のadmin列をtrueに勝手に変更できたら大問題である。API呼び出しにadmin=trueを追加するだけで意図しないadmin列の更新ができる場合がマスアサインメント脆弱性である。Ruby on Rails 4以降ではStrong Parametersと言う機能によりマスアサインメントに対策している。マスアサインメントのテスト自体は簡単なのだが、問題は「変更できてはいけないパラメータ(先の例ではadmin)」をどう発見するかである。本章では、マスアサインメント可能なパラメータの探索についていくつかの方法を説明している。

12章はインジェクションということで、クロスサイトスクリプティング(XSS)やSQLインジェクションなどが含まれる。有名な脆弱性であるからか、この章の説明は簡潔なものである。12.4.1項で説明されるSQLインジェクション攻撃文字列は、あまり凝ったものではないし、本番環境で試すには危険なものが含まれていて評者はぎょっとした(p304)。だが、直後に訳者による適切なコラム「SQLインジェクションのテストを実施する際の注意と補足(pp305-306)」があり、評者は安心した。もっとも、コラム内の文字列「’||’」や「’+’」もMySQLの場合は危険なので、SQLインジェクション検査は厳重な注意が必要である(参考:とある診断員とSQLインジェクション)。

第4部 実世界におけるAPI攻撃

第4部は、「実世界におけるAPI攻撃」というテーマで、13章はバイパス技術の応用とレート制限テストとして、バリデーションやWAF、APIの利用制限を回避する技術といういかにもハッカー的なテーマ、14章は皆さん大好きGraphQLへの応用、15章では、APIの脆弱性が情報漏洩やバグバウンティでどのように発見されたかを紹介している。

  • 13章 バイパス技術の応用とレート制限テスト
  • 14章 GraphQLへの攻撃
  • 15章 データ侵害とバグバウンティ

本書のすごいところ

本書の眼目は、APIセキュリティテストの方法論に徹底しているところである。それは、APIを検出するところから始まる。種々の検出手法は、APIそのものを探すだけではなく、マスアサインメント可能なパラメータを探す場合にも応用できるもので、この種の解説は非常に貴重なものだ。
また、テストに使うツールの説明も詳しい。筆者は主にBurp SuiteやPostmanなどの汎用的なツールを使い、Burp SuiteのIntruderやPostmanのCollection Runnerによりファジングだけでなく、パスワードに対する辞書攻撃やマスアサインメントのパラメータ探索にも用いる。その他にも多くのツールが紹介されているが、評者には、汎用ツールの使いこなしこそ勉強すべきだと思えた。
さらには、テストに対する心構えや、方針の立て方など、現役のペンテスターならではの知見が学べるところも、本書ならではの価値といえる。

本書で扱ってない内容

本書で扱っていない項目についても紹介しよう。
まず、現在APIの主流であるRESTfulAPIはステートレスだからCookieによるセッション管理は行わないという主張から、Cookie関連の記載は一切ない。これに関連して、以下の項目もない。

  • Cookieに関する説明(例えばSameSite属性を含め、Cookieの言及がない)
  • セッション管理(トークン類の保存場所はlocalStorageかCookieか等)
  • APIのCSRF(Content-Type、CORSとの関連を含むが、そもそもCSRFの言及がない)

また、Web APIの基礎としてJSONなどの説明はあるが、同一オリジンポリシーやCORSの説明はない。
XSSの話題は少し出ているが、Content-Typeの話題はない。例えば、以下のケースは、レスポンスボディの見かけ上はXSSだが、Content-Type: application/jsonなのでJavaScriptは実行されない。この種の話題は、他の本(例えば拙著)で学ぶ必要がある。

HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 43

{"message": "<img src=x onerror=alert(1)>"}

その他、触れられてないテーマの例として下記がある。

  • JSONP(RESTfulAPIだから関係ない)
  • CSP(API側だから無関係というのは分かる)
  • X-Content-Type-OptionsやHSTSなどのレスポンスヘッダ(侵入とは直接関係がないからか?)
  • 脆弱性の対策方法

注意点

筆者は根っからのペンテスター気質という感じで、例えば、以下のような記載がある(p301)。

プロバイダのAPIがコンテンツを追加したり、そのWebアプリケーションに変更を加える場合、脆弱性が存在しないか探すべきかもしれません。

これに対しては、下記の訳注がついている。

一般に、許可なくサードパーティAPIをテストすることは許されていないケースが多いため、注意が必要です。

また、以下のような記載もある(p115)。

筆者は、Webアプリケーションの存在を発見すると、すぐにNiktoでスキャンを行います。

おそらく文脈的には「セキュリティテストの過程でWebアプリケーションを発見すると…」ということであろうが、Niktoも脆弱性診断ツールの一つではあるので、許可なくNiktoスキャンを行うことは問題がある。

本書の眼目は訳者の知見にある

本書は、本格的なAPIセキュリティテストの書籍の和訳というだけで価値が高いものであるが、次の点において、価値が倍加していると考える。

  • 原書の出版後に利用サイトやツールのバージョンアップ、サイトの閉鎖等に伴う利用法の変更や代替手段の説明があること
  • 豊富な訳注と訳者コラムにより、原書の説明不足や、日本の読者になじみのない一般知識(例えばAcmeの意味)が補足されていること
  • 訳注での参考情報の記載がとても豊富であり、追加の勉強のために役立つこと

したがって、読者が英語に堪能であったとしても、それでもこの和訳を選択する価値は十分にある。また、参考リンクが豊富であることから、買うなら電子版(PDF)が圧倒的にお勧めである。評者はレビューを紙版で行ったが、電子版も購入した。
翻訳はこなれていて、問題となるような箇所はなかった。

本書の使い方

本書のお勧めの活用法は以下のようなものであろう。

  • 4章「APIハッキングラボの構築」と5章「脆弱なAPIラボ環境の準備」に従い実習環境を準備する
  • 各章を読む
  • 章末に示された実習を行う
  • 本書を読むだけでは分からない箇所を訳注の参考文献に従って勉強する

かなり時間がかかるはずだが、それだけの価値は必ずある。

まとめ

  • 本書はAPIセキュリティテストに関する実践的なガイドである
  • ツールの紹介が多いが、読者はツールを能動的に活用する必要があり、そのための情報が本書にはある
  • 訳注および訳者コラムは価値が非常に高く、それだけで訳書を選択する理由になる
  • 買うなら絶対に電子版(PDF)をお勧めする

2022年12月20日火曜日

Ruby cgi gemのHTTPヘッダインジェクション脆弱性CVE-2021-33621の概要と発見の経緯

この記事はRuby Advent Calendar 2022の第20日の記事です。前日の記事は@ydahさんによる「RuboCopのバージョンを最新に保つ技術」でした。

2022年11月22日に、Ruby cgi gemのHTTPヘッダインジェクション脆弱性CVE-2021-33621が発表がされました。

私はHackerOneを通じてこの脆弱性を報告しました。この記事では、当該脆弱性の概要と発見の経緯などについて報告します。

概要

この脆弱性はRubyでCGIプログラムを記述際に用いられるcgi gem のheaderメソッドに内在するものです。PoCを以下に示します。このスクリプトは、クエリ文字列 num を受け取り、http://example.jp/?num=<指定された数値>にリダイレクトするものです。

#!/usr/bin/ruby
require 'cgi'

cgi = CGI.new
num = cgi.params['num'][0]
print cgi.header({'status' => '302 Found', 'Location' => "http://example.jp/?num=#{num}"})

ここで、numとして下記を指定した場合、

num=3%0d%0aSet-Cookie:+SESSID%3d1234567890

%0d%0aは改行なので、以下のレスポンスヘッダが出力されます。

Status: 302 Found
Location: http://example.jp/?num=3
Set-Cookie: SESSID=1234567890

すなわち、リダイレクトする「ついで」に任意のクッキーをセットすることができます。

クッキのセット以外に、任意URLへのリダイレクトもできます。

num=3%0d%0aLocation:+http://trap.example.com/

この結果のレスポンスヘッダは下記となりますが、

Status: 302 Found
Location: http://example.jp/?num=3
Location: http://trap.example.com/

Apacheの場合複数のLocationヘッダがあった場合、最後のLocationヘッダのみがブラウザに返されるので、結果として、trap.example.comにリダイレクトされます。これにより、偽ログイン画面に遷移してパスワードを盗むなどができます。

また、以下のようにHTTPレスポンスボディを出力することもできます。

num=3%0d%0a%0d%0a<script>alert(1)</script>

レスポンスは下記となります。空行の後にJavaScriptコードが出力されていることが分かります。

Status: 302 Found
Location: http://example.jp/?num=3

<script>alert(1)</script>

ただ、このままだとリダイレクトが優先されるのでレスポンスボディは表示されません。リダイレクトを避けるテクニックとして、ヘッダインジェクションによりStatus 500等を出力する方法があります。このテクニックははるぷさんに教えていただきました。

num=3%0d%0aStatus:+500%0d%0a%0d%0a<script>alert(2)</script>

このケースでの出力は下記となります。

Status: 302 Found
Location: http://example.jp/?num=3
Status: 500

<script>alert(1)</script>

Statusヘッダが2つありますが、前述のようにApacheは最後のStatusヘッダのみをブラウザに返すため、リダイレクトは無効となり、JavaScriptが実行されます。これはXSSと同等の脅威となります。

脆弱性発見の経緯

なぜ今どきRubyのcgi gemを調べたか、それにはちょっとした理由があります。 元々は、2020年1月にRuby on RailsのHTTPヘッダインジェクションに脆弱性を見つけて、HackerOneにて報告したところ、これはRailsの脆弱性ではなくて、ウェブサーバーのPumaの脆弱性だということになり、Puma側で修正された(CVE-2020-5247)ことがきっかけです。

この脆弱性について、適当な場で紹介したいと思っていたところ、2021年6月18日に銀座Rails#34@リンクアンドモチベーションがオンライン開催されることがわかりましたので、CfPに応募して採択されました。

この内容は私のYouTubeチャンネルにて公開しています。動画データを主催者様に提供いただきました。ありがとうございます。

この発表(動画)では、冒頭のHTTPヘッダインジェクション入門をPHP(の古いバージョン)にて行っていますが、元々はRubyのCGIで説明するアイデアがありました。そのサンプルプログラムを作成する過程でRubyのcgi gemに脆弱性があることに気づきました。ゼロデイの脆弱性を説明に使うわけにもいかず、本番ではPHPの旧版の脆弱性を用いた形になりました。

さて、cgi gemに脆弱性があることは疑いのないものでしたが、「RubyでCGIを書いているサイトはどれくらいあるのだろう」という疑いもあり、gem側で修正しなくても、注意喚起してアプリケーション側での改修でもよいのではないかと思いました。とはいえ、当方が勝手に「ゼロデイ脆弱性」を公開することもよくありません。

このためRubyコミッタ柴田さんに相談したところ、チームで検討するのでHackerOne経由で申告してほしい(日本語でOK)旨の連絡をいただきましたので、HackerOneに投稿した内容が冒頭で紹介したものです。こちらは脆弱性と認められ、改修されることになりました。 また、CGI::Cookieにもセキュリティ上好ましくない実装を見つけましたので、追加の報告として提出しました。

内容は、Cookieのname、path属性、domain属性設定時に外部由来の値を使うとインジェクションが可能というものでした。こちらも脆弱性と認められ、同時に修正されています。詳しくはHackerOneの報告を御覧ください。

影響を受けるアプリケーション

当脆弱性の影響を受けるアプリケーションは下記のとおりです。

  • cgi.headerメソッドに外部由来の値をセットしている場合
  • CGI::CookieによりCookieのname、path属性、domain属性設定時に外部由来の値を使っている場合

※ Cookieのpath属性およびdomain属性へのセミコロンを用いたインジェクションは、PHP-7.2以前にも存在していました(バグ#69948)。

影響

当脆弱性の影響は概要で示したとおりですが、まとめると以下のようになります。

  • 任意のレスポンスヘッダの追加・改変
    • (その結果)クッキーの追加、改変
    • (同上)任意URLのリダイレクト
  • レスポンスボディの追加・改変
    • (その結果)任意JavaScriptの実行(XSSと同等の脅威)
  • Cookieのname、path、domainを通じた属性等の改変

対策

cgi gemを最新版(0.3.5, 0.2.2, 0.1.0.2)にアップデートすることで対策されます。

Ruby本体のバージョンアップ

Rubyのバージョン 3.1.3 / 3.0.5 / 2.7.7 にて最新のcgi gemを含む形で対応されています。 現時点では、主要Linuxディストリビューションはアップデートを提供していないようです。

cgi gemのアップデート

前述のように、Linuxディストリビューション経由でのyumやaptによるアップデートでは本問題の対応はできませんが、gemコマンドによるアップデートは可能です。

$ sudo gem update cgi

ただし、Rubyのバージョンが2.7以降である必要があります(参考)。Ruby 2.7未満を使用している場合は、Ruby自体をバージョンアップする(推奨)か、以下のアプリケーション側の対策を実施してください。

アプリケーションでの対応

アプリケーション側で対策するには、以下を実施してください。

  • cgi.headerメソッドに渡すパラメータを検証して改行(\rや\n)が混入しないようにする
  • CGI::Cookieに渡すname属性やdomain属性を検証する

まとめ

Ruby cgi gemのHTTPヘッダインジェクション脆弱性CVE-2021-33621について、脆弱性の内容と経緯について説明しました。今時RubyでCGIプログラムを記述するケースもほとんどないとは思いますが、HTTPヘッダインジェクションという今となってはレアな脆弱性が発見され、きちんと修正されたことをご報告したいと思い本稿を書きました。

脆弱性そのものは拙著「安全なWebアプリケーションの作り方」に記載されている範囲のものですので、バグハンターを目指す皆さんは、「著名ソフトウェアだけどあまり使われていない機能」に着目すると、比較的容易に脆弱性が見つけられ、インターネットの安全にも貢献できるのではないでしょうか。

また、今回の脆弱性対応くださった柴田(@hsbt)さん、@mameさん、@nobuさんに感謝申し上げます。きちんと対応いただき、発見者としてうれしく思います。ありがとうございました。

2022年9月9日金曜日

PHPカンファレンス2022にてSPAセキュリティ超入門の話をします

今年もPHPカンファレンスにてトークさせていただくことになりまして、以下のようなお話をいたします。

日時:9月25日(日) 14:40〜15:40
場所:大田区産業プラザPiO  および YouTube
費用:無料
講演タイトル:SPAセキュリティ超入門
申し込み: connpass
アジェンダ:

SPA(Single Page Application)の普及が一層進んでおり、従来型のMPAを知らないウェブ開発者も生まれつつあるようです。SPA対応のフレームワークでは基本的な脆弱性については対策機能が用意されていますが、それにも関わらず、脆弱性診断等で基本的な脆弱性が指摘されるケースはむしろ増えつつあります。
本セッションでは、LaravelとReactで開発したアプリケーションをモデルとして、SQLインジェクション、クロスサイトスクリプティング、認可制御不備等の脆弱性の実例を紹介しながら、現実的な対策について紹介します。LaravelやReact以外のフレームワーク利用者にも役立つ説明を心がけます。


実は昨年も「SPAセキュリティ入門」というテーマでトークをしておりまして、今年はもう少し易しめということで「超入門」としました。

昨年の講演のスライドおよび動画は以下から参照ください。

昨年は主にSPAにまつわるセッション管理に焦点をあてて、JWTによるセッション管理は是か非か、JWT等トークン類の保存場所はCookieかlocalStorageかという基本的な考え方(しばしば論争になる)のお話をしました。

今年はもう少し現実的なテーマとして、アジェンダにもあるように、LaravelによるサーバーサイドAPI、Reactによるフロントエンドという構成のSPAを題材として、以下のような「よくある」脆弱性がいかにして混入するか、およびその対策について説明します。

  • 認可制御不備
  • SQLインジェクション
  • クロスサイトスクリプティング(XSS)

これら脆弱性は、LaravelおよびReactを普通に使っていれば混入しないはずのものです。しかし脆弱性診断等ではこれら脆弱性はしばしば目にします。普通に作れば混入しないはずの脆弱性がなぜ混入するのか。私はその原因を追い続けていましたが、どうも従来型のアプリケーション(マルチページアプリケーション=MPA)では常識だった知識が、SPAでは伝承されていないのではないかと考えるに至りました。この要因ファクターXについて紹介するとともに、なぜ今基本的な脆弱性が多いのかを説明しようと思います。

なお、前述のようにファクターXは従来の常識ですので、「なぁんだ、そんなことか」となること請け負いですが、「そんなこと」レベルのことが問題になっているように考えています。

それでは、よろしくお願いいたします。




無事終了しましたのでスライドと動画を添付いたします。


2022年7月4日月曜日

メタップスペイメント不正アクセス事件の第三者報告書から攻撃の模様を読み解く

株式会社メタップスペイメントの運営する決済代行システムから約288万件のクレジットカード情報が漏洩した不正アクセス事件について、第三者委員会の報告書および経済産業省の行政処分(改善命令)があいついで公開されました。

第三者委員会調査報告書(公表版)
クレジットカード番号等取扱業者に対する行政処分を行いました (METI/経済産業省)

本稿では、主に第三者委員会の調査報告書(以下「報告書」と表記)をベースとして、この事件の攻撃の様子を説明します。

システムの概要

報告書にはシステム構成図やネットワーク構成図は記載されていないため、報告書の内容から推測によりシステムの構成を以下のように仮定しました。

図中のサーバー名は報告書の記載に従っています。以下、概要を説明します。

サーバ名概要
A社アプリ一般社団法人A 会員向け申込みフォーム
経産省改善命令では、「同社とコンビニ決済に係る契約を締結していた加盟店にサービスを提供するために開発、運用していたアプリケーション(以下「加盟店向けアプリ」という。)」が該当すると思われる
K管理画面社内用決済管理画面。A社アプリのサーバーと同居していた(*1)
決済サーバ決済機能を提供するサーバー。攻撃対象ではなかった可能性があるが機能としては存在するので記載した
データベース各システム共用のデータベース
報告書内にデータベースの種類は明記されていないが、用語集にMySQLの説明があるので、MySQLを使用していると推測
復号化サーバ報告書に登場する。暗号化されたクレジットカード情報を復号を提供するAPIと思われるが、不正アクセスに関する記載はない(*2)

注 *1 : 報告書中には、A社アプリとK管理画面が同居していた旨は明記されていませんが、時系列表には、事故後の対応として「管理画面サーバから確認用サイト、A社アプリの分離(2022年1月7日)」を実施した旨が記載されているので、元々これらは同一サーバに同居していたと考えられます。

注 *2 : 報告書には「Web2系に暗号化されたカード情報に係る復号化サーバが配置されていた。Web2系には、決済システムも配置されており、そこで暗号化されたカード情報も管理されていた。」と記載されています。報告書中では「サーバー」、「サイト」、「画面」、「機能」の使い分けが明確でないため断言は難しいのですが、「Web2系」がサーバーを意味すると解釈すると、決済サーバと復号化サーバは同一マシンに同居していた可能性があります。


時系列の流れ

第三者委員会の報告書に加えて、メタップス社の2月28日づけリリースも合わせて時系列の流れをまとめました。

日時出来事
2021年8月2日メタップスペイメントの決済データセンターに対する不正アクセスが開始。K管理画面へのXSS攻撃か?
2021年8月31日K管理画面に対する不正ログイン始まる
2021年10月14日A社アプリにSQLインジェクション攻撃始まる
2021年10月15日A社アプリに、SQLインジェクションで得たパスワードによる不正ログイン
2021年10月19日
~10月27日
A社アプリのSQLインジェクションにより2万5千件のカードデータ窃取
2021年10月25日
~12月14日
K管理画面不正ログインによりカード番号全桁の検索が実行される(2万件程度)
2021年10月25日メタップスペイメントがA社アプリのメンテナンス中にSQLインジェクション攻撃を発見
2021年10月27日メタップスペイメントがA社アプリのSQLインジェクション対策を完了
2021年11月11日A社アプリのアップロード機能よりバックドアが設置され、攻撃開始。最終的にカード情報データベースの全データが窃取されたとみられる(460,395件 + 2,415,750件)
2021年12月14日アクワイアラ E 社からイベントペイで不正利用懸念の連絡
2021年12月16日イベントペイでクレジットカード決済を停止
2022年1月6日K管理画面の管理用サイトにBasic認証を追加
2022年1月7日K管理画面サーバから確認用サイト、A社アプリの分離、A社用DBとペイメントDBの分離
2022年1月8日A社アプリのサーバの分離を実施
2022年1月24日メタップスペイメントがバックドアプログラムの存在を確認、削除
2022年1月24日メタップスペイメントが不正アクセス被害を公表
2022年1月28日管理用サイトのクロスサイト・スクリプティングに対応、Basic認証の追加
2022年2月28日メタップスペイメントが不正アクセスによる情報流出を公表

攻撃の流れの詳細については以下で説明します。


1. K管理画面 のアカウント情報の窃取、不正ログイン

報告書によると、以下の順で攻撃が行われました。

  1. K管理画面のXSS脆弱性を悪用し、当管理画面のID・パスワードを窃取(報告書には時期の記載がないが、2022年2月28日づけメタップス社のリリース記載の2021年8月2日の不正アクセスが該当するか?)
  2. X氏アカウントによる不正ログイン(2021年8月31日~)
  3. メタップス社内にてX氏アカウントのパスワードを変更(2021年9月末から2021年10月初旬までの間)これ以降X氏アカウントの不正ログインなし
  4. Y氏アカウントにて不正ログイン(2021年10月6日以降)

攻撃の模様を下図に示します。

報告書によると、XSS攻撃を許してしまった理由は下記のとおりです。

  • 自社で実施した脆弱性診断ではXSS脆弱性が検出されていたが、高危険度の脆弱性があるとPCI DSSの審査に通らないため、報告書を改ざんして脆弱性自体をなかったことにした
  • WAFが導入されていなかった(PCI DSSではコードレビューまたはWAFのいずれかの導入を求められているので、WAF導入は必須ではない)

XSS攻撃の詳細

K管理画面は社員向けのシステムであるので、画面の詳細は外部の攻撃者にはわからないはずです。報告書ではXSS攻撃の詳細は発表されていませんが、管理画面を狙うXSS攻撃自体は最近よく見かけるもので、おそらく問い合わせ画面のように外部から入力できるフォームからJavaScriptによる攻撃コードを注入したのではないかと予想されます。その種の攻撃の例としては、Water Pamolaが知られています。Water Pamola型のXSS攻撃の例については以下の動画を参照ください。


なぜパスワードが窃取できたか?

次にXSS攻撃でK管理画面のパスワードが窃取できた理由を考察します。こちら報告書には書かれていないので、「ありそうな経路」を列挙するにとどめます。

  1. 管理機能としてパスワードを平文で表示する箇所があった
  2. ログイン状態で自分自身のパスワードを変更した(パスワード再入力なし)
  3. 他の管理者のパスワードを変更する機能を悪用した(パスワード再入力なし)
  4. ログイン中のユーザあるいは他の管理者のパスワードをリセットする機能を悪用した
  5. 偽のタイムアウトを引き起こして「IDとパスワードを入力してください」という画面を表示した(12:56追記)

1は通常はあり得ないのですが、この事件では「あり得ないことが幾つも起こっている」のでないと断言することもできません。ありそうな経路は2または3ですが、そうすると、本来の管理者がログインできなくなります。その段階で気づきそうなものですが、報告書には当初不正ログインに使われていたX氏のパスワードが変更されたとあるものの変更した理由は明記されていない(ちなみに時期も明確ではない)ため、「X氏は攻撃者にパスワードを変更されたことに気づかないままパスワードをリセットした」可能性も考えられると思います。

社内用決済管理画面はインターネットからアクセスできた

K管理画面に不正ログインされたということは、社内用決済管理画面にインターネットからアクセスできたことを意味します。これも奇異な状態ですが、報告書の時系列表には、2022年1月6日に「管理用サイトにBasic認証を追加」とあるので、それまではインターネットから自由に当該システムにアクセスできたものと推測されます。


2. SQLインジェクション攻撃によるカード情報とパスワードの窃取

報告書には以下のように記載されています。以下引用です。

攻撃者は、2021年10月14日から2021年10月27日に渡り、A社アプリに対するSQLインジェクション攻撃により、暗号化されたカード番号、マスクされたカード番号及びA社管理画面の管理者アカウント情報をそれぞれ不正取得した。

この攻撃の様子を下図に示します。




A社アプリは元々他のクラウドに設置されていたものですが、2018年に東京データセンターに移設され、その際、データベースのテーブルはカード情報データベースと同じスキーマに設置されていたとのことです(データベーススキーマの未分離)。このため、A社アプリに対するSQLインジェクション攻撃により、カード情報まで窃取されたことになります。

SQLインジェクションによるパスワード窃取と不正ログイン

また、A社管理画面の管理者アカウントの窃取と不正ログインについては以下のような時系列となっています。

2021年10月15日 05:09SQLインジェクションによりID・パスワードの窃取
2021年10月15日 05:12不正ログイン

IDとパスワードの窃取から、わずか3分後に不正ログインされていることから、パスワードは平文で保存されていた可能性が高いと推測されます。仮にハッシュ値等で保存されていたとしても3分間で平文パスワードを復元されたのでは意味がありません。この不正ログインが次項の「バックドアプログラムの設置」につながります。

SQLインジェクション脆弱性が残置された理由

SQLインジェクション攻撃を許してしまった理由は、前述のWAFの未設置の他、A社管理画面の開発経緯が原因だったようです。以下報告書からの引用です。

上記ソースコード・レビューに関する社内規程が作成されたのは、2012年10月であるところ、A社アプリが委託先であるB社によって開発されたのは、2007年頃であるため、当時は、社内的にも同アプリに対してSQLインジェクション攻撃への対策としてソースコード・レビューを実施することは必須とされていなかった。また、MPにおいては、以前より「決済システム以外は脆弱性対策をする必要がない」との認識があったため、同規定の作成時において、当時フロントシステムにあったA社アプリが見直し的にソースコード・レビューの対象となることもなかった。

A社アプリが東京データセンターに移設された後も、同様の認識により、ソースコード・レビューや脆弱性診断の対象にはなっていなかったようです。


3. バックドアプログラムの設置と攻撃

こちらも報告書から引用します。

攻撃者は、2021年10月15日、A社管理画面に一度不正アクセスしているが、更に2021年11月11日、A社管理画面に不正アクセスを行い、A社アプリの管理機能の一つであるファイルアップロード機能を悪用し、バックドアプログラムを設置した。

そして、不正ファイル経由で、データベース内から、暗号化されたカード情報を含む当時格納されていた全ての情報を不正取得したと考えられる。

この様子を下図に示します。




ファイルアップロード機能によるバックドアプログラム(おそらくWebShell)を設置するのは定番の攻撃方法です。報告書には「東京DCがA社アプリと同じJavaで構築されているため」という記述があるのため、A社アプリはJavaで構築されていることがわかります。なので、バックドアプログラムは、JSP記述のWebShellと推測されます。

また、「不正ファイル」という用語はバックドアプログラムとは別のものとして記載されているようです。不正ファイルの中身は判然としませんが、WebShellから起動されたリバースシェルあるいはデータベース(MySQL)アクセス用のツールではないかと思われます。

バックドア設置はSQLインジェクション対策後に行われた

A社アプリのSQLインジェクション脆弱性対策は2021年10月27日に完了していますが、A社アプリのパスワードを悪用してのバックドア設置は2021年11月11日に実行されています。SQLインジェクション対応の一環として、A社アプリのパスワード変更を実施しておけば、バックドア設置はできなかったはずです。

復号鍵の窃取

また、報告書には記載がありませんが、経産省の改善命令には復号鍵について以下の記載があります。

当該クレジットカード決済システム内のデータベースに保存していた暗号化されたクレジットカード番号(マスキングされたクレジットカード番号を含む。)、有効期限、セキュリティコード及びこれらを復号化するための復号鍵が窃取され

復号鍵が窃取されたと明記されていますが、復号鍵がデータベースに保存されていたとは考えにくく、また「復号化サーバ」が存在する以上は、復号鍵はそこにあると考えるのが自然です。

報告書には復号鍵の漏洩ルートに関する記載はないようですが、時系列表には以下の記載があります。

2022年1月28日 復号APIのディレクトリトラバーサルに対応。

 このため、復号APIのディレクトリトラバーサル脆弱性が悪用されて復号鍵が窃取された可能性があります。

任意形式のファイルをアップロード可能だった

管理画面にファイルアップロード機能があること自体はよくあることですが、この場合、任意ファイル名で任意の内容のファイルをアップロードできると、簡単にWebShell等を設定されてしまうので通常はファイル名やファイルの中身に制限をつけます。しかし、報告書によると、以下のような記載があり、

アップロード機能の設定の不備 により、想定以外のファイルをアップロード可能だった為、バックドアプログラムを設置されていた。

拡張子.jspのファイル等をアップロードできていたことがわかります。

ファイル改ざん検知の不備

バックドアプログラムの設置は一種の「改ざん」にあたるため、ファイル改ざん検知システムが導入されていれば、バックドア設置を早期に発見できた可能性があります。メタップスペイメント社はPCI DSS 3.2.1完全準拠をうたっていましたし、PCI DSSではファイル改ざん検知システムの導入を要求しています。A社アプリはPCI DSSの対象外だったようですが、このアプリケーションにも改ざん検知システム(ファイル整合性監視ツール)を導入して監視しておけば、早期にバックドアの設置を検知して対応できた可能性があります。また、この記事の冒頭で推測しているようにA社アプリとK管理画面が同一サーバーに同居していたとするならば、PCI DSSの観点からも、ファイル改ざん検知の対象にすべきであったと考えます。

もっとも当社の監視体制については、報告書に以下の記載もあるため、改ざん検知システムを導入していただけでは有効に機能しなかった可能性が高いです。

従業員のヒアリング結果によれば、実際はセキュリティアラートにする検証ができる人材が不足しており、また、必要な範囲でセキュリティアラートを発信するようにするためのシステム面での調整(チューニング)が出来ていないことも相まって、MPの従業員は、セキュリティアラートが発信されても、特段気にして監視していなかったとのことであり、十分な検証がなされていなかったことが認められた。

事故後の対応として、2022年1月29日に「改ざん検知設定を修正」とあるため、改ざん検知システム自体は元々導入されていたようです。


4. 管理画面 への再度の不正アクセス 及び カード番号照会開始

報告書には以下のように書かれさています(2021年10月25日から同年12月14 日)。

上記SQLインジェクション攻撃及びバックドアプログラムにより、既にデータベースからマスクされたカード番号を不正取得しており、K管理画面上で不正取得したマスクされたカード番号を検索照会することによって、平文のフル桁のカード番号を閲覧することができたと考えられる。

また時系列表には以下のように記載されています。

海外IPアドレスによりUserID「Y氏」を利用してカード番号の検索が行われ、不正取得した閲覧用パスワード入力後、平文のフル桁のカード番号の検索結果が表示された。
なお、この間、平文のフル桁のカード番号を確認可能なURLに対し、約2万回不審な連続アクセスが確認された。

この攻撃の様子を下図に示します。

クレジットカード窃取は3経路存在した

ここまで説明した攻撃手法から、クレジットカード情報を攻撃者が入手した経路は以下の3経路があることになります。

  1. A社アプリ経由: SQLインジェクション攻撃によりマスク化カード情報と暗号化カード情報を入手(2万5千件、2021年10月27日まで)
  2. バックドア経由: バックドアにより暗号化カード情報と復号鍵を入手(288万件、2022年1月18日まで)
  3. K管理画面経由: K管理画面のもつクレジットカード番号検索機能の悪用による平文全桁カード情報取得(2万件、2021年12月14日まで)

3のK管理画面経由での平文カード情報取得は2021年12月14日で終わっています。攻撃者がなぜ経路3をこの時期にやめたかという理由を推測すると、この時期に復号鍵が入手できたため、経路3を悪用する理由がなくなったから、というのが私の推測です。

事故対応の過程で、当初メタップスペイメント社は上記1および3の経路のみを把握していたようですが、以下のように、1および3以外の経路があることに気づきます。

MPは、2022年1月21日に受領したK社12件のログの社内検証結果として、判明している原因(K管理画面に対する不正アクセスやSQLインジェクション攻撃)以外でクレジットカード情報が窃取されていると判断した(1月8日までの対策のみでは情報漏えいを防ぎきれていないことを認識した。)。

その後の調査にて、2022年1月24日にバックドアプログラムの発見、削除に至ります。


まとめ

メタップスペイメントのクレジットカード情報漏えい事件の概要を第三者委員会の報告書を元に説明しました。決済代行事業社からクレジットカード情報が大量に漏洩するという衝撃的な事件でありましたが、漏洩に至る経緯も驚くべきもので、第三者委員会報告書はセキュリティ関係者にとって非常に学びの多い資料だと思います。

侵入の発端となった脆弱性は、クロスサイトスクリプティングおよびSQLインジェクションという非常に基本的なものでありますが、仮にそれらの脆弱性があっても、他の保険的な対策や侵入発見後の対処が適切であれば、被害を最小限に留められたはずという点でも学びが多く、機会があれば別の記事で紹介したいと思います。

クロスサイトスクリプティングやSQLインジェクションなどの基本的な脆弱性や、当事件で悪用されたファイルアップロード機能やアカウント管理に関する対策方法については下記の書籍にて説明しています。

2022年5月16日月曜日

DNSリバインディング(DNS Rebinding)対策総まとめ

サマリ

DNSリバインディングが最近注目されている。Google Chromeは最近になってローカルネットワークへのアクセス制限機能を追加しており、その目的の一つがDNSリバインディング対策になっている。Googleが提供するWiFiルータGoogle Nest WiFiはデフォルトでDNSリバインディング対策機能が有効になっている。 DNSリバインディング対策は、攻撃対象アプリケーションで行うべきものであるが、ブラウザ、PROXYサーバー、リゾルバ等でも保護機能が組み込まれている。本稿ではそれら対策機能の状況と対策の考え方について説明する。

DNSリバインディング(DNS Rebinding)とは

DNSリバインディングはDNS問い合わせの時間差を利用した攻撃です。DNSのTTL(キャッシュ有効期間)を極めて短くした上で、1回目と2回目の問い合わせ結果を変えることにより、IPアドレスのチェック等を回避する攻撃です。下図は、DNSリバインディング時のDNS問い合わせの様子です。




DNSリバインディングの主な脅威

DNSリバインディングによる脅威は、DNS問い合わせがあるところ全てにありえますが、典型的な脅威として下記があります。

  • 外部からアクセスできない対象へのブラウザ経由での攻撃
  • SSRF攻撃のチェック回避

ブラウザ経由での攻撃

ブラウザ経由での攻撃の概要図を示します。

上図は、攻撃者の誘導により、被害者が罠のページ(http://trap.example.org/)を閲覧しているところです。罠ページが閲覧された瞬間にDNSのAレコード(IPv4アドレス)を変更し、罠ページは10秒後にXMLHttpRequestにより http://trap.example.org/secret.html をアクセスします。この時点ではIPアドレスは変更されているためイントラネット内のサーバーにアクセスします。この攻撃により、外部からは直接アクセスできないサーバーにアクセスできます。

このように、DNSリバインディングは、イントラネット内のサーバーの他、ルーターやファイアウォール、IoT機器など、利用者のパソコン自身など、「外部からはアクセスできないが内部ネットワークからはアクセスできる」機器やサーバーが主な攻撃対象です。IPアドレスのみでアクセス制御されているサイトも攻撃対象になります。

攻撃対象の例として、Ruby on Railsの開発環境がありました。Railsの開発支援機能web-consoleはDNSリバインディングに脆弱で、任意のコードを外部から実行できる問題が指摘されていました。

DNS rebinding attacks protection in Rails 6

このため、バージョン6以降で開発版でのDNSリバインディング対策が入るようになりました)。具体的にはHostヘッダのチェックであり、これはDNSリバインディングの定石的な対策方法の一つです。

この機能は開発環境のみでプロダクション環境では無効になります。 これは、Web-consoleのようなデバッグ支援環境でリモートコード実行の脆弱性が入りやすい(現実にあった)ので、開発環境だとDNSリバインディングの脅威があるという想定だと思います。

【参考】


SSRF攻撃との組み合わせ

SSRF攻撃の際に使われるDNSリバインディングについては以下の記事をお読みください。

EC2上でDNS RebindingによるSSRF攻撃可能性を検証した | 徳丸浩の日記

ここでは概要を説明します。以下のようなスクリプトがEC2上で動いているとします。外部からURLを取得して、その内容を表示するものです。

$url = $_GET['url']; $urlinfo = parse_url($url); $host = $urlinfo['host']; // URLからホスト名を取り出し $ip = gethostbyname($host); // 接続先IPアドレスを取得 if ($ip == "169.254.169.254") { // AWSのIMDSチェック die("Invalid host $host"); // IPアドレスが169.254.169.254ならエラー } $ch = curl_init($url); // URLからコンテンツ取得、表示

上記のスクリプトに、IPアドレス 169.254.169.254 のチェックをしていますが、これはEC2のIMDS (Instance Metadata Service)という機能を悪用されることを防ぐためです。IMDSは下記のように、169.254.169.254という仮想的なエンドポイントにアクセスすると、参照元インスタンスの設定を返します。以下は、EC2インスタンスに付与されたIAMクレデンシャルを参照する様子です。

[ec2-user@web ~]$ curl http://169.254.169.254/latest/meta-data/iam/security-credentials/XXXX { "Code" : "Success", "LastUpdated" : "2022-05-08T04:17:09Z", "Type" : "AWS-HMAC", "AccessKeyId" : "ASIAR6Mxxxxxxxxxxxxx", "SecretAccessKey" : "Wrt7en1xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", "Token" : "IQoJb3JpZ2luX2VjEAQaDxxxxxxxxxxxxxxxx...", "Expiration" : "2022-05-08T10:52:42Z" }

先に示したスクリプトは複数の抜け道があるのですが、その一つがDNSリバインディングによる攻撃です。以下は、DNSサーバーにdigコマンドにより連続してアクセスしたところ、2回目にIMDSのIPアドレスが返っている様子です。

[ec2-user@web ~]$ dig example.net +short ; dig example.net +short 203.0.113.2 169.254.169.254 [ec2-user@web ~]$

これにより、IPアドレスチェックの際は無害な内容を返し、本番アクセスの際はIMDSのIPアドレスということになって、SSRF攻撃によりIMDSの内容を盗むことができます。

【参考】


DNSリバインディングの対策

下図はDNSリバインディングの対策ができる場所を示しています。


以下、図中の数字の順に説明します。

① 対象サイト側の対策

DNSリバインディングの根本対策は、攻撃対象のサイトや機器側で行われるべきです。DNSリバインディングの対策は以下のいずれかにより対策できます。

  • ホスト名のチェック、あるいはダミーのデフォルトバーチャルホスト
  • 認証機能の実装(安全なパスワードを設定すること)

以下はNginxでダミーのバーチャルホストを設定している例です。本番サイトはexample.jpですが、それ以外のホスト名のリクエストはすべてダミーのコンテンツが返されることになります。ダミー側には機密情報や機能などはないので、DNSリバインディング攻撃を「受け流す」ことができます。

# ダミーのバーチャルホスト(Hostヘッダがexample.jp以外はこちらが設定される) server { listen 80 default_server; server_name '_'; root /var/www/dummy; # 無害なコンテンツが返される } # 本番サイトのバーチャルホスト server { listen 80; server_name example.jp; …

あるいは、認証機能の実装でも対策になります。DNSリバインディング攻撃は利用者のセッションを乗っ取れるものではないからです。IoT機器やルーターなど初期パスワードが設定されているものは、必ず初期パスワードを変更する必要があります。

【参考】

SSRF対策のパイパスについては、SSRF自体の対策の中で考える必要があります。詳しくは以下のコンテンツを参照ください。

② ブラウザ側対策

DNS Pinning

主要ブラウザでは、DNSリバインディング対策としてDNS Pinning(DNSピニング)が実装されています。DNS Pinningとは、DNSのTTLが短い場合でも、DNSの参照結果を一定時間保持することです。下図は主要ブラウザのDNS Pinningの期間です。

Google Chrome Firefox Safari IE
1分程度 1秒~70秒 15秒~30秒 無期限?

DNSリバインディング対策という観点からはDNS Pinningの期間は長いほど安全ですが、DNSリバインディング以外の正当な状況でサーバーのIPアドレスが変化する場合もあるので、過度にDNS Pinningの期間が長いと副作用もあると考えられます。DNS Pinningの期間は時代とともに変化しており、最近はウェブサイトの本来のIPアドレスが短期間で変化するため、DNS Pinningの期間は短めにされる傾向があります。

Google Chromeで提唱されている対策

Google ChromeではDNS Pinning以外に「ローカルネットワークに対する攻撃」への防御機能が実装され始めています。Google Chrome 94では、XMLHttpRequestやFetch APIにより「パブリックネットワークからプライベートネットワークへの送信」については、HTTPSであることを要求するようになりました。

Starting in Chrome 94, public non-secure contexts (broadly, websites that are not delivered over HTTPS or from a private IP address) are forbidden from making requests to the private network.

Private Network Access update: Introducing a deprecation trial - Chrome Developers より引用

Chrome 94以降、パブリックな非セキュアコンテキスト(広義には、HTTPSで配信されていないウェブサイトや、プライベートIPアドレスからでないウェブサイト)は、プライベートネットワークへのリクエストが禁止されるようになりました(私訳)。

これにより、Google ChromeでDNSリバインディング攻撃しようとすると以下のようなエラーになります(ホスト名は例示用のもの)。

Access to XMLHttpRequest at 'http://example.com/secret.txt' from origin 'http://example.org' has been blocked by CORS policy: The request client is not a secure context and the resource is in more-private address space `private`.

エラーメッセージとしてはCORSエラーとなっていますが、DNSリバインディングは通常同一オリジンポリシーの範囲内のアクセスであり、当然CORSのエラーではありません。しかし、Google Chromeの最近のセキュリティ機能では、パブリックネットワークからプライベートネットワークへのリクエスト、およびプライベートネットワークからローカルホストへのアクセスについては、通常より厳しい制限を課していることになります。

このセキュリティ機能は、ローカルネットワークに対するCSRF緩和策として導入されたようですが、DNSリバインディング対策としても機能すると思われます。なぜなら、HTTPSによりDNSリバインディング攻撃しようとすると、攻撃先サーバーへのアクセスで証明書のエラーエラーになり、アクセスは停止するからです。

さらに、Google Chrome 102 以降では、このような状況でプリフライトリクエストが送信されるようになる予定です。

Preflight requests for PNA are also sent for same-origin requests, if the target IP address is more private than the initiator. This is unlike regular CORS, where preflight requests are only for cross-origin requests. Preflight requests for same-origin requests guard against DNS rebinding attacks.

Private Network Access: introducing preflights - Chrome Developers より引用

PNA(Private Network Access)のプリフライトリクエストは、ターゲットIPアドレスがイニシエーターよりもプライベートである場合、同一オリジンのHTTPリクエストに対しても送信されます。これは、プリフライトリクエストがクロスオリジンリクエストに対してのみ送信される通常のCORSとは異なります。同一生成元リクエストのプリフライトリクエストは、DNSリバインディング攻撃を防止します(私訳)。

引用元にもDNSリバインディング攻撃防止のためと明記されています。

このようにGoogle Chrome(あるいはChromium系ブラウザ)を使うことでDNSリバインディングの対策が強化されますが、これら対策はProxyサーバー経由での通信には適用されません。Proxy経由での通信の場合、ブラウザからはパブリックあるいはプライベートという区別がつかないからです。これはDNS Pinningについても同様であり、各ブラウザ共通の挙動になります。

③ Proxyサーバーでの対策

前述のようにProxy経由でのブラウザ利用の際には、ブラウザ側のDNSリバインディング対策は機能しないため、Proxy側での対策が求められます。よく理由されるFoward ProxyであるSquidには、以下のDNS Rebindin対策が利用できます。一方、Apache HTTPdをProxyとして使う場合、DNSリバインディングに使える機能は調査の範囲では見つかっていません。ご存じの方はぜひご指摘ください。

(1) IPアドレスによるアクセス制御

Squidのアクセス制御機能から、接続先(Destination)のIPアドレスを制限することができます。以下は、192.168.0.0/24に対するアクセスを拒否する例です。

acl localnet dst 192.168.0.0/24 http_access deny localnet

(2) DNS Pinning

SquidはDNSキャッシュの上下限を指定することができます。

ディレクティブ 意味 デフォルト値
positive_dns_ttl DNSキャッシュの上限 6時間
negative_dns_ttl DNSキャッシュの下限 1分

これらのうち、negative_dns_ttl はDNS Pinningの用途に使うことができます。 しかしながら、negative_dns_ttlをむやみに長くすると副作用もあります。もしも正規のDNSクエリに失敗した場合、その失敗の結果もキャッシュされるからです。また、前述のように、正常なIPアドレスが短期間で変わる場合もありえます。このため、negative_dns_ttlをデフォルトより長くすることはお勧めできません。

結論としては、SquidでDNSリバインディング対策する場合は、(1)のアクセス制御による方法がお勧めです。

【参考】

④ DNSキャッシュサーバーでの対策

リゾルバ(DNSキャッシュサーバー)による対策も可能です。Squidの項で説明したDNS Pinningとアクセス制御の両方が主要リゾルバで用意されています。

DNS Pinning

下表に主要ブラウザでDNS Pinningを指定するディレクティブを示します。DNSコンテンツサーバー側でTTL=0秒などと短い秒数が指定されていた場合でも、こちらで指定した秒数に切り上げられます。

リゾルバ bind9 unbound dnsmasq PowerDNS KNOT DNS
設定項目 min-cache-ttl cache-min-ttl min-cache-ttl minimum-ttl-override cache.min_ttl()
備考 90秒以下 制限など記載なし 1時間以下 デフォルト1秒 デフォルト5秒

PowerDNSとKNOT DNSは最短のTTLがデフォルトとして指定(1秒~5秒)されており、TTL=0は許容されない設定になっています。このような控え目の設定でもSSRF攻撃の緩和には役立つと思われます。

特定IPアドレスの拒否

また、多くのDNSサーバーは、DNSリバインディング対策として、IPアドレスのフィルタリング機能を提供しています。下表はIPアドレスの拒否リストあるいはDNSリバインディング対策として使えるプライベートIPアドレス等を拒否するためのディレクティブの一覧です。

リゾルバ bind9 unbound dnsmasq PowerDNS KNOT DNS
設定項目 deny-answer-addresses private-address stop-dns-rebind 設定は見つからなかった modules.load('rebinding < iterate')
備考 サブネットマスク等で指定 サブネットマスク等で指定 一括停止 Luaスクリプトで可能 一括停止、詳細にやるならLuaスクリプト

私の調査では、PowerDNSのみ該当する項目を探せなかったのですが、Luaスクリプトで特定IPアドレスを拒否することは可能でした。 また、dnsmasqとKNOT DNSはIPアドレス指定ではなく、DNSリバインディングに使われそうなサブネットマスクを一括して拒否する形になっています。

また、単体のリゾルバではありませんが、Googleが提供するGoogle Nest WiFiにはDNSリバインディング防御機能が提供されてます。

Google Nest スピーカー、ホームメディア サーバー、IoT(モノのインターネット)デバイスのような接続されたデバイスをホストするホーム ネットワークは、DNS リバインディングと呼ばれる攻撃を受けるおそれがあります。Google Wifi では、この種の攻撃を防止するため、DNS リバインディングに対する保護機能で、公開ドメインにプライベート IP アドレス範囲を使用されないようブロックすることができます。この機能はデフォルトで有効になっています。

DNS リバインディングに対する保護機能 - Google Nest ヘルプより引用

試したところ、192.168.10.1 のようなプライベートIPアドレスはブロックされる一方で、127.0.0.1 のようなlocalhostのアドレスはブロックされません。また、当該機能は副作用の可能性もあるため、無効にすることもできます。

リゾルバでのDNSリバインディング対策をどう考えるか

多くのリゾルバがDNSリバインディング対策の機能を提供しますが、デフオルトは無効化されていることから、いずれも「積極的に使っていきましょう」という姿勢ではないように感じます。その典型はbindです。min-cache-ttlの最大値は90秒なので「これで守り切る」という数字ではありません。また、IPアドレスの拒否リストについては以下のような注意書きがマニュアルに付記されています。

The “rebinding” attack must primarily be protected at the application that uses the DNS. For a large site, however, it may be difficult to protect all possible applications at once. This filtering feature is provided only to help such an operational environment; turning it on is generally discouraged unless there is no other choice and the attack is a real threat to applications.

4. BIND 9 Configuration Reference — BIND 9 9.19.0 documentation より引用

リバインディング攻撃は、主にDNSを使用するアプリケーション側で保護されなければなりません。しかし、大規模なサイトでは、可能性のあるすべてのアプリケーションを一度に保護することは困難な場合があります。このフィルタリング機能は、そのような運用環境を支援する目的にのみ提供されています。他に選択肢がなく、攻撃がアプリケーションにとって本当に脅威とならない限り、この機能を有効にすることは一般に推奨されません。(私訳)

この「DNSを使用するアプリケーション側で保護されなければなりません」という指摘に私も同意します。 また、以下の資料にはDNSリゾルバの防御機能の抜け穴が報告されています。例えば、CNAMEとしてlocalhost.を返すようなケースが紹介されています。

このため、DNSリゾルバでの対策はあくまで緩和策としてとらえておくべきだと思います。

結局DNSリバインディング対策はどうすればよいか

ここまで説明したように、DNSリバインディング対策が「出来る」ポイントは以下の4箇所あります。

  • 攻撃対象
  • ブラウザ
  • PROXYサーバー
  • リゾルバ

これらの中で、確実な対策がとれるのは攻撃対象のみです。対策自体は難しいものではないので、まずはこれを検討するべきです。 しかし、以下のような状況はありえます。

  • 社内ネットワーク内に攻撃対象となり得る機器が多すぎで把握すら難しい
  • 対象のサーバーや機器側の仕様上対策が難しい

このため、以下のステップで対策を検討するとよいでしょう。

  1. ネットワーク内に存在するDNSリバインディング攻撃対象の機器やパソコンの洗い出し
  2. 対策の要否検討
  3. 対策方法の検討
  4. 対策実施

DNSリバインディングはマイナーな攻撃方法であり、他のウイルス感染などの方が簡単に侵入できるため、あまり過敏になることもないとは思いますが、原理的には可能であるので、「重要情報が盗まれる」などの状況は放置しない方がよいでしょう。DNSリバインディングの確実な対策の一つが「認証ちゃんとやる」ですので、結局のところ、

  • 社内ネットワークといえども認証とアクセス制御をきちんとやる

この当たり前のことをちゃんとやっていれば大丈夫です。 後は、保険的な対策としてPROXYやリゾルバの対応をどうするかですが、近年はPROXYやリゾルバはセキュリティ製品の一機能である場合も多く、自前でオープンソースソフトウェアを構築するケースは少ないと思います。なので、PROXYやリゾルバでの対策は、積極的に活用するというよりは、「使える場合は使うことも考える」くらいのレベル感ではないでしょうか。

まとめ

DNSリバインディングの対策として使える機能について説明しました。Google社がDNSリバインディング対策に熱心なことが印象的ですが、まずは攻撃可能性の洗い出しと、ローカルネットワークでも認証をおろそかにしないという基本的な対策を推奨いたします。

2022年3月14日月曜日

とある通販サイトに学ぶ自動ログイン機能のバッドプラクティス

 サマリ

とある通販サイトにて「 メールアドレス・パスワードを保存する」機能がありますが、サイトにクロスサイトスクリプティング(XSS)脆弱性がサイトにあると生のパスワードが漏洩する実装となっています。本稿では、この実装方式を紹介し、なぜ駄目なのか、どうすべきなのかを紹介します。

記事の最後にはセミナーのお知らせを掲載しています。


はじめに

家人がテレビを見ていて欲しい商品があるというので、あまり気は進まなかったのですが、その商品を検索で探して購入することにしました。「気が進まない」というのは、利用実績のないサイトはセキュリティが不安だからという理由ですが、この不安は的中してしまいました。

最初の「えっ?」はパスワード登録のところでして、パスワードを再入力する箇所で「確認のためもう一度、コピーせず直接入力してください」とあるのですよ。私は乱数で長く複雑なパスワードを入力しかけていたのですが、コピペができないとなると長すぎるので、パスワードを短くしました。セキュリティ上は逆効果だと思うのですが、なぜこうするのでしょうかね。しかし、これは本題ではありません。


「パスワードを保存する」チェックボックスの存在

会員登録が終わってサイトにログインしようとすると、パスワード欄の下に下記のようなチェックボックスがあり、デフォルトはONになっています。

メールアドレス・パスワードを保存する

「ログイン状態を保持」とかならよくある機能ですが、「パスワードを保存」とは匂いますね。そこで、そのままログインをした後、ログアウト後にもう一度ログイン画面を表示させると、なんということでしょう! メールアドレスとパスワードが初期値として入っているではありませんか! 以下のようなHTMLがサーバー側で生成されていました。

<input name="email" value="tokumaru@example.jp">
<input type="password" name="pwd" value="P@ssw0rd">


「パスワードを保存する」機能の実装は?

こういう実装を見ると「サーバー側でパスワードが平文で保存されている」と思う人が多いようですが、そうではないようです。

メールアドレスとパスワードは、あるクッキー(ここではXとする)に紐づけられています。当初は、クッキーXをキーとしてサーバー側でパスワード等を保存しているのかと思いましたが、そうではなく、クッキーXにメールアドレスとパスワードが暗号化して保存されているようです。そう判断した理由は、メールアドレスとパスワードの長さを変えるとクッキーの長さも変わるからです。また、暗号化に際し初期化ベクトルも使ってないようです。


クッキーが漏洩すると平文パスワードまで漏洩する

「初期化ベクトルを使わないなんてダメじゃないか」と思いますよね。そうなんですが、このサイトの場合、もっとダメな理由があります。というのは、暗号化されたクッキーをセットしてログイン画面を表示させると、先に紹介したように、平文でメールアドレスとパスワードがHTML上に表示されるのです。つまり、暗号化していても簡単に平文に戻せるのですよね。なので、初期化ベクトル云々という次元ではなくなってしまっているわけです。

このサイトの場合、クッキーXにsecure属性はついていますが、HttpOnly属性はついていません。なので、サイト上にクロスサイトスクリプティング(XSS)脆弱性があると、クッキーは簡単に漏洩します


仮にHttpOnly属性がついていてもXSSで平文パスワードが漏洩する

しかし、仮にクッキーXにHttpOnly属性がついていても、XSS攻撃により平文のメールアドレスとパスワードは漏洩します。XSS攻撃によりXMLHttpRequestでログイン画面をリクエストすると、そのレスポンスのログイン画面HTMLにはメールアドレスとパスワードが平文で記載されているからです。

そもそもサイトにXSSがあると、クッキーにHttpOnly属性がついていても「なりすまし」により情報漏えいやサイト機能の悪用は避けられません。このあたりは以下の動画にて詳しく説明しています。

しかし、パスワードまで漏洩してしまうと、そのパスワードがパスワードリスト攻撃により悪用されたり、「パスワードを入力しないと利用できない機能」まで悪用できるので通常のXSSよりも被害が増大することになります。


この場合のベストプラクティスは?

ログインを簡便にするために、いったんログインした後はパスワードを入力しなくてもログインを継続したいというニーズ自体はよくあるものであり、拙著では、「5.1.4 自動ログイン」にて解説しています。

体系的に学ぶ 安全なWebアプリケーションの作り方 第2版 脆弱性が生まれる原理と対策の実践

本項では、自動ログインの危険な実装を紹介した上で、トークンを使うなど安全な自動ログインの実装方法について紹介しています。詳しくは上記書籍を参照してください。


サイトオーナーはどうすればよかったのか?

とある通販サイトの自動ログイン機能がイケてないことを紹介しましたが、このサイトの運営者はどうすればよかったのでしょうか。

まず思いつくのは「脆弱性診断はしていなかったのか?」ということです。脆弱性診断していたかどうかは外部の者には分かりませんが、以下の可能性が考えられます。

  • 脆弱性診断はしていなかった
  • 脆弱性診断はしていたが指摘されなかった
  • 脆弱性診断で指摘されていたが、改修はしなかった

最後のケースを考えると、仮に脆弱性診断で指摘されていたとしても、サイトが出来上がった後では簡単に修正できるものでもなく、いささか「手遅れ」という感があります。なので、サイトを実装する前に自動ログインのセキュリティを検討しておくべきでした。

自動ログインは珍しい機能ではなく、「徳丸本にも載っている」ようなよくある機能なのですから、ウェブアプリケーションのセキュリティガイドラインのようなものがあれば、安全な実装ができていたかもしれないと考えられます。このガイドラインには、自動ログインのような機能面だけでなく、SQLインジェクションのような実装面にも言及されているとよいですね。


宣伝

では、「徳丸本にも載っていないような機能」についてはどうすればよいでしょうか。こちらについては個別に検討するしかありません。その際に類似機能を持つ先行サイトを調べてもよいでしょうが、たまたま参考にしたサイトがセキュリティ的に強固な仕様であるとは限りません。

また、「そもそもセキュリティ上の問題があるのか」という脅威分析をしないことには、セキュリティを検討する・しないの俎上にも上がらないということになります。

ということから考えると、セキュアな開発にも到達度レベルがあって、以下のようになるのではないかと考えています。

今回紹介したケースは、脆弱性診断はしていたかもしれないが、指摘されたか否かは分からず、少なくとも危ない実装が修正されないまま本番リリースされたという意味で、「レベル1にも到達していない」と考えられます。

私は拙著を書く際に、ウェブアプリケーションに存在する問題を列挙してできるだけ多くのパターンを解説してしまおう、と目論みました。なので徳丸本はあんなに分厚いのですが、それでも全てのパターンを列挙することは当然できなません。なので、徳丸本をいくら読んでも到達できるのは上記の「レベル2」です。

私の最近の関心はその上のレベルに到達するための方法論です。これについては2022年3月16日のセミナーにて簡単に紹介する予定ですので、お時間がある方は参加いただけると幸いです(宣伝)。

  • 2022年3月16日(水)16:00~17:00(オンライン)
  • 講演タイトル:セキュア開発ライフサイクル(SDLC)実践入門
  • イベント詳細・お申し込みはこちらから

フォロワー

ブログ アーカイブ