2007 年 6 月
はじめに
ウェブサービスとやり取りするアプリケーションの開発には、特有の問題があります。よくある不満は、サーバーに送信されたメッセージや受信したレスポンスが正確にわからないことです。追跡が困難なバグのいくつかは、Google がサーバーに送信していると思われるものと、ネットワーク内で実際に送信されている情報の間の断絶が原因で発生します。
この記事では、転送されたデータの可視性と有用性を高めるために役立ついくつかのツールを紹介します。一般に「パケット スニッファ」と呼ばれるこれらのツールは、ネットワーク インターフェース内を移動するすべてのネットワーク パケットをキャプチャします。そのようなデバッグでは、これらのパケットの内容と送受信された順序を調べると便利です。
例: 公開フィードの取得
サイクリング クラブを企画し、情報セッション、チームの募金活動、トレーニングの日程などの計画を立てています。このカレンダーを公開して、チームメンバーやその他の参加者にカレンダーを公開してイベントに参加してもらっています。また、今後の予定を記載したニュースレターを送付したいので、Google カレンダーのウェブサイトから情報をコピーするのではなく、Google Calendar Data API を使用してこのカレンダーをクエリし、予定を取得できます。
RESTful Google Data API を使用してカレンダーをプログラムで操作する方法については、Google Calendar API のドキュメントをご覧ください。(編集者注: v3 以降、Google Calendar API は Google データ形式の使用を終了しました)。まず、カレンダーの設定ページで ボタンをクリックして、カレンダーの予定のフィード URL を取得します。
http://www.google.com/calendar/feeds/24vj3m5pl125bh2ijbbneh953s%40group.calendar.google.com/public/basic
Google カレンダーのドキュメントを参考にして、PUBLIC_FEED_URL
でイベント フィードの URL が保持されているカレンダーの予定を以下のように取得して表示できます。
CalendarService myService = new CalendarService("exampleCo-fiddlerExample-1"); final String PUBLIC_FEED_URL = "http://www.google.com/calendar/feeds/24vj3m5pl125bh2ijbbneh953s%40group.calendar.google.com/public/basic"; URL feedUrl = new URL(PUBLIC_FEED_URL); CalendarEventFeed resultFeed = myService.getFeed(feedUrl, CalendarEventFeed.class); System.out.println("All events on your calendar:"); for (int i = 0; i < resultFeed.getEntries().size(); i++) { CalendarEventEntry entry = resultFeed.getEntries().get(i); System.out.println("\t" + entry.getTitle().getPlainText()); } System.out.println();
これにより、カレンダーの予定の基本的なリストが生成されます。
All events on your calendar: MS150 Training ride Meeting with Nicole MS150 Information session
上のコード スニペットでは、カレンダーの予定のタイトルが表示されていますが、サーバーから受け取った残りのデータについてはどうでしょうか。Java クライアント ライブラリでは、フィードやエントリを XML として簡単に出力することはできません。出力されたとしても XML はすべてではありません。リクエストに付随する HTTP ヘッダーはどうでしょうか。クエリはプロキシ送信またはリダイレクトされましたか?より複雑なオペレーションでは、これらの問題がますます重要になり、特に問題が発生したり、エラーが発生したりします。パケット スニッフィング ソフトウェアは、ネットワーク トラフィックを公開することで、これらの質問に答えることができます。
tcpdump
tcpdump は、Unix 系プラットフォーム上で動作するコマンドライン ツールですが、Windows ポートには WinDump もあります。ほとんどのパケット スニッファと同様に、tcpdump はネットワーク カードを無作為モードにします。このモードにはスーパーユーザー権限が必要です。tcpdump を使用するには、リッスンするネットワーク インターフェースを指定するだけで、ネットワーク トラフィックが stdout に送信されます。
sudo tcpdump -i eth0
このコマンドを実行すると、あらゆる種類のネットワーク トラフィックを利用できるようになりますが、イベントが認識されません。出力をファイルに転送してから後で grep することもできますが、その場合、非常に大きなファイルが発生する可能性があります。ほとんどのパケット キャプチャ ソフトウェアにはいくつかのフィルタリング メカニズムが組み込まれているため、必要なデータのみをキャプチャできます。
tcpdump では、ネットワーク トラフィックのさまざまな特性に基づくフィルタリングがサポートされています。たとえば、サーバーのホスト名を次の式に挿入すると、tcpdump でポート 80 上のサーバーとの間のトラフィック(HTTP メッセージ)のみを取得するように設定できます。
dst or src host <hostname> and port 80
tcpdump は、フィルタ式に一致するパケットごとに、タイムスタンプ、パケットの送信元と宛先、複数の TCP フラグを表示します。この情報は、パケットが送受信された順序を示すため、有益です。
パケットの内容も役に立つ場合があります。'-A' フラグを指定すると、TCP は HTTP ヘッダーとメッセージ本文を公開して、各パケットを ASCII で出力します。「-s」フラグは表示するバイト数を指定するために使用されます(「-s 0」はメッセージ本文がまったく切り捨てられないことを意味します)。
これらすべてをまとめると、次のようになります。
sudo tcpdump -A -s 0 -i eth0 dst or src host <hostname> and port 80
このコマンドを実行した後、上記の短い .Java の例を実行すると、この操作に関連するすべてのネットワーク通信を確認できます。トラフィックには、HTTP GET
リクエストが含まれます。
22:22:30.870771 IP dellalicious.mshome.net.4520 > po-in-f99.google.com.80: P 1:360(359) ack 1 win 65535 E.....@....\...eH..c...P.=.....zP......GET /calendar/feeds/24vj3m5pl125bh2ijbbneh953s%40group.calendar.google.com/public/basic HTTP/1.1 User-Agent: exampleCo-fiddlerExample-1 GCalendar-Java/1.0.6 GData-Java/1.0.10(gzip) Accept-Encoding: gzip Cache-Control: no-cache Pragma: no-cache Host: www.google.com Accept: text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2 Connection: keep-alive
また、Google データフィードを含む 200 OK
レスポンス メッセージも表示されます。フィードは 4 つのパケットに分割されています。
22:22:31.148789 IP po-in-f99.google.com.80 > dellalicious.mshome.net.4520: . 1:1431(1430) ack 360 win 6432 E...1 ..2.I.H..c...e.P.....z.=.:P..M...HTTP/1.1 200 OK Content-Type: application/atom+xml; charset=UTF-8 Cache-Control: max-age=0, must-revalidate, private Last-Modified: Mon, 11 Jun 2007 15:11:40 GMT Transfer-Encoding: chunked Date: Sun, 24 Jun 2007 02:22:10 GMT Server: GFE/1.3 13da <?xml version='1.0' encoding='UTF-8'?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:gCal='http://sc hemas.google.com/gCal/2005' xmlns:gd='http://schemas.google.com/g/2005'><id>http ://www.google.com/calendar/feeds/24vj3m5pl125bh2ijbbneh953s%40group.calendar.goo gle.com/public/basic</id><updated>2007-06-11T15:11:40.000Z</updated><category sc heme='http://schemas.google.com/g/2005#kind' term='http://schemas.google.com/g/2 005#event'></category><title type='text'>MS150 Training Schedule</title><subtitl e type='text'>This calendar is public</subtitle><link rel='http://schemas.google .com/g/2005#feed' type='application/atom+xml' href='http://www.google.com/calend ar/feeds/24vj3m5pl125bh2ijbbneh953s%40group.calendar.google.com/public/basic'></ link><link rel='self' type='application/atom+xml' href='http://www.google.com/ca lendar/feeds/24vj3m5pl125bh2ijbbneh953s%40group.calendar.google.com/public/basic ?max-results=25'></link><author><name>Lane LiaBraaten</name><email>api.lliabraa@ gmail.com</email></author><generator version='1.0' uri='http://www.google.com/ca lendar'>Google Calendar</generator><openSearch:totalRe 22:22:31.151501 IP po-in-f99.google.com.80 > dellalicious.mshome.net.4520: . 1431:2861(1430) ack 360 win 6432 E...1!..2.I.H..c...e.P.......=.:P.. 2...sults>3</openSearch:totalResults><openSe arch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch :itemsPerPage><gd:where valueString=''></gd:where><gCal:timezone value='America/ Los_Angeles'></gCal:timezone><entry><id>http://www.google.com/calendar/feeds/24v j3m5pl125bh2ijbbneh953s%40group.calendar.google.com/public/basic/dgt40022cui2k3j 740hnj46744</id><published>2007-06-11T15:11:05.000Z</published><updated>2007-06- 11T15:11:05.000Z</updated><category scheme='http://schemas.google.com/g/2005#kin d' term='http://schemas.google.com/g/2005#event'></category><title type='text'>M S150 Training ride</title><summary type='html'>When: Sat Jun 9, 2007 7am to 10am &nbsp; PDT<br> <br>Event Status: confirmed</summary><conte nt type='text'>When: Sat Jun 9, 2007 7am to 10am&nbsp; PDT<br> <b r>Event Status: confirmed</content><link rel='alternate' type='text/html' href='http://www.google.com/calendar/event?eid=ZGd0NDAwMjJjdWkyazNqNzQwaG5qNDY3 NDQgMjR2ajNtNXBsMTI1YmgyaWpiYm5laDk1M3NAZw' title='alternate'></link><link rel=' self' type='application/atom+xml' href='http://www.google.com/calendar/feeds/24v j3m5pl125bh2ijbbneh953s%40group.calendar.google.com/public/basic/dgt40022cui2k3j 740hnj46744'></link><author><name>MS150 Training Schedule</name></author><gCal:s endEventNotifications value='false'></gCal:sendEventNotifications></entry><entry ><id>http://www.google.com/cal 22:22:31.153097 IP po-in-f99.google.com.80 > dellalicious.mshome.net.4520: . 2861:4291(1430) ack 360 win 6432 E...1#..2.I.H..c...e.P.......=.:P.. ....endar/feeds/24vj3m5pl125bh2ijbbneh953s%4 0group.calendar.google.com/public/basic/51d8kh4s3bplqnbf1lp6p0kjp8</id><publishe d>2007-06-11T15:08:23.000Z</published><updated>2007-06-11T15:10:39.000Z</updated ><category scheme='http://schemas.google.com/g/2005#kind' term='http://schemas.g oogle.com/g/2005#event'></category><title type='text'>Meeting with Nicole</title ><summary type='html'>When: Mon Jun 4, 2007 10am to 11am&nbsp; PDT<br> <br>Where: Conference Room B <br>Event Status: confirmed</summ ary><content type='text'>When: Mon Jun 4, 2007 10am to 11am&nbsp; PDT<br& gt; <br>Where: Conference Room B <br>Event Status: confirmed <br>Event Description: Discuss building cycling team for MS150</content><l ink rel='alternate' type='text/html' href='http://www.google.com/calendar/event? eid=NTFkOGtoNHMzYnBscW5iZjFscDZwMGtqcDggMjR2ajNtNXBsMTI1YmgyaWpiYm5laDk1M3NAZw' title='alternate'></link><link rel='self' type='application/atom+xml' href='http ://www.google.com/calendar/feeds/24vj3m5pl125bh2ijbbneh953s%40group.calendar.goo gle.com/public/basic/51d8kh4s3bplqnbf1lp6p0kjp8'></link><author><name>MS150 Trai ning Schedule</name></author><gCal:sendEventNotifications value='false'></gCal:s endEventNotifications></entry><entry><id>http://www.google.com/calendar/feeds/24 vj3m5pl125bh2ijbbneh953s%40group.calendar.google.com/public/basic/va41amq3r08dhh kpm3lc1abs2o</id><published>20 22:22:31.190244 IP po-in-f99.google.com.80 > dellalicious.mshome.net.4520: P 4291:5346(1055) ack 360 win 6432 E..G1$..2.K.H..c...e.P.....<.=.:P.. ....07-06-11T15:10:08.000Z</published><updat ed>2007-06-11T15:10:08.000Z</updated><category scheme='http://schemas.google.com /g/2005#kind' term='http://schemas.google.com/g/2005#event'></category><title ty pe='text'>MS150 Information session</title><summary type='html'>When: Wed Jun 6, 2007 4pm to Wed Jun 6, 2007 5pm&nbsp; PDT<br> <br>Event Statu s: confirmed</summary><content type='text'>When: Wed Jun 6, 2007 4pm to Wed Jun 6, 2007 5pm&nbsp; PDT<br> <br>Event Status: confirmed< /content><link rel='alternate' type='text/html' href='http://www.google.com/cale ndar/event?eid=dmE0MWFtcTNyMDhkaGhrcG0zbGMxYWJzMm8gMjR2ajNtNXBsMTI1YmgyaWpiYm5la Dk1M3NAZw' title='alternate'></link><link rel='self' type='application/atom+xml' href='http://www.google.com/calendar/feeds/24vj3m5pl125bh2ijbbneh953s%40group.c alendar.google.com/public/basic/va41amq3r08dhhkpm3lc1abs2o'></link><author><name >MS150 Training Schedule</name></author><gCal:sendEventNotifications value='fals e'></gCal:sendEventNotifications></entry></feed>
この出力には、すべての HTTP ヘッダーとコンテンツ、複数の暗号化 TCP フラグが含まれます。すべてのデータはここにありますが、読み取りと理解が困難な場合があります。このデータを見やすくするためのグラフィカル ツールがいくつかあります。
WireShark(旧 Ethereal)
WireShark は、ネットワーク トラフィックを複数の方法で表示します。
WireShark は tcpp がビルドされたライブラリである libpcap を使用してビルドされたグラフィカル ツールで、Linux、Mac OS X、Windows で利用できます。WireShark の GUI は、パケット キャプチャ データを解釈して操作するためのいくつかの新しい方法を可能にします。たとえば、ネットワーク インターフェースからキャプチャされたパケットは、使用しているプロトコルに基づいてさまざまな色で表示されます。タイムスタンプ、送信元、宛先、プロトコルでトラフィックを並べ替えることもできます。
パケットのリストで行を選択すると、Wireshark では、人が読めるツリーのパケット ヘッダーに IP や TCP などのプロトコル固有の情報を表示します。また、データは画面下部の 16 進数または ASCII で表示されます。
WireShark は視覚的な性質のためネットワーク トラフィックを理解しやすいですが、ほとんどの場合はネットワーク トラフィックをフィルタする必要があります。WireShark は、数百のプロトコルのサポートなど、堅牢なフィルタリング機能を備えています。
ヒント: 使用可能なプロトコルを表示し、複雑なフィルタを作成するには、WireShark ウィンドウの上部にある ボタンをクリックします。
上記の tcpdump の例で使用したフィルタを再作成するには、WireShark フィルタ ボックスに次の式を挿入します。
ip.addr==<your IP address> && tcp.port==80
または、WireShark の HTTP の知識を活用します。
ip.addr==<your IP address> && http
この設定により、Google カレンダー サーバーとのやり取りに関係するパケットのみが取得されます。各パケットをクリックすると、内容を確認して取引を分割できます。
ヒント: パケットのいずれかを右クリックして [TCP ストリームをフォロー] を選択すると、単一のウィンドウでリクエストとレスポンスを順番に表示できます。
WireShark には、キャプチャ情報を保存するいくつかの方法があります。1 つ、複数、またはすべてのパケットを保存できます。TCP ストリームを表示している場合は、[名前を付けて保存] ボタンをクリックするだけで、関連するパケットのみを保存することができます。tcpdump キャプチャから出力をインポートし、WireShark で表示することもできます。
問題: SSL と暗号化
パケット キャプチャ ツールの欠点として、SSL 接続で暗号化されたデータを表示できないということがあります。上記の例では、公開フィードにアクセスしているため、SSL は必要ありません。ただし、サンプルがプライベート フィードにアクセスした場合、クライアントは SSL 接続を必要とする Google 認証サービスで認証する必要があります。
以下のスニペットは前の例と似ていますが、ここでは CalendarService
がユーザーのカレンダーのメタフィード(認証が必要な非公開フィード)をリクエストしています。認証するには、setUserCredentials
メソッドを呼び出します。このメソッドは、Service への HTTPS リクエストをトリガーし、レスポンスから認証トークンを取得します。その後、CalendarService
オブジェクトで後続のすべてのリクエストに認証トークンが追加されます。
CalendarService myService = new CalendarService("exampleCo-fiddlerSslExample-1"); myService.setUserCredentials(username, userPassword); final String METAFEED_URL = "http://www.google.com/calendar/feeds/default"; URL feedUrl = new URL(METAFEED_URL); CalendarFeed resultFeed = myService.getFeed(feedUrl, CalendarFeed.class); System.out.println("Your calendars:"); for (int i = 0; i < resultFeed.getEntries().size(); i++) { CalendarEntry entry = resultFeed.getEntries().get(i); System.out.println("\t" + entry.getTitle().getPlainText()); } System.out.println();
限定公開の Google Data API フィードの認証とアクセスに必要なネットワーク トラフィックについて考えてみましょう。
- OpenSSL サービスにユーザー認証情報を送信する
- メッセージ本文に次のパラメータを指定して HTTP
POST
を https://www.google.com/accounts/gclid に送信します。- メール - ユーザーのメールアドレス。
- Passwd - ユーザーのパスワード。
- source - クライアント アプリケーションを指定します。companyName-applicationName-versionID の形式で指定してください。この例では、「ExampleCo-FiddlerSSLExample-1」などの名前を使用します。
- service - Google カレンダーのサービス名は「cl」です。
- メッセージ本文に次のパラメータを指定して HTTP
- 認証トークンを受け取る
- 認証リクエストが失敗すると、HTTP 403 Forbidden ステータス コードが返されます。
- 成功すると、サービスからのレスポンスは HTTP 200 OK のステータス コードと、3 つの長い英数字のコード(
SID
、LSID
、Auth
)になります。Auth
値は認証トークンです。
- 限定公開カレンダーのメタフィードをリクエストする
- 次のヘッダーを含む HTTP
GET
を http://www.google.com/calendar/feeds/default に送信します。
Authorization: GoogleLogin auth=<yourAuthToken>
- 次のヘッダーを含む HTTP
次のスニペットを実行し、WireShark でネットワーク トラフィックを確認してください(「http || ssl」をフィルタとして使用)。トランザクションに含まれる SSL パケットと TLS パケットが表示されますが、OpenSSL のリクエストとレスポンスのパケットは「アプリケーション データ」パケットで暗号化されています。それでは、暗号化された情報を実際に確認できるツールについて見ていきましょう。
Fiddler
Fiddler もグラフィカルなパケット スニッフィング ツールですが、動作はこれまで説明してきたツールとは大きく異なります。Fiddler は、あなたのアプリケーションと、あなたがやり取りしているリモート サービスの間のプロキシとして機能し、実質的に中間者となります。Fiddler は、アプリケーションとリモート ウェブサービスの両方に対して SSL 接続を確立し、一方のエンドポイントからのトラフィックを復号し、平文をキャプチャして、送信前にトラフィックを再暗号化します。Fiddler は、Mac と Linux をご利用のすべてのお客様のみご利用いただけます。
注: SSL サポートには、Fiddler バージョン 2 と .NET Framework バージョン 2.0 が必要です。
Fiddler でのネットワーク トラフィックの表示は、主に [Session Inspector] タブで行います。Google Data API に関する問題をデバッグする際に役立つサブタブは次のとおりです。
- ヘッダー - HTTP ヘッダーを折りたたみ可能なツリー形式で表示します。
- Auth - Authentication のヘッダーが表示されます。
- Raw - ネットワーク パケットの内容を ASCII テキストで表示します
ヒント: Fiddler ウィンドウの左下にある アイコンをクリックすると、キャプチャのオンとオフを切り替えることができます。
Fiddler は、.NET Framework を使用して、Fiddler をプロキシとして使用するネットワーク接続を構成する。つまり、Internet Explorer または .NET コードを使って行った接続は、デフォルトで Fiddler に表示されます。ただし、Java では HTTP プロキシの設定方法が異なるため、上記の Java サンプルからのトラフィックは表示されません。
Java では、システム プロパティを使用して HTTP プロキシを設定できます。Fiddler は、ポート 8888 で実行されているため、次の行を追加することで、Java コードで HTTP と HTTPS のプロキシとして Fiddler を使用できます。
System.setProperty("http.proxyHost", "localhost"); System.setProperty("http.proxyPort", "8888"); System.setProperty("https.proxyHost", "localhost"); System.setProperty("https.proxyPort", "8888");
これらの行を使用してサンプルを実行すると、Java セキュリティ パッケージから厄介なスタック トレースが発生します。
[java] Caused by: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
Fiddler は、SSL トラフィックを復号して表示できます。
このエラーは、SSL 接続でサーバーから返された証明書を確認できない場合に発生します。この場合、不正な証明書は Fiddler からのもので、中間者として機能します。Fiddler は、その場で証明書を生成します。Fiddler は信頼できる発行者ではないため、この証明書により Java で SSL 接続の設定が失敗します。
注: Fiddler の実行中は、Internet Explorer との SSL 接続により、「疑わしい証明書」であっても続行するかどうかを確認する「セキュリティ通知」がトリガーされます。[証明書を表示] をクリックすると、Fiddler が生成した証明書が表示されます。
セキュリティの例外を回避するにはすべての証明書を信頼するには、基本的に Java のセキュリティ フレームワークを再構成する必要があります。幸いにも、ここで一から作り直さなくても、Francis Labrie のソリューションが紹介されているので、上記の例に SSLUtilities.trustAllHttpsCertificates()
メソッドを追加することができます。
Fiddler をプロキシとして使用するように Java を構成し、デフォルトの証明書検証を無効にしたら、サンプルを実行して、ネットワーク経由で送信されるすべてのトラフィックを平文で確認します。パスワードを盗まない
この認証トランザクションは SSL トラフィックのほんの一例です。一部のウェブ アプリケーションは SSL 接続のみを使用するため、HTTP トラフィックのデバッグは、データを復号する方法がないということは問題ではありません。
まとめ
Linux、Mac OS X、Windows で利用できる tcpdump は、探しているものをすぐに把握したいときに最適なツールです。ただし、ネットワーク トラフィックをわかりやすい形式で表示しているグラフィカル ツールもありますが、tcpdump では、ここで説明したオプションよりも多くのオプションとフィルタリング機能を使用しています。tcpdump の機能の詳細については、「man tcpdump」と入力するか、tcpdump のマニュアル ページをご覧ください。
WireShark は、Linux、Mac OS X、Windows でもご利用いただけます。WireShark は、数百のプロトコルをサポートする組み込みサポートを備えているため、HTTP デバッグだけでなく、多くのアプリケーションに有用なツールとなります。この導入は、WireShark の多くの機能をほんの少ししか取り上げていません。詳細については、「man wireshark」と入力するか、WireShark のウェブサイトをご覧ください。
Fiddler にも優れた機能が数多くありますが、特筆すべきは SSL トラフィックを復号する能力です。詳しくは、Fiddler2 のウェブサイトをご覧ください。
パケット スニッフィング アプリケーションは、ツールに適していて、誰でも無料であることをお気づきになるでしょう。次回 Google API を操作したときに、おかしなことに気づいたら、いずれかのネットワーク アナライザを取り出して、ネットワークの状態を詳しく調べます。問題が見つからない場合は、ディスカッション グループにいつでも質問を投稿できます。関連するネットワーク メッセージを含めると、特定の問題を正しく把握して診断するのに役立ちます。
健闘を祈ります!