日記予定
まず、Webアプリ以前に、一般に、ボタンを押すなどして画面を次々に遷移していくアプリケーション(スタンドアロンアプリケーション(ネットワークなしに単体で動作するもの)を含めて)を作成するときは、設計段階から(もしくは事後に)図1のような画面遷移図を描いて検討(ないし確認)するだろう。
水色の四角は画面を表し、白抜き実線枠の四角はボタンを表す。
これを、Webアプリという実装手法を選択する場合に特化すると、図2のような遷移図が描ける。
実線矢印はブラウザが送信するHTTPのrequest(ヘッダおよび、POSTの場合はボディを含む)を表し、黄色の丸がサーバ側での1アクセスの処理を表し、点線がその処理結果を返すHTTPのresponse(ヘッダおよび、HTML)を表す。responseの上の文はHTMLの内容を説明するものである。黄色の丸の中の文は処理内容の説明であり、ここから複数のresponse矢印が出ている場合、処理の結果によって遷移先の画面が異なる場合であることを表し、破線の白抜き四角がその分岐の条件を概説している。
この図で例に用いているのは、ECサイトやblogサービスなどに見られる典型的な「登録個人情報変更」の機能である。「メインメニュー」画面の「登録情報変更」のリンクをクリックすると、「登録情報DB読み出し」の処理が実行され、その結果(現在の登録情報)が以下のようなHTMLとして構成されて出力され、
<form action="......" method="POST"> 氏名 <input type="text" name="name" value="高木"> 住所 <input type="text" name="addr" value="東京都"> 電話 <input type="text" name="tel" value="03-XXXX"> <input type="submit" value="確認">
「登録情報編集」の画面が以下のように表示される。
「確認」ボタンを押すと、「様式検査」処理(電話番号が電話番号の形式をしているかどうかなどの検査)が行われ、正常であれば「プレビュー」画面に進む。プレビュー画面は次のような画面となるだろう。
これでよろしいですか?
氏名: 高木
住所: 東京都
電話: 03-XXXX
さてここで、この次の画面に進ませる(「保存」を押したときの処理を実現する)ためにどのような方法を用いるか、次の2種類の実装方法がある。
一つ目は、「保存」ボタンを押したときのアクションをPOSTメソッドとし、そのパラメタにこれらの情報を渡すようにする方法で、それらパラメタが画面上に見えないようにするために <input type="hidden" ...> を用いる。つまり、「プレビュー」画面のHTMLは次のようになる。
<p>これでよろしいですか?</p> 氏名: 高木<br> 住所: 東京都<br> 電話: 03-XXXX<br> <form action="......" action="POST"> <input type="hidden" name="name" value="高木"> <input type="hidden" name="addr" value="東京都"> <input type="hidden" name="tel" value="03-XXXX"> <input type="submit" name="back" value="戻る"> <input type="submit" name="save" value="保存"> </form>
これを画面遷移図に書き込んだのが図3である。
青い矢印はPOSTメソッドによるHTTP requestであることを表す。
二番目の方法は、図4に示すものである。
図中の六角形はサーバ側のオブジェクトを表す。「登録情報編集」画面で入力されたデータが「確認」ボタンでサーバに送信されたとき、サーバは「様式検査」の処理の前に、入力データをサーバ側オブジェクトに記憶し、その後の処理ではこのオブジェクトの値を参照して実行するようにする。プレビュー画面の出力や、プレビュー画面で「保存」ボタンを押したときの「DB書込」処理でも、このオブジェクトから値を参照して処理を実行する。
この方式を採用した場合、「プレビュー」画面に hiddenパラメタは不要となる。その結果として、「プレビュー」画面からの遷移のHTTPアクセスはPOSTメソッドでなくてもよいことになる。
さて、この「サーバ側オブジェクト」はどのように実現すればよいだろうか。
安易なその場限りの方法でよければ、「セッションオブジェクト」(ログインユーザごとに1つ用意された記憶空間。「セッション変数」と呼ぶミドルウェアもある)に「name」「addr」「tel」という名前の変数で記憶しておくという発想が出てくるだろう。
しかし、本物のプログラマ*1であれば、ここで、それがそんなに単純な話でないことにすぐに気づくはずだ。メインメニューから使える他の機能があるなら、変数名が衝突しないようにしなければならないし、それよりなによりも、同じ機能を同時に複数使う場合にどう管理すればよいのか――といったことに思いをめぐらすはずだ。
こうした考え方は、オブジェクト指向プログラミングがGUIシステムの開発に向いているとして発展してきた経緯に符合する。 オブジェクト指向プログラミングを知らないプログラマがGUIシステムを作ろうとすると、変数管理を自前でやるという汚いコーディングに陥ることがある。つまり、同じ画面が複数のウィンドウとして開かれたときに、そこで使う変数名が衝突することを避けようとして、変数を配列にして、ウィンドウ番号をインデックスにしてアクセスするという発想だ。オブジェクト指向プログラミングを知っていればそうした汚い作り方は自然に回避される。ウィンドウを開く時点で、ウィンドウオブジェクトを「new」することにより、そのウィンドウ専用の記憶空間が用意される。変数はそのオブジェクトにローカルであるので、他のオブジェクトでどうなっているかを気にする必要がない。
今日のスタンドアロンアプリケーションのGUIシステム開発では、GUIライブラリがそうしたオブジェクト指向スタイルで設計され、提供されているので、開発者は自然とそうした開発手法に従うことになる。
ところが、GUIシステムをWebアプリとして作るとなるとどうだろうか。
スタンドアロンのGUIアプリと同様に、Webサーバ側を、オブジェクトを「new」しながら動作するように作ることはできる。あとは、それらのオブジェクトをどうやってクライアント側のWebブラウザと結びつけるかだ。
ひとつの自然な方法は、新しく開くウィンドウごとにシリアル番号を振り、その番号をブラウザに渡し、アクセスごとに返させるようにすることである(図5)。
図5は、2つの「追加」処理が同時に進行している様子を表したものである。「追加」のリンクが辿られると、ウィンドウオブジェクトを生成し、ウィンドウを識別するシリアル番号を得る。生成したオブジェクトをそのシリアル番号で検索できるように、オブジェクトテーブルに登録する(セッションオブジェクトから辿られるテーブルに)。処理を進める各画面のHTMLには、
<input type="hidden" name="winid" value="2">
のようにしてウィンドウのシリアル番号「winid」を埋め込んでおき、POST(またはGET)アクションの各処理では、HTTP request中のwinidの値から(セッションオブジェクト経由で)オブジェクトを検索し、その参照を得る。「様式検査」の処理でそのオブジェクトのフィールドに値を書き込み、「DB書込」の処理でその値を読み出してDB更新の処理を実行する。
こうした作り方は、オブジェクト指向なGUIシステム設計の流れからすれば自然であるところ(いくつかのWebアプリフレームワークではこうした実装方法を提供しているであろうが)、しかしながら、実際にWebアプリでこうした実装方法をとっている例は少な目かもしれない。
にもかかわらず、複数ウィンドウを用いた同時編集を許すWebアプリというのが、珍しいわけではないだろう。上のような一般化されたオブジェクト指向Webアプリフレームワークを用いずに、複数同時編集を実現するにはどうするのだろうか。たいていの場合、編集開始の最初の段階で、機能に固有の何らかの識別コードを確定させて使う方法が使われているのではないか。「何らかの識別コード」とは、システムでユニークな文書番号だったり、日記システムであれば日付がそれに該当する(図6)。
日記システムであれば、「追加」機能の最初の段階で編集する日付を確定させ、「date」パラメタにその値を入れて次画面へと渡す。セッションオブジェクトで記憶しておくべきデータは、日記の日付から検索して読み書きするように作る。
この実装方法では、同じ日のエントリを同時に編集することはできなくなるが、この場合はユーザにもその挙動は直感できることであるため、この仕様で満足とされる。
たいていのWebアプリはこの方法で作れてしまうので(あるいは図3の方法で作ることが多いため)、このようなアドホックな実装方法のことしか考えたことのないWebプログラマも少なくないかもしれない。
クロスサイトリクエストフォージェリ(CSRF)攻撃による被害は、Webアプリが設計上想定していない画面遷移を辿られることによって起きる。であれば、Webアプリが想定している画面遷移しか許さないようにすることによって(も)解決できるということになる。
画面遷移を完全に制御するとなったとき、本物のプログラマがまず思い浮かべるのは図5の実装であろう。ただし、想定外のユーザ操作によって画面遷移を外れることを防ぐためには、図5のようにウィンドウ識別番号としてシリアル番号でよかったところ、これが悪意ある第三者の攻撃を想定するとなると、この値は予測困難な値としなくてはならない。これは、「new」したときのwinidに十分な長さの乱数値を与えるようにすればよい。
CSRF対策に「ワンタイムトークン」を用いるという話が出ると、本物のプログラマ達は、まず図5の実装(でwinidを乱数にする)を頭に浮かべるのではなかろうか。
しかし実際には、図3ないし図6の実装方法ばかりが採用されているという現実がある。機能的にはそれで十分だからそうしていたのに、後になって図5の実装方法が「必須だ」と言われたら困惑するだろう。全体にわたって作り直すことになってしまう。
昨年7月3日の日記「クロスサイトリクエストフォージェリ(CSRF)対策がいまいち進まなかったのはなぜか」では、CSRF対策が進まなかった原因を複数挙げたが、その中で、
センスある開発技術者の立場からすれば、「あんな対策も必要、こんな対策も必要」と言われることは、プログラミング美学に反すると感じられることもある。
XSSやSQLなどのインジェクション系の脆弱性は、脆弱性であるという以前に、本来正しいコーディングをしていればそういう穴にはならないのだから、美学に反するものではない。バッファーオーバーフローもそうだ。センスある開発技術者にとっては「対策」不要というのが美学だ。
その点、CSRF対策が必要というのは、どうにも気持ち悪いものとなる。画面の遷移をすべてチェックするというのであればまだわかるが、一部の画面に姑息な手段で対策を仕掛けないといけないとなると、なんだか美しくないように感じられる。
と書いている。画面遷移を完全に制御するのは自然な実装であるが、その実装はオーバースペックであるし、後からそのように変更するのは大変すぎる。
本物のプログラマには「対策は簡単でない」と思われていることが対策を遅らせているのではないかと考えた。
それなのに、「ワンタイムトークン」方式を採用すべきと主張する人達は、「実装が簡単なんだからやればいいじゃないか」と言う。
hiddenとセッション(とCookie)に予測不可能な文字列を入れる
セッションIDをハッシュする手法に比べ、使用するのは無意味な文字列なので安全性が高い。
- 推奨: する
- 効果: 大
- 回避法: 特にない
- 実装: 簡易
- 副作用: ない
ワンタイムチケット(トークン)のコードなら4/27の時点でも、ちょっと探せばいくらでも見つかったはずです。
>ワンタイムトークンを正しく使うという解決策が書かれているのだけれど、
>正直これはちょっと面倒である。
本当に面倒ですか?実際にコードを書いてみると数行しか違わないんじゃないで
しょうか。僕は本業がウェブアプリ開発なのですが、例えば「日記を書き込む」
みたいな、ウェブアプリケーション本来の機能の複雑さ・面倒くささに比べれば
ワンタイムトークン方式を組み込むことくらい何でもないのですが。
> そうですね、このあたりは感覚の違いだと思います。
> 本来の機能と比べてしまうとちょっとアレですが、
> 僕はやっぱりワンタイムにする面倒さを考えると、
ワンタイムにする場合は処理2でセッションオブジェクトからトークンを削除す
る必要があるので、例えばJavaなんかだと
session.removeAttribute( "token" );
を加えないといけませんね。
…1行多いですね。これ面倒ですか?(笑
なぜこんなに簡単だ簡単だと言えるのだろう? と不思議に思えるところ、要するに、彼らが主張する実装は、図7のような方式ということである。
グローバル変数1個に「トークン」を入れる方法なので、これでは同時編集ができなくなる。
実際のコード
// 確認画面 session_start(); (認証など略) $uniq_id = md5(uniqid(rand(),1)); // 推測不可能な文字列を生成 $_SESSION['uniq_id'] = $uniq_id; // セッションに保存 setcookie('uniq_id', $uniq_id); // Cookieにも保存 // hiddenにも入れておく print "<input type=hidden name=uniq_id value='{$uniq_id}'/>";
> 2画面以上開かれてしまった場合の手当てとか、
> もっと複雑な気がなんとなくしてました。
失礼しました。私が間違ってました。
ご指摘どおり2画面以上の場合を考慮するため、ワンタイムトークン方式は実際
にはトークンの名前もそれぞれの機能ごとに別のものを利用し、管理するのがベ
ターです。
つまり「日記を書く」のトークンはtoken1、「日記を消す」のトークンはtoken2
にする、などですね。
そうなると処理1及び処理2で「トークンの名前を求める」という処理が必要にな
るので、さらに1行か2行くらいずつ増えそうです。(面倒かどうかはアレですが
笑)
変数を機能ごとに別々にしても、同じ機能の同時編集は依然としてできない。(インスタンス変数を使うべきところにクラス変数を使うような話である。)
自分だけが使うWebアプリに対策したときに、同時編集不能になろうが、それは自由だ。ある特定のWebアプリで同時編集が不要であれば、その対策方法を採用することもできるだろう。
だが、Webアプリ一般における対策方法を説くときには、アプリの基本設計に制限をもたらすようなものでは駄目だ。
図5の実装方法を推奨できれば話は早いが、先に述べたように、残念ながらこのオブジェクト指向スタイルのWebアプリ実装はあまり普及していない。図3の実装方法を用いている場合でも、図6の様々な実装方法の場合でも、どんな場合にも使える対策方法を示したいところだ。
編集操作のインスタンスごとにトークン用の記憶域を確保しようとすると、図6の実装方式の場合、「識別コード」の存在にまで踏み込んで説明しないと、記憶域の確保方法を説明できない。ひとつの例について書くことはできてもそれはすべてではない。
ここで、あえて図7の方式をベースに改善することを考えてみる。たとえば、次の図8のようにすれば解決できるだろう。
トークン格納用変数を集合型オブジェクトとし、任意個の発行されたトークンを格納していく。「DB書込」処理の冒頭では、hiddenパラメタで渡されたトークンがこの集合の中に含まれているかどうかを調べて、正規のリクエストであるかを確認する。
図5の、想定外のユーザ操作によって画面遷移を外れることを防ぐ場合には、IDが一致していないといけなかったが、第三者からの攻撃だけを防ぎたいときには、IDが既存のものであるかを調べればよい。同じセッションに格納されたトークンはすべて正規の画面遷移によるものだからである。
このようにして考えると、トークンはログインセッションで共通の1個でよいことがわかる。画面ごとに別の値にする必要もないし、操作インスタンスごとに変える必要もない。
「ワンタイムトークン」という発想は本来、画面遷移を完全にコントロールすることでCSRFを解決しようとするものだろう。だが、CSRFを解決するだけの目的には、第三者からの攻撃リンクによる画面遷移なのか、正規の画面遷移なのかさえ区別できればよいのである。
もし、画面遷移の完全コントロールを必要としていて既に図5の実装をしているならば、CSRF対策はウィンドウIDを予測困難な値にすればよい。だが、画面遷移の完全なコントロールは一般的には不必要であり、CSRF対策のためだけに図5の実装を推奨するのは開発者に対して酷であろう。
そのため、昨年4月27日の日記「クロスサイトリクエストフォージェリ(CSRF)の正しい対策方法」では、
不適切な解説の例
- ワンタイムトークンを使わなくてはならない。
と書いたのだった。
乱数を生成するということはそう容易いことではない。自動的にセキュアであると謳うCSRF対策をするならば、チェック用の値は暗号学的に安全な擬似乱数生成系で生成しなければならない。
自分の使っている環境でそのような乱数生成系がすぐに使える状態になっているからそれを使うというのは自由だけども、他人に対策を説く場面では、あらゆる環境を想定して、そのような乱数生成系の使用を推奨しなくてはならない。
セッションIDを使うという方式は、そうした乱数生成の問題(プログラマが杜撰な乱数生成方式を採用してしまう事態)を避けることができる。なぜなら、セッションIDは暗号学的に安全な擬似乱数生成系で生成されているはずだからである。(そうでなけれは、そのセッション管理機構自体に脆弱性があるということになり、それがまず修正されるべきとなる。)
tDiaryのCSRF対策でも、乱数を用いるのを避けている。その理由は、tDiaryは一般的なCGI環境とRubyがあれば動作することを保証しているため、セッション管理機構の導入が必須になるような対策方法は採りたくなかったこと、そして、Rubyの乱数生成系(少なくとも当時の)は暗号学的に安全なものではなかった(どのOSにおいてもという意味で)からである。
そこで、tDiary 2.1.2のCSRF対策では、Referer:チェックによる対策をデフォルトとし、どうしても Referer:を空にしても使えるようにしたいユーザは、ユーザの責任においてユーザ固定キーを設定して使うことにしたものである。ユーザ固定キーは、暗号学的に安全な擬似乱数よりも弱いものであるが、ユーザの責任で設定するものであり、システムが自動的にセキュアであると謳うものではない。
どうも素人さんには「hiddenは簡単に読める」という思い込みがあるらしい。
(略)何も、戻る時に追加の情報をポストする必要がない、という前提ではあるが、Cookieでセッション管理していれば大抵、そういう状況だと思う。(そもそもセッション管理をinput[type="hidden"]等で行うべきではない。改竄が容易というのもあるし、もしCSS3のcontentやappearanceが実装されると、簡単にブラウザ上にこの要素をinput[type="text"]のように表示してデータを変更して送信し直せる可能性が高いからだ。Cookieなら改竄できないかというとそういう訳ではないが、CSS3のこれらのプロパティはWebアプリケーションにとっては、驚異的である。また、(略)
「改竄」というのは、ブラウザのユーザがhiddenパラメタを弄ることを指しているのだと思われるが、このような理由で「セッション管理をhiddenで行うべきでない」とするのは、二重の意味で誤りである。
第一に、ブラウザが送信する値をユーザが自由に変えられるのは当然であり(「改竄」などという表現を用いること自体が不適切なのだが)、どんなふうに変えられてもセッション管理が安全であるようにしなくてはならない。そのために、セッションIDには、予測困難な十部に長い暗号学的に安全な擬似乱数を用いることが必須になっている。(「容易に改竄されるので危険」などと思う人は、ユーザ名をセッション管理に用いていたりするのだろうか?*2)
第二に、hiddenの値を変更して送信する困難さと、cookieの値を変更して送信する困難さは同一である。(HTTPのヘッダにあるか、ボディにあるかの違いでしかない。)
こうした思い込みは少なくないようで、「HTMLソースで見える」という経験がそうした感覚を生じさせるのだろう。だが、cookieを読むのだって、アドレスバーに「javascript:document.cookie」と打ち込むだけでできる。
これも、読まれる可能性はcookieと同等である。
通常、読まれるのが困る場合はSSLで防止する。
CSRFチェック用に用いる秘密情報の候補としては、
などが考えられるところ、「クロスサイトリクエストフォージェリ(CSRF)の正しい対策方法」でセッションIDをそのまま使う方法を挙げたことに対して、いくつか批判があった。検討に値するのは、サーバ側やブラウザの脆弱性によって漏洩するケースである。
まず、漏洩の可能性のパターンで脆弱性を分類すると次のようになる。
このうちhiddenパラメタが漏れるのは、1. および 3. と 4.である。
1.の脆弱性があるとき、hiddenパラメタが漏れるときはcookieも漏れるのだから、hiddenのリスクだけを個別に検討する理由にならない。
次に、3.の脆弱性だけがあるとき、hiddenに(cookieと同じ値の)セッションIDを入れている場合、どのようなリスクがあるか。ただし、RefererチェックによるCSRF対策をしていない(hiddenパラメタによるCSRF対策をしている)とする。
この場合、脆弱性を突かれてhiddenの値が漏れることが、漏れないはずのcookieの値が漏れたのと同じ結果を招くことから、「hiddenにそのような値を入れるのは好ましくない」という議論が出てくる。
しかし、セッションIDが漏れることによって起きるリスクはセッションハイジャック攻撃であるところ、3.の脆弱性がある場合、いずれにせよ(hiddenにセッションIDを入れなかったとしても)セッションハイジャックと同等の脅威が生じる。その理由を以下に記す。
CSRF攻撃の脅威がセッションハイジャック攻撃と異なる第一の差は、セッションハイジャックでは個人情報などを閲覧できる場合があるのに対し、CSRFではHTTPのresponseを取得できないため、そうした直接的な情報漏洩の脅威はないという点である。
しかし、今ここでは「HTMLテキスト(hiddenパラメタを含む)が漏れる脆弱性」の存在を仮定しているので、攻撃者はCSRF攻撃のresponseを取得できる。つまり、直接に個人情報等を盗み出すことができる。
第二の差は、CSRF攻撃は通常、単発のアクセスしかできないという点である。つまり、Webアプリの構成によっては、1ページ目のresponseに含まれる値を使って2ページ目のrequestに含めないと目的を達成できない画面があり得るところ、通常のCSRFではそれら2つのページへ連続した攻撃をしかけることはできない。(この性質があるからこそ、hiddenパラメタに秘密情報を埋め込んでおくことがCSRF対策となり得る。)それに比べて、セッションハイジャック攻撃は、連続したページのアクセスを自由に操れるのであるから、単発アクセスしかできないCSRF攻撃より強力だということになる。
だが、今ここでは「HTMLテキスト(hiddenパラメタを含む)が漏れる脆弱性」の存在を仮定している。それは、1ページ目へのCSRF攻撃のresponseを攻撃者は読めるということを意味するのだから、その値を使った2ページ目のCSRF攻撃へと続けることができてしまう。
よって、セッションハイジャック攻撃を用いなくても、それと同じ脅威をもたらす攻撃は可能である。
脅威に差がないのであるならば、hiddenパラメタにcookieと同じセッションIDを入れておくことが新たな脅威を生むことはない。
これは新しい話ではない。たとえば、2000年に立て続けに発覚したJavaの「ネット接続機能が任意サイトへのアクセスを許す」脆弱性は、まさにその危険性のあるものだった。攻撃者の仕掛けたアプレットを表示したとき、この脆弱性を突かれると、そのJavaアプレットは、ユーザがログイン中のWebアプリにアクセスして、操作を完全に乗っ取ることができた。その原因は、攻撃者のプログラムが、攻撃先サイトのresponseを得られるところがミソであった。
同様に、JavaScriptの「同じホストのページのDOMにしかアクセスできない」という基本制約が破れる脆弱性がこれまでに多数発見されては修正されてきたが、この脆弱性がある場合も、同じ脅威があった。(もっともこのケースでは、cookieも盗まれるものであったが。)
残るは 4.のケースであるが、hiddenだけ漏れ、それ以外のHTMLテキストは漏れないという、そんな脆弱性がはたして生ずるのだろうか。つまり、以下の強調部分以外は漏れず、強調部分だけ漏れるという脆弱性である。
氏名: 高木<br> 住所: 東京都<br> 電話: 03-XXXX<br> <form action="......" method="POST"> 氏名 <input type="text" name="name" value="高木"><br> 住所 <input type="text" name="addr" value="東京都"><br> 電話 <input type="text" name="tel" value="03-XXXX"><br> <input type="hidden" name="sessionid" value="2aa5adb93356d85697cd0a114eb2100f"> <input type="submit" value="確認">
このような著しく特殊な脆弱性が将来生ずる可能性があると心配するならば、「セッションIDをそのままhiddenに入れないほうがよい」という理屈は成り立つ。
次に、「セッションIDをハッシュしておけばよい」「ハッシュしないよりした方がよいに決まってるし、コストもかからないのだからやっておけばいい」という主張があったが、はたして本当だろうか。
(続く)
*1 Webデザイナあがりの日曜掲示板プログラマでなく。
先日、Winnyに対する意見を求められる取材申し込みが立て続けにあった。「現状を把握しておかねば」と思い、書店にずらりと並べられていると噂に聞いていた、Winny利用教唆本を何冊か買ってみることにした。とくに次の一冊の謳い文句が興味をひいた。
こわーいウィルスから個人情報を完全に守る方法教えます!今日パソコンを買ってすぐ『ファイル共有』を初めたい人大集合!!!!!「ファイル共有」ヤバ〜イ、『お宝映像』もカンタンにダウンロードできる!!
ほほう。さっそく通販で購入して目を通してみた。
しかし、ざっと見た限りどこにも「個人情報を完全に守る方法」らしきものは見当たらない*1。 それよりも目に飛び込んできたのは、はじめの方に書かれているこのページだった。
なんと、「ファイアウォールを無効にしよう」と、その手順を詳細に指導している。
警告が「いちいち邪魔」ということで、警告が出ない設定にしようと指導している。
そしてなぜかこの話とは関係がないのに、Windows Updateしない設定のときの警告も出ないようにすることを指南している。
セキュリティ関係者にはぜひ買って読んでいただきたい代物だ。
国土交通省オンライン申請システムのサイトで、3月10日付で次の「重要なお知らせ」が掲載されていた。
平成18年3月26日より提供いたします「申請書作成アプリケーション及びアプレット環境設定プログラム」(以下、申請用ソフトウェア)においては、 Java 2 Runtime Environment(以下、JRE)の自動アップデート機能が動作することがあります。自動アップデートを行うと、本システムにて対応していないバージョンのJREがインストールされるため、あらかじめ以下に示す手順によって、自動アップデート機能を無効化するようお願いいたします。
自動アップデートを無効にするとどんな不利益が生ずるかは、一切、説明されていない。
3月22日の「最新の「申請書作成アプリケーション及びアプレット環境設定プログラム」の提供について」でも、システム利用準備手順の説明の最後で、
(2)-3 申請用ソフトのインストール後の注意
申請用ソフトをインストールした後、「関連情報:Javaの自動アップデート機能について(http://www.goa.mlit.go.jp/info/c_autoup.html)」に記載された手順でJREの自動アップデート機能を無効にしてください。
最新の「申請書作成アプリケーション及びアプレット環境設定プログラム」の提供について, 国土交通省総合政策局
と念を押している。
対策としては……やはりこれだろうか。
「ヤバ〜イルート証明書もじゃんじゃんダウンロードできる!!」
*1 あとでよく見ると、p.66にちょっとだけ(半ページだけ)書いてあった。内容は、
という説明のほか、HUBからケーブルを引き抜いた様子の写真が掲載されている。Winny独特のプライバシー侵害ウィルスにご用心! (略)
これを防ぐには、ウィルス対策ソフトを導入し、拡張子を表示してexeファイルを実行しないなどの予防が大切だ。万一感染したらネット接続は物理的に切断しよう。また何よりも個人情報を特定できるデータが入ったパソコンを使わないこと。会社のパソコンでWinnyなどもってのほかだ。
Winnyやりてぇー! 初心者のための「ファイル共有入門」, 英知出版, p.66
巡査長は「通達があってウィニーを削除しようとしたが、失敗した」と話しているという。
府警はこれまで、ウィニー搭載の有無の調査や、削除などを指示していたが、巡査長は搭載していることを報告しておらず、「先月から何度も削除しようとしたが消せなかった」と話している。
「何度も死のうと思ったが死ねなかった」みたいなもんか。
先月、朝日新聞社「論座」のインタビューを受けたものが記事となり、今月5日発売号に掲載されている。
ここで確認しておきたい論旨は次の点である。
情報流出はウィニーだけの問題ではないとの声もある。だが、ウィニーの登場で情報漏洩による被害は格段に深刻なものとなった。ウィニーから流出した情報は、ほとんど自動的に無制限に広がっていく。回収する手段は皆無と言っていい。その深刻さは、今年3月に注目された新種のコンピューターウイルス「山田オルタナティブ」と比較すれば一目瞭然だ。「山田」に感染すると、パソコン内のデータが全部、外部から直接閲覧できてしまう。しかし、感染に気づいてパソコンをインターネットから切断すれば1次流出はそこで止まり、積極的に2次流出させる第三者がいない限り、それ以上は拡散しない。他人の個人情報を2次流出させたがる人はそういないし、何の罪もない人の個人情報が暴かれた場合、「かわいそう」「ひどい」という感覚が、ネットユーザー間で生まれることがある。「人間的良心」が抑止力として働くのだ。
しかし、ウィニーは違う。何十万台ものパソコンを相互に接続し、常時ファイルを流通させる仕組みのため、1次流出が自動的に2次流出、3次流出、4次流出となる。(略)
いったん流出したファイルが止められないのは、その独特の使用方法にも原因がある。ウィニーユーザーは、必要なものだけ選んでダウンロードするのではなく、キーワード検索にヒットするファイルを片っ端からダウンロードして、後から必要なものだけ見るという使い方をする。そのため延々とウィニーを接続し続ける。(略) 暴露ウイルスはそれを利用し、「お宝」「美少女」などの人気キーワードや流出データと分かるタイトルをつけてファイルを「放流」する。誰かの検索にヒットすることで、いつまでもウィニー・ネットワーク上を流通するのだ。
ウィニーでは、他の人がやりとりするファイルまで勝手に自分のパソコンに入ってくることがある。第三者のパソコンを経由することで匿名性を高めているのだ。最近は女性のウィニーユーザーも少なくないと聞く。「私のウィニーはきれいなウィニー」と思っていても、実際には児童ポルノなどのデータが自分のウィニーの「キャッシュ」というフォルダ内に自動的に入ってくる。キャッシュ内のファイルは簡単には開けない。知らず知らず他人の違法行為の片棒を担がされ、流出情報の2次流出役を担わされるのである。
海上自衛隊の被害者は、ウイルス対策ソフトを常に更新しており、「自分は絶対にウイルスに感染しないと思っていた」と話したという。しかし、最新のウイルスは防ぎようがない。生命体のウイルスに対するワクチンと同様に、感染の拡大を一定レベルに抑えるための仕組みでしかないからだ。流行の初期段階で感染する少数の人を守るものではない。少数の個人だけを標的にした不正プログラムは、普通のウイルス対策ソフトでは防げない。
どんなに正しい知識を持って注意していても人はミスをする。たった一度のミスでも、ウィニー・ネットワークに秘密を流出させてしまったら終わりだ。たとえ自分がウィニーを使わないようにしていても、他人が動かしているウィニーに接続してファイルを放流する悪質なウイルスが今後出てくる危険性もある。勤務先のファイルは持ち帰らないように徹底しても、プライベート写真やメールが流出したら困る。万が一の被害を抑えるために、ウィニー・ネットワークはできるだけ縮小したほうがいい。ウィニーの使用を自粛するよう国民に呼びかけた安倍官房長官の発言(3月15日)には、そうした意味もあると思う。根絶は難しいにしても、少なくともウィニーユーザーは、自分のウィニーが何をしているかを知り、自分が何の片棒を担がされているかを自覚すべきだということだけは言える。
論座の記事には明確には書かれていないが、「ミス」とは、脆弱性を突かれてトロイを実行させられるケースも含む。もちろん、普段からWindows Updateして脆弱性を排除する作業を怠らないのは元々当然だが、脆弱性が見つかるのはWindowsだけではない。FlashプラグインやQuickTimeプラグイン、Becky!などのメールソフト、Java 2 実行環境(JRE) など、インストールしているソフトウェアのすべてにパッチをあてていなければ、事故は起こり得る。そのような管理を完遂できると自信を持って言える人がどれだけいるだろうか。加えて、未公表の脆弱性が発見者に悪用される「0-day 攻撃」のリスクも存在する。
Winnyを巡る現在の世論はどうなっているだろうか。不思議なことに現時点ではマスメディアも「Winnyが悪い」と決め付ける様子がない。人気ブロガーたちもこぞって「Winnyは悪くない」の大合唱だ。「悪いのはトロイを踏んだ人だ」と言ってみたり、「悪いのは情報を自宅に持ち出した人だ」とか、「悪いのはウイルスだ」とか、「包丁は人も殺せるが……」とか延々繰り返している。
トロイを踏む不用意さも問題だし、自宅に持ち出すことも問題だし、ウイルスも悪いが、Winnyネットワークも危険なのである。なぜその事実を直視することから逃れるのか。
たとえば、「japan.internet.com編集部」が客観性を失っている様子が次の記事に見てとれる。
ファイル共有ソフトを利用したことがない970人の認識はどうか。Winny ウィルスによる一連の事件について意見を聞くと、「(ファイル共有ソフトの)ユーザーに原因があると思う」がトップ(715人)。ソフトウェアは常に人間が動かすものだが、2位は「Winny そのものに原因があると思う」(490人)、そして3位は「企業の危機管理に原因があると思う」(451人)となった。
これはアンケートの結果を分析する記事なのに、「Winnyそのものに原因があると思う」との回答の前に、どういうわけか、「ソフトウェアは常に人間が動かすものだが」などという著者の主観による注釈(多かった回答に対する反論めいたもの)を付け加えてしまっている。
人気ブロガーが「Winnyは安全である」などというトンチキなことを言い始めた事例もある。
Winnyは安全である。メーラーやブラウザのように、外部から来たデータがオペレータの意図に反して、間違って実行されてしまうことがない。本来、ワームとは利用者に何の落ち度がなくても拡散するものであり、Winnyのようにセキュリティーホールが無いソフトではあり得ないものだ。「暴露ウィルス」は別の名前で呼ぶべきものだと思う。
Winnyが危険であるというのは全くの間違いで、外部から来た信頼できないデータをプログラムとして実行してしまうことが危険なのである。「暴露ウィルス」では、実行するのは馬鹿なユーザであって、Winny本体が勝手に外部から来たデータを実行することはない。
正直、この人がこんな馬鹿だとは思わなかった*1
この種の「識者」達にとっては、Winny礼賛に導く新しい「理論」をどれだけ唱えられるかが思想エリートとしてのテーゼなのだろう。
ここまで「識者」達の思考を狂わせてしまうものはいったい何か。それは、Winny作者が著作権法違反幇助の罪で逮捕、起訴されたことが発端であろう。
Winnyニートのみならず、関心がなかったあるいは中立的だった人たちさえ、作者が幇助犯として処罰されること自体に対する危機感から、「ということにしたい」症候群に陥ってしまった。あるいは、本当のことはわかっていても、意図して「大人の議論」をしている人もいるのだろう。そしてその「大人の議論」を真に受ける人が続出している。それどころか、それまで「Winnyはけしからん」としていた人たち(著作権ビジネス界の)さえも黙らせてしまった。Winnyを悪く言うだけでバッシングの対象となる恐れがあり、本当のことを言うのが難しくなっている。
しかし、ここで注意したいのは、「Winnyネットワーク自体が危険である」という事実を認めることが、「Winnyの製造は悪である」を意味するわけではないということだ。今では作者自身が、Winnyネットワーク自体が危険であることについて「Winnyの技術的的欠陥」と認めているのである。
金子氏は、一度放流したファイルは消せないという管理不可能性は「Winnyの技術的欠陥」と自ら認める。これを解決するアイデアはいろいろあるというが、Winny開発をめぐって公判中の今の彼は、それを試せる立場にはない。
金子氏は、「これを応用すれば、ファイル共有の方も管理可能になり、現在流通しているファイルを変更・削除するといったことも可能になるのではないかと考えていた」と語った。こうした管理機能は、掲示板については確実に実装する予定で、ファイル共有については当時は可能性について考えていただけだが、現在ではファイル共有についても管理は可能だと考えているという。
現在の作者のスタンスは、Winnyは技術的な試験のために作り配布したもので、その技術は発展途上のものだった(「そのため意図せず著作権侵害の蔓延を許してしまった」ということか?)ということになっている。だからその意味でもむしろ、現在のWinnyには欠陥があるということに「しなくてはならない」のだ。いまさら「Winnyはすばらしい」などと言い続けようとしている連中は、頭のネジが緩んでいることに気づくべきである。
ところで、AntinnyがWinnyネットワークを崩壊させるために作られたとみる人もいるようだが、それは違うだろう。
Anti-Winny(アンチウィニー)ことAntinny(アンティニー)とは、セキュリティベンダーも上手い名前を付けたものだ。「Winnyなんてやってるから、こんなことになるんだ」と言わんばかりに、次から次へと個人情報や重要情報が流出。
日本人ウイルス作者というものを考えてみると、従来、単純に増殖するだけのウイルスはあまり登場しなかった。これはおそらく、「ウイルスをばらまく愉快犯は子どもっぽい」と見なす文化的風潮からくるものだろう。発展途上国ではメールで広がるワームを作った程度でヒーロー扱いされることがあったようだが、(フロッピーディスクに感染する昔のウイルスならともかく)いまどきワームを作ることくらい何ら高度な技術を要しないのであるから、単に増殖するだけで喜んでいては馬鹿にされるだけだ。システムに甚大な被害をもたらすウイルスを撒く行為は厳しく断罪されることだろう。
だが、Antinny作者は、Winnyユーザだけをターゲットとすることで、そうした批判が自分に向かうのを避けることに成功している。Winnyを使っていること自体がろくなものではないと皆わかっているので、ウイルス被害者は同情されない。「悪いのはトロイを踏んだ人だ」と言っている人たちは、愚かなことに、ウイルス作者の思惑にまんまと乗せられてしまっている。
つまり、Antinnyは、Winnyネットワークを壊すことなく、人を罠に陥れる楽しみを続けられるように(手加減して)作られているのである。
したがって、次の展開によって、Winnyネットワークは崩壊への道をたどると考えられる。
メールソフトやWebブラウザの脆弱性を突く 0-day攻撃で、何の落ち度もない人達に感染するウイルスが登場する。そのウイルスは、被害者のコンピュータ内の秘密のファイルをWinnyネットワークに放流する。Winnyを使っていなくても、他人が使っているWinnyに接続して放流してしまう*2。
自称進歩的識者達がこの被害に遭う。このとき、もはや「誰それが悪い」と言えないだろう。自分の身に降りかかった痛みを知ってようやくWinnyネットワークの存在自体の危険に目を向けることとなる。「Winnyは安全だ」「悪いのはトロイを踏んだ馬鹿な人だ」などと言っていたトンチキが目を覚まし、「やっぱりWinnyを止めよう」ということになり、Winnyネットワークはようやく縮小の方向に向かう。
ネットエージェント社が以前から、Winnyプロトコルを自在に操るツールを作っていることを公表していた。
だが、これはビジネスとして展開されていたようで、これが一般の人の手に渡ることはなかった。ところが、先日、米eEye社がその種のツールを無償で公開する予定であることを明らかにした。
Winnyプロトコルを利用すれば、Winnyネットワーク内のノード情報(IPアドレス、ポート番号、クラスタリング情報など)を収集することができます。また、キー・パケットの収集により、特定ノードが持つファイル一覧や、特定ファイルを持つノード一覧なども取得できます。
このような仕組みを実現するWinnyネットワーク分析システムは既に実装が完了しており、今後、何らかの形で一般に無償配布できればと考えています。その他、漏洩してしまった情報の追跡や消去を支援するためのツール群も開発中です。こちらもあわせて無償配布したいと考えています。
このようなツールが誰でも利用できるようになると、次のような展開が予想される。
まず、個人情報を流出させた者もしくはその代理人、あるいは被害者(漏らされた情報の主体)の代理人が、これらのツールを使って、そのファイルを持っているWinnyノードのIPアドレスを洗い出し、プロバイダ責任法に基づいてISP経由で当該ノードのWinny利用者にファイルの削除を要請する。
そのとき、「そのファイルをダウンロードした記憶がないので、何かの間違いではないか」との疑問を持つWinnyユーザが続出し、そのことが世間で話題となる。
それにより、Winnyがcacheと呼んでいる仕組みのことがあちこちで解説されるようになり、「cacheにファイルを持っているだけで公衆送信可能化しているのだ」という事実が広く知れ渡り始める。実際、任意のWinnyノードの所有するファイルを閲覧できるツールを皆が使うようになれば、そのことは一目瞭然となるだろう。(Webを閲覧しているのと同じに見える。)
一方、Winnyネットワークからダウンロードだけするプログラムが作られて無償配布されると、流出ファイルのお宝探しをしていた報道関係者たちが、Winnyを使うのではなく、ダウンロード専用プログラムを使うようになる。
これによって、ようやくマスメディアが、中継するだけでも違法性がある可能性について語り始める。それまではそれを語ることができなかった。なぜなら、Winnyの実態を報道するためにはWinnyを使わざるを得ず、Winnyの中継を違法ということにしてしまうと、自分の首を絞めることになるからだ。実態が報道されないのはより悪いことだ誰もが思うため、それまでは誰も(表では)そのことに触れないできた。
その状況を踏まえて、ネットランナー等がDOM(ダウンロードするだけの行為)を推奨する。DOMが増大し、DOMだけとなり、Winnyネットワークは消滅する。*3
ISPにWinnyの利用を規制する正当な理由があるとすれば、それは、Winnyが通信の使い方に欠陥があることを示した場合だろう。
Slammerワームが流行したとき、ISPでポートを塞いで対処する方法が検討されたが、これは、Slammerが不正プログラムであることが明らかだったからだ。
ワームでなくても、ある壊れたプログラムによって、全く意味を持たない大量のパケットが放出され続けるという事態が起きれば、そのプログラムを止めるようISPがユーザに依頼するということも正当化できるだろう。
Winnyは、実際、無益なパケットを大量に出している可能性がある。
いったん流出したファイルが止められないのは、その独特の使用方法にも原因がある。ウィニーユーザーは、必要なものだけ選んでダウンロードするのではなく、キーワード検索にヒットするファイルを片っ端からダウンロードして、後から必要なものだけ見るという使い方をする。そのため延々とウィニーを接続し続ける。
ウィニー騒動の本質 あまりにも情報流出のリスクが大きい, 朝日新聞社 論座, 2006年5月号
大半のファイルは、消費されることなく削除されているのではなかろうか。
仮にすべてのWinnyユーザが寝ている時間以外のすべてを動画鑑賞に費やしていたと仮定しても、4Mbps程度しか消費しない。一方、ブロードバンド回線の帯域全部をWinnyに使用した場合、数十Mbpsが消費する。実際には、有益に消費されるファイル容量はずっと小さいだろう。
ISPは、Winnyのそうした使われ方の実態を調べたらいい。「平均10Mbpsで通信しているのに、そのうちの99パーセントは無意味に捨てられている」という結果を出せれば、Winnyには欠陥があると主張することができるはずだ。
昔は、シグネチャを5行以上書くと「トラフィックの無駄だ」などとネットワーク屋にトンチキなことを言われたものだ。それが今はどうだ。
まっとうなソフトウェア作者なら、ネットワーク回線を有益に使うためのトラフィック調整を考えて作るだろう。Winnyは、Winnyネットワークにとってだけ都合がよいように作られた利己的プログラムである。全体のトラフィック制御をせず、最大限使い尽くし、基幹ネットワークのボトルネックによって結果的にトラフィック制御されるという、傍若無人なソフトウェアだろう。
そうした欠陥プログラムは、匿名でない人によって配布され、用途が革命を起こすようなものでもないならば、とっくに糾弾されているところのはずではないか。
「ソフトウェア技術者連盟」のような技術者の倫理を考える集まりは、そうした、非倫理的プログラムの定義を打ち出したらよい。
情報処理学会のような既存の団体が倫理綱領を作れば、当然、現行法遵守となるだろうが、そうした観念にとらわれない新しい団体であるならば、違った形の定義を出せるはずだ。
現在Winnyについて「大人の議論」を繰り返している人たちは、技術を理解していないオヤジ達によって不適切に広く「非倫理的プログラム」が定義され、法規制されることの有害性を憂慮してのことだろう。
であれば、わかっている技術者団体が先手を打って、最小限の非倫理的プログラムの定義を打ち出せばよい。Winny作者が認めている通り、Winnyはそれに該当する欠陥プログラムであるとし、ISPが規制するのも妥当だとすればよい。そして、Winnyに取って代わる次のソフトウェアも、その定義に当てはまらないように作ることを促したらよい。
*1 Winnyに脆弱性がなければトロイを自動実行させられることがないというものではないのであり、Winny自体に脆弱性があるかないかはどうでもいい。別のソフトウェアの脆弱性が突かれてWinnyネットワークに放流されることが危険である。ちなみに、もしWinnyにバッファオーバーフロー脆弱性が発覚すると何が起きるかというと、破壊的ワームの登場によってWinnyネットワークは一旦壊滅状態となり、その後、そのワームを排除する「無視リスト」設定が周知されるか、もしくは、Winnyが使うポートに挟んで使用するフィルタが開発され配布されて、Winnyネットワークは復旧するだろう。
*2 もちろん、そんな悪質な不正プログラムをばら撒く行為は許されないものであり、一刻も早く処罰できる体制にしておかねばならない。
*3 しかし、このとき、ユーザはそそくさと次世代システムに移行してしまうかもしれない。次世代システムがファイルを分割してばら撒く方式を採用した場合、もはや、倫理に訴えることはできなくなるかもしれない。二次流出に加担するという点は実質的には同じであるけれども、分割方式ではそのことがわかりにくくなるかもしれない。Winnyのような単純な方式であれば、まだ理解されるかもしれないのだが……。
4月12日の日記「Winny利用教唆本のセキュリティ対策指南、その仰天内容」のリンク元を辿ったところ、
今月Winny特集やってるから、高木さんに取り上げてほしいなあ。
という記述があった。どうやらこのブログ主は、「ネットランナー」の編集長の方らしい。
たしかに、Winnyの話題で「違法行為を蔓延させた刑事責任は出版社にある」という指摘が出てくるときに真っ先に槍玉に挙がるのは「ネットランナー」であることが多いが、実際のところ同誌はそれほど悪質なものではなく、セキュリティ対策をキチンと啓蒙するなどの良い点もあるとの主張を耳にすることもあった。
ネットランナーはほとんど読んだことがない*1ので、昔どういう内容だったとかは知らないが、編集長がこうおっしゃるくらいなので、今月号はセキュリティ対策のことがたくさん書かれているのだろう。
「じゃあ見てみることにするか」というわけで、買ってきた。パラパラと開くとたしかにセキュリティの解説が盛りだくさんだ。
ほう……。
それはひょっとしてギャグで言ってるのか?
終了。
*1 私のWebサイトが紹介されたときに頂いた見本誌を読んだことがある程度。