イエラエセキュリティ CSIRT支援室 第9回「gRPC ベースのシステムの脆弱性診断とツール(前編)」 | ScanNetSecurity
2024.05.02(木)

イエラエセキュリティ CSIRT支援室 第9回「gRPC ベースのシステムの脆弱性診断とツール(前編)」

近年 gRPC の利用がだいぶ普及してきましたね。今回は gRPC を利用するシステムの脆弱性診断と、そのためのツールについて書きたいと思います。

製品・サービス・業界動向 業界動向
イエラエセキュリティ CSIRT支援室 第9回「gRPC ベースのシステムの脆弱性診断とツール(前編)」
イエラエセキュリティ CSIRT支援室 第9回「gRPC ベースのシステムの脆弱性診断とツール(前編)」 全 4 枚 拡大写真
 札幌オフィス在籍の岸谷です。近年 gRPC の利用がだいぶ普及してきましたね。今回は gRPC を利用するシステムの脆弱性診断と、そのためのツールについて書きたいと思います。

●gRPC って何?

 本稿は gRPC 自体の解説を目的としたものではありませんが、本題に進む前に簡単に概要に触れます。gRPC は Google で開発され、その後オープンソース化されたフレームワークです。grpc.io には下記のようにあります。


gRPC is a modern open source high performance RPC framework that can run in any environment.


 「環境を問わずハイパフォーマンスな RPC 開発フレームワーク」ということで、XML-RPC や JSON-RPC、REST API 開発用のフレームワークなどのように、他コンピュータ上のコードの呼び出しなどシステム間通信の開発に利用します。以下のような特徴があります。

・アプリケーション層のプロトコルとシンプルなスキーマ定義言語(標準で Protocol Buffers を利用する)

・スキーマ定義から各種言語用クライアント&サーバのコード生成などを行える開発ツール群

・HTTP/2 の利用

●gRPC のよいところ

 gRPC のよいところは開発効率と通信効率でしょう。それぞれ見て行きましょう。

開発効率

 特徴として挙げた通り、gRPC は標準のメッセージフォーマットとして Protocol Buffers を利用します。
RPC クライアントとサーバで共有するスキーマ定義 = インターフェース仕様を .proto ファイルに記述しておき、それをもとに自動生成したクライアントとサーバのコードを実装して開発を進めることができます。OpenAPI Generator なども同様の流れですね。

 小規模なプロジェクトなら、サーバとクライアントのインターフェース仕様を一個の .proto ファイルに記述し、それにコメントで詳しい API 仕様等も記載しプロジェクトのリポジトリで共有すれば、このファイルが実装の一部でありつつ複数のドキュメントの役割も兼ねられます。いくつもの形式のドキュメントを作る手間が減らせ、開発チーム間の認識相違による手戻りなどを防ぎつつ効率よく開発できそうです。

 また例えばいわゆる microservices 的な、多数の相互関連するサービスがそれぞれ別々のチームや言語で開発されていたり、多対多の場合を含めて相互にインターフェース仕様が整合した状態を維持して行くケースでは gRPC を採用するメリットが大きいのではないでしょうか。

通信効率

 ネットワーク上で同じ意味のメッセージを送る場合、データ量が小さければ小さいほど通信が早く完了し、よりよい利用者体験に繋がります。特にモバイルインターネット回線などでは回線帯域に優しいことは重要でしょう。Protocol Buffers を用いると、例えばHTTPクエリ文字列等で一般的な「key=value」形式や JSON のようなフォーマットに比べ、開発者が特に意識せずとも多くの場合にデータサイズが小さくなります。以下に、各フォーマットで同じ意味のデータを表現したメッセージ例を示します。


・Content-Type: application/x-www-form-urlencoded (データ長 53 バイト)

name=Naoki+Hanzawa&target=Akira+Owada&num_revenge=100


・Content-Type: application/json (データ長 65 バイト)

{"name":"Naoki Hanzawa","target":"Akira Owada","num_revenge":100}


・Content-Type: application/grpc (データ長 35 バイト )

\x00\x00\x00\x00\x1E\x0A\x0DNaoki Hanzawa\x12\x0BAkira Owada\x18\x64

※"\xXX" は ASCII 印字可能文字以外のバイト列


 印字可能文字以外のバイト列のせいで一見 gRPC が一番大きいような見え方になってしまいましたが、データ長は 35 バイトの gRPC が最も小さいことが分かります。数十バイトの通信の差は体感不能だと思いますが、これがある程度大きいメッセージの場合、さらには例えば秒間数十万~数百万のメッセージを処理するような大規模システムの場合、データ量の差は大きいものになるでしょう。
※現実の通信ではデータ圧縮などの要素が影響しますが、ここでは主旨から外れるため考慮しません

 さて、どこでデータ長の差が生まれたのでしょうか?

 大きな差異として、前 2 者にある「name」「target」といったパラメータ名が gRPC(上記では標準の Protocol Buffers エンコーディング)には含まれていません。その代わりの情報を「フィールド番号」として保持しており、クライアントとサーバはこの番号でパラメータを識別することができます。先に触れた .proto ファイルに下記のようなメッセージ定義があれば、受信したメッセージをパースして「フィールド1番はname」「2 番は target」と理解できるのです。


message Baigaeshi {
 string name = 1;
 string target = 2;
 int32 num_revenge = 3;
}

※「string」「int32」などが型、「name」などがフィールド名(パラメータ名)、1, 2, 3 がフィールド番号


 Protocol Buffers メッセージには ASCII 印字可能文字以外のバイト列も含まれますので、テキストデータを期待するソフトウェアで表示すると文字化けしたようになってしまいます。

イエラエセキュリティ CSIRT支援室 第9回「gRPC ベースのシステムの脆弱性診断とツール(前編)」
 どのようにデコードするか見てみましょう。メッセージを再掲します。


\x00\x00\x00\x00\x1E\x0A\x0DNaoki Hanzawa\x12\x0BAkira Owada\x18\x64


 gRPC では先頭1バイト(\x00)は圧縮フラグ、続く 4 バイト(\x00\x00\x00\x1E)が後続のメッセージ本文の長さです。これに Protocol Buffers などのメッセージ本文が続きます。
フィールド番号 1 番を示す箇所は 6 バイト目 “\x0A” です。これを 2 進数表現して “00001010” の 2~5 ビット目(0001)でフィールド番号の 1 を表し、残り 3 ビット(010)で “wire type” (伝送上の型情報。“010” = 2 なら string などを含むLength-delimited 型)を表しています。長さ情報が必要な型の場合、続く 7 バイト目の “\x0D” で値の長さ(バイト)を表すといった形式です。フィールド番号と wire type、必要に応じ長さ、データ本文バイト列が必要数分連結されます。
※ここでは varint 形式についてなど多くの説明を省略していますので、詳細に興味がある方は公式ドキュメントをご覧ください

 key=value 形式や JSON でもパラメータ名を番号にすることはできますが、それらをシステム上の変数名等とマッピングする工数をかけなくては開発しにくいですし、ドキュメントも複雑になりバグを量産してしまいそうですね。

 他にはデリミタや数値の基数(何進数表現か)のような細かい差異もありますが、これらの影響はケースバイケースでしょう。

 加えて gRPC は HTTP/2 を利用しますので、ヘッダ圧縮(HPACK)や TCP ハンドシェイク回数の減少などによる通信効率向上も期待できます。

 こうしたことから、回線の速度や通信容量に制限があるモバイル端末向けアプリや IoT 機器の通信や、速度が重視されるシステム間通信などで、gRPC は高パフォーマンスで安定した選択肢として今後も普及が進みそうです。
一方で、Web ブラウザがクライアントとなる Web アプリケーション界隈では、Web ブラウザ向け実装の gRPC-Web もあるものの、機能的な制限があったり構成に一手間要することなどから、まだまだこれからという状況かと思います。

●脆弱性診断する上での課題

 さて、ようやく本題です。gRPC を利用しているシステム、とりわけインターネット向けなどクライアントを信用できない環境下にあるサーバサイドアプリケーションのブラックボックス形式での脆弱性診断を考えます。

 オーソドックスな Web アプリケーションや REST API の脆弱性診断では主に HTTP メッセージの内容を読み、書き換えながら問題点がないか様々なことを試行します。加えて限られた時間の中で多くの作業を行う必要があるため効率化のためのツールを利用します。gRPC にはこれまでに挙げた特徴から、従来の脆弱性診断と比べ次のようなテスタビリティ面の課題があります。

1. Protocol Buffers の利用に関する課題

2. HTTP/2 の利用に関する課題

Protocol Buffers の利用に関する課題

 従来の一般的な Web アプリケーション等では、HTTP リクエスト / レスポンスはヘッダとデータともに大部分がテキストとして扱える形式でした。脆弱性診断でも多くの作業は key=value 形式や JSON などをテキストとして書き換えて行うことができました。

 しかし先に触れた通り、Protocol Buffers は印字可能文字以外のバイト列も含むバイナリデータです。また、一つひとつのパラメータがフィールド番号とデータ型、長さといったメタデータとセットになっています。何かをテストするために一つのパラメータを書き換えたい時、メッセージ全体の正常性、整合性を保ちつつ書き換えるには値そのものに加えそれらのメタデータも正しく更新する必要があります。また 1 バイトの中でビットごとに役割がある場合もあり、そうしたことも考慮して Hex エディタで複数箇所を適切に更新しなくてはいけません。これを手作業で都度行うのは手間がかかります。

イエラエセキュリティ CSIRT支援室 第9回「gRPC ベースのシステムの脆弱性診断とツール(前編)」
 とは言え、これについては特段難しい課題という訳ではありません。Protocol Buffers v3 以降は JSON と相互変換可能な仕様で、必要に応じて JSON などに変換した上で編集し、送信する時には再度 Protocol Buffers にエンコードすれば解決できます。各種ツールやその拡張機能でそのようなことをするものもいくつかあります。
※ただしパラメータ名がフィールド番号だと役割を直感的に読み取れず手間がかかります。この解決方法は追って紹介します。

HTTP/2 の利用に関する課題

 HTTP/2 は 2015 年に RFC7540 として標準化され、一般的な Web サーバやクライアントであればほとんどはサポート済の状態です。しかし、Web アプリケーション診断に関わる多くの方が愛用する Burp Suite など汎用的なツールの多くは長らく HTTP/2 に未対応または部分的対応の状態でした。そもそも HTTP/2 メッセージを扱えないという課題です。
※なお、Burp Suite はセキュアスカイ・テクノロジーさんのエンジニアブログに記事がある通り、2020 年 6 月に HTTP/2 の試験的・部分的サポートを始めました。

Burp 2020.6 で HTTP/2 対応したから試してみた

 HTTP/2 はプロトコルとして HTTP/1.1 までとはだいぶ異なります。
HTTP/1.1 はリクエストとレスポンスに共通して、基本的にはテキストベースで 1 メッセージ内にヘッダとボディを順に記述する形でシンプルです。
それに対して HTTP/2 ではヘッダは HEADERS フレームで送り、従来のボディにあたる部分を別途 DATA フレームで送るなどコネクションとストリーム、フレームの考え方や、バイナリ指向であったりなど多くの面で異なります。ヒューマンフレンドリーから、よりマシンフレンドリーで効率重視のプロトコルになりました。

 ただし、一般的な Web ブラウザなどは 1.1 と 2 の両対応が通常で、通信相手と双方が対応している方を選択してくれます。URL や Cookie などのヘッダ、データ本文といった従来と同じメッセージを伝送する方式が異なるだけで、そこはブラウザやサーバがうまくやってくれます。
そのため、Web サーバ層を含むアプリケーションの場合は除きますが、Web アプリケーションのコードを書く時にどちらの通信かを考えなくても HTTP/2 対応サイトを作ることはでき、1.1 との互換性も保たれます。従って脆弱性診断ツールも HTTP/1.1 だけで従来通り多くの Web アプリケーションを診断可能で、HTTP/2 対応の優先順位が高くなかったのではないかと思います。

 しかし gRPC の利用も含め、ブラウザ以外のソフトウェアで HTTP/2 のみを使用するシステムも増えてきました。そのような中 mitmproxy や DeNA さんが公開されている PacketProxy、直近で Burp Suite などのツールも HTTP/2 を徐々にサポートしてきたものの、それぞれにまだ部分部分で未サポートの動作があります。例えば通信開始の仕方がいくつかある中で、Web ブラウザが通常行う以下の 1, 2 番は概ね対応していますが、3 番には未対応であるなどです。

1. ALPN を介した HTTP/2 接続

2. 一度 HTTP/1.1 で接続した上で Upgrade ヘッダによって HTTP/2 へ切替

3. 通信相手が HTTP/2 対応である前提で、ネゴシエーションを省略して Connection Preface を送信する

 他に、近年の流れもあって HTTPS で HTTP/2 を利用することが主だと思いますが、平文(http://)での通信も可能で区別のため h2c と呼びます。mitmproxy や Burp Suite はこれを書いている時点では h2c に対応していません。
Server push、Priority といった HTTP/2 の機能や、Trailer(データの後に続くヘッダ)も対応していないものが多いようです。他にも Burp Suite で言うと透過 Proxy(Invisible proxy)モードでは HTTP/2 が未サポートで、gRPC 通信でもこれらが支障になりがちです。

 例えば、利用する開発フレームワーク等にもよると思われますが、いくつかの言語でドキュメントに従って HTTPS 対応の gRPC クライアントを素直に書いてみると、信頼する CA 証明書をクライアントに持たせることが多いようで、これまでに見たシステムはそのパターンがほとんどでした。つまりシステム(OS)が持つ CA 証明書を信頼するのではなく、クライアントソフトウェア自身が持つ CA 証明書により通信相手のサーバ証明書を検証します。これは広義でTLS証明書 Pinning の一形態と言えます。
※言語やフレームワークによる例外もあるかもしれませんが、もちろん OS の持つ CA 証明書を使用させる実装も可能です

 Pinning は適切に運用すれば中間者攻撃対策を強化でき、セキュリティの観点からすると推奨されます。しかし、ソフトウェア品質のために行う脆弱性診断もまた中間者として行う手法が主流で、脆弱性診断対象とする環境およびビルドでは一時解除頂くなど、事前に方針をご相談させて頂きます。

 と言うのは、Burp Suite などの Proxy 型ツールでは、Proxy が発行した CA 証明書を予め TLS クライアント側の OS に信頼させた上で、その CA が署名した診断対象ドメインのサーバ証明書を TLS/Proxy クライアントであるブラウザ等に提示することで、クライアントに対して診断対象サーバのふりをして TLS 通信に介入します。Pinning されていると通信に介入できず、これは gRPC や HTTP/2 以外でも回避しなければアプリケーション層の効率的な診断の支障になります。

 クライアントの動作を外から改変して Pinning を無効化する方法はありますが、必ずしも短時間でクライアントの正常動作に影響なく無効化できるとは限りません。また、特にスマホアプリは正規の署名が施されたアプリでないと OS やストア等のアクセス面で不都合が生じたり、root 化して証明書検証を回避しようとしたらそれが検知されたりしがちです。

 開発元で診断対象クライアントの Pinning を無効化して頂くことが可能ならそうして頂けるよう事前相談させて頂きますが、その可否や必要工数は実装や状況によりけりで、場合によってはスケジュールに影響なく行うことは不可という結論の場合もあります。
また開発者の立場から言えば、忙しい中一部のテストだけのために本来想定していない動作変更を、ある程度以上の工数をかけて行うというのは本末転倒であるというのがごく自然な考えです。

 Pinning を無効化できなかった場合の残りの選択肢として、開発元で比較的現実的な工数と変更範囲で Pinning もろとも「HTTPS 自体を OFF にして頂く」という手が考えられます。これはいくつかの言語で見る限りgRPCクライアントとサーバで接続と待受の最小1箇所ずつのメソッドの変更で実現できることがあります。
…しかし h2c だと今度はツール側で対応していないのでした。

 また、前項に引っかからない場合も、OS の Proxy 設定を使用しない gRPC クライアントが多い印象です。通信が Proxy 型ツールを通ってくれないといけませんので、対処としてネットワーク上でクライアントからの通信を Proxy にルーティングしてみても、それを受け付けるための透過 Proxy モードだと HTTP/2 に対応していないのでした。骨が折れます。

 下図のように Burp Suite などの前後に HTTP/2 対応 Proxy を置いて HTTP/2 と HTTP/1.1 を相互変換するというやり方もありますが、私の経験の限り gRPC では、Trailer や大きいサイズのデータの扱いなどに問題が生じたりと、組み合わせ等にもよると思われますが有効な場面は限定的でした。HTTP/2 を LISTEN して内部的には HTTP/1.1 メッセージとして扱うツールもあるようで、それらも同様でした。

HTTP/2とHTTP/1.1の相互変換(Burp SuiteのHTTP/2対応前の社内勉強会スライドより抜粋)
HTTP/2とHTTP/1.1の相互変換(Burp SuiteのHTTP/2対応前の社内勉強会スライドより抜粋)

 既存のツールやその拡張スクリプトを書くなどしたり色々試してはその度に多数ある落とし穴のどれかにはまることを繰り返し、前項も踏まえてたどり着いた結論としては、『少なくとも今のところは gRPC の対応にフォーカスした、既存ツールに近い使い勝手の専用ツールを用意するのが確実だろう』ということでした。

※なお補足として、各ツールとも日々開発が進んでおり、HTTP/2 でもブラウザ向けの一般的な Web アプリケーションに限れば概ね普通に脆弱性診断できるようになってきました。PacketProxy は最近の数回のリリースで gRPC の対応が改善され、以前動作しなかったシステムでも今は動作するようになっていたりと、着実に良くなっています。個人的にはそちらや Burp Suite の拡張などで gRPC などが十分に扱えるようになると良いな…と思う一方、現段階ではまだ選択肢が複数あった方が実務者として問題解決の助けになる段階かと考えています。

 開発したツールを紹介したいと思います…が、ここまでで長くなってしまいましたので、記事を分けて後編に続きます。

<後編へ続く>

(連載「イエラエセキュリティ CSIRT支援室」は、「診断業界の切り込み隊長」として存在感を発揮する株式会社イエラエセキュリティの公式ブログ「SECURITY BLOG」から、創造力あふれるイエラエセキュリティのCSIRT支援の情熱を伝える記事を厳選して掲載しています)

《株式会社イエラエセキュリティ》

この記事の写真

/

特集

関連記事

PageTop

アクセスランキング

  1. ランサムウェア被害の原因はスターティア社の UTM テストアカウント削除忘れ

    ランサムウェア被害の原因はスターティア社の UTM テストアカウント削除忘れ

  2. クラウド労務管理「WelcomeHR」の個人データ閲覧可能な状態に、契約終了後も個人情報保存

    クラウド労務管理「WelcomeHR」の個人データ閲覧可能な状態に、契約終了後も個人情報保存

  3. 信和へのランサムウェア攻撃で窃取された情報、ロックビット摘発を受けてリークサイトが閉鎖

    信和へのランサムウェア攻撃で窃取された情報、ロックビット摘発を受けてリークサイトが閉鎖

  4. 今日もどこかで情報漏えい 第23回「2024年3月の情報漏えい」なめるなという決意 ここまでやるという矜恃

    今日もどこかで情報漏えい 第23回「2024年3月の情報漏えい」なめるなという決意 ここまでやるという矜恃

  5. 「GMOサイバー攻撃 ネットde診断」Palo Alto、Cisco、SonicWall、OpenVPN に対応

    「GMOサイバー攻撃 ネットde診断」Palo Alto、Cisco、SonicWall、OpenVPN に対応

ランキングをもっと見る
PageTop