2004-08-25
_ トラックバックURLの集計 from 日記ちょう (13:31)
個人的にはトラックバックのURLは集計対象外にしちゃった方がいいと思うんだけど。
現在は、「データ収集対象からサイドバーを除去」で書いたように、recent trackbackなんかが含まれていることが多いサイドバー部分をできる限りデータ収集対象から弾くようにしたんで、trackbackのURLの大部分は集計対象外になっていると思います。
ちなみに上記対応をしたのは、私も最近「似ている話題を扱っているサイトにめったやたらとtrackbackを打ちまくる(主に)スポーツ系サイト」がランキングに出てくるのがいやだったから。特に悪意もなさそうだし、こういうtrackbackの使い方もありだろうから、SPAM扱い(=ランキング非表示処理)はしなかったけど、情報としてあまりにも意味がなさすぎる。
なんとなく
上記のようなtrackbackの使い方って、一昔前のテキストサイト系のなれ合い文中リンクの仲間のような気がする。同じような話題を扱っているお友達サイトにtrackbackを送ることで、(読者の流しあいによる)曖昧なコミュニティ(内輪)を形成する、みたいな。でもtrackbackの場合は、相手に強制的にリンクを張らせることができるから、双方の同意(なれ合い)度が低い可能性もあるな。片思いでもtrackbackは送れるし。
2005-08-25
_ 今日はスポクラお休み (13:28)
つばを飲んでも喉が痛い状態になり、さらにちょっと寝違えて(あるいは昨日のシャドーピッチングのせいで?)持病の背筋痛が出かかっているんで、今日はスポクラはパス。台風が近づいていて雨の中スポクラに行くのもだるかったし。
_ 今日は (13:32)
JR東日本:列車運行情報 関東エリアをながめながら、やばそうだったら早めに帰らないとな。
_ 状況でToDoリストを整理する (13:33)
時間軸での分類とは別に、状況によってもリストを整理することができる。ToDoリストにまとめられた各項目には、特定の状況でしか実行できないものが存在するはずだ。たとえば、「寝室の収納の掃除をする」のような項目は、家にいるときにしか実行できないだろう。また、「営業のAさんと打ち合わせ」のような項目は、会社にいるときにしか実行できない。
そのような項目は、その実行可能な「状況」という軸で整理してしまう。たとえば、現在「家にいる」という状況で何らかの仕事をこなそうと考えた場合には、「家にいる」という状況のリストを見れば、今実行可能な項目が見つかるだろう。逆にその状況では「会社にいる」という状況のリストを見る必要はない。
というのが「状況」という軸での整理なのだが、本家GTD本ではこの「状況」ベースの整理の具体的な方法は、いまひとつ明快に書かれていなかった気がする。その理由としてはおそらく以下の2点が挙げられるだろう。
まず、この「状況」という分類方法は人によって大きく分け方が異なる。会社勤めしている人しか「会社にいる」という状況はないだろうし、また複数のオフィスを持っている人ならば、単純に「会社にいる」とひとくくりで表現することはできない。そのため、「状況」という軸における分類では、誰にとっても明快なサンプルが出せないというのが一点。
もう一点は、本家GTDでは基本的に通常の紙+ファイリングベースでの分類を前提と(というか、そのようなやり方でも実現できるように)している。そういう物理的な分類方法では、先に書いたような時間軸での分類という明快なやり方を先に採用してしまっている関係上、それとは異なる「状況」という軸を使った分類を、どう実現するかが難しい。物理的な紙とファイルでは、一つの紙は一つのファイルにしか挟めないのだ。
ちなみに具体的な分類例として、私は以前「家にいる」「会社にいる」「出かけている」という三つの状況の分類を試してみた。それはそれで有用な分類方法ではあったのだが、時間軸の分類のような明快さはなく、気持ちよく整理していくという気分とはほど遠かった。この「状況」を切り口に分類するというアプローチ自体は悪くないと思うのだが、整理の明快さを実現するためには、もう一工夫が必要なように思う。
すでに時間軸で分類されたものに対しての「2軸目の分類の表現が難しい」という点に関しては、コンピュータで分類する限りは、リンクによってn軸の関係性は簡単に表現できるので、GTDに向いたn軸の分類が使いやすいプログラムを用意すればそれで解決できるだろう。
自分なりにGTD的なやり方をコンピュータ上で実現するにあたっては、この「状況」という分類方法の実装は検討するべき点が多いが、逆に言うとこの部分で新しいうまいやり方を思いつけば、GTD的なやり方の生産性はさらに高くなりそうでもある。
_ 客観的な判定基準 (13:51)
自分の方の話は、(分かってはいたけど)その不毛さにちょっと疲れてきたので、GTDネタとかで脳みそがリフレッシュされるまで中断することにして、highbiscusさんとτさんの間でやりとりしている、井上雅夫さんの手による「米国著作権法102条(b)項の解説文」の読解について、取り上げてみます。
ポイントは、元の井上さんの文章の、
プログラムは何らかの機能を有しているのであり、ソースコードあるいはオブジェクトコードの表現の複製、翻案を行えば、それに伴って、その機能もコピーされる
における「ソースコードあるいはオブジェクトコードの表現」の解釈でしょう。
τさんはblog@なゆきすと : 「プログラムの表現」とは何かにおいて、
井上氏の解説内で使われている「プログラムの表現」という言葉は、「メディアの上に表現されているプログラムコードそのもの」を指すと考えるのが妥当であろう。
というように、その「ソースコードあるいはオブジェクトコードの表現」とは、ソースコードあるいはコンパイルされたバイナリコード自体を指す(その実行された画面表示などは含めない)と解釈しています。もちろん私もそう解釈します。著作権に関する文章における「表現」という言葉の意味を理解していれば、そう読むのが当たり前です。
一方highbiscusさんは、単に102条bの表現侵害規制の判例を語ってるだけでしょ : highbiscus -北国tvによれば、
プログラムとはなんらかの機能を有しているのはあたりまえであるが、ソースや表示をコピーして、これは機能(アイディア)のコピーであるからいいのだ!って論理は間違いで、それは著作権侵害です、と述べている。
のように、コンパイルされたバイナリコード自体だけではなく、それを実行した際の表示なども含めて、「ソースコードあるいはオブジェクトコードの表現」であると解釈しています。この文章は、Whelan判決における「アイディアのコピーも著作権侵害だ」を表現している文章だ、という主張らしいです。
さてどちらが正しいのでしょう。この件については、客観的な判断基準が存在するので、いつもの不毛な言い合いを続ける必要がありません。実際に元の文章を書いた人に、どちらが正しいのかを聞いてみればいいわけですから。
そこで、「プログラム関連米国判決集ホームページ」の井上雅夫さんに、米国著作権法102条(b)項の注釈文における「ソースコードあるいはオブジェクトコードの表現」の解釈についてメールで尋ねたところ、それは単に「ソースコードとそれをコンパイルしたバイナリコード自体」を意味しており、そこにおける「表現」という言葉には「オブジェクトコードを実行した際の表現(画面表示など)」という意味合いまでは持たせていない旨、ご返答をいただきました。
というわけですので、少なくともその注釈文において、井上さんが「オブジェクトコードを実行した際の表現」について語っているわけではないことになります。
※上記2段落の文章は、井上さんにその内容に間違いがないか確認していただいた上で、そのまま*1掲載しています。
こうやっていつも客観的な判断基準があるといいんですけどね。
_ mb_convert_variables (17:00)
今までその存在に気づかず、自前で再帰関数を書いて使っていたよorz...。
*1 正確には、最初の「そこで」を付け加え、敬称の「様」を「さん」に変更してある
2006-08-25
_ 残り容量が数十Mバイトになっていた
PCがなんかくそ遅いなーと思ってふと空きディスク容量をみたら、残り数十Mバイトまで減っていた。Folder Size for Windowsで各ディレクトリ単位のディスク使用量をながめてみたところ、
- Thunderbirdでimapでアクセスしているアカウントのデータフォルダに、なぜか1GバイトオーバーのINBOXファイルがあった。なにこれ? 削除したけど別に動作には支障はなし。
- puttyのlogが無限に追記されたよ……。数Gバイト。
- 昔ダウンロードしたCD/DVD-ROMのisoイメージファイルが、そこかしこに消されず残ってたよ。10Gバイトオーバー。
あと、細かいテンポラリディレクトリの中身とか消したら、30Gバイトくらい空いた。そこまでやって久しぶりにデフラグを起動したら、表示が真っ赤(ほとんど全部断片化されている)だったので、最適化実行中。これで使わないファイルの圧縮とかが走ればさらに余裕ができるかな。
_ PHPで安全なセッション管理を実現する方法
なんかこの辺の情報って、ちゃんとまとまっているのを見たことがない気がするんで、まとめておく。特にPHPのセッションを標準設定で使った場合の問題とその対策について。ツッコミ歓迎。
まずセッションの仕組みの基本から。
Webアプリケーションは、通常ステートレス(=状態がない)である。ステートレスというのは何かというと、ユーザー(ブラウザ)が連続的に複数回のアクセス(Webページの表示)しても、サーバー側はそれを特定のユーザーの連続したアクセスと認識せず、単に誰ともしらない複数のユーザーが複数回アクセスしたものとして処理すること。
ステートレスの反対のステートフル(状態を持つ)ってのは、ユーザーがページA→ページB→ページCなんてアクセスをしたり、あるいはページBでフォームからデータを投稿したりしたときに、そのアクセス履歴やら入力したデータなどの情報(=状態)を保持した上で、次にそのユーザーがアクセスしたときに、そういう状態を持つユーザーからのアクセスであることをサーバーが(認識しようと思えば)認識できることを表す。
ステートレスなWebアプリケーションにステートを持たせるための機能が、いわゆるセッション管理機能。これは、
- Webアプリケーションにアクセスするユーザーを特定する
- そのユーザーに関する状態(情報)を、サーバー側で保持する
という二つの仕組みを組み合わせて実現している。
ユーザーを特定するための仕組みとしては、ユーザーに対して自動的に(通常初回アクセス時に)識別コードを割り振り、その識別コードを使って特定する。この識別コードのことをセッションIDという。ユーザー(ブラウザ)は、そのWebアプリケーションにアクセスするたびに毎回必ずセッションIDを送信する必要がある。そうしないと、サーバーは同一のユーザーだと識別できない。
セッションIDは通常Cookieとしてブラウザに記憶され、Webアプリケーション(というか、特定のドメインの特定のパス以下)にアクセスするときには、ブラウザが自動的に送信してくれる。Cookieに対応していないブラウザ(携帯とか)では、あらゆるリンクのQUERY_STRINGにセッションID情報をくっつけて送ったりする場合もある。
このセッションIDというのは、ユニークでありさえすれば機能的(ユーザーの識別)には問題ないんだけど、セキュリティまで考えると、ユニークであればなんでもいいという訳ではない。
たとえばセッションIDを、アクセスしてきた人に連番で割り振るような仕組みになっているとする。自分のセッションIDが100だったときに、試しにセッションIDを99とか98に書き換えてアクセスしてみたら、他人(=自分の直前にそのWebアプリケーションを利用した人)のセッションIDを使ってアクセスできてしまうかもしれない。
その場合、そのセッションIDに結びつけられた情報には、他人の個人情報などが含まれていたりして、そういうものが表示されてしまうかもしれない。あるいは、そういう他人の情報を書き換えてしまったり、あるいはその人の権限で何らかの処理を実行できてしまうかもしれない。
それを考えると、セッションIDは第三者が推測可能な内容であってはいけない。そのため一般的には、ランダム(=ロジックで推測されない)かつ十分に大きい(=可能性のある値を順次試す(=ブルートフォースアタック)ことで、実用的な時間内に正解に行き当たることがない)識別コードを生成して利用する。たとえば、マイクロ秒単位の現在時間+乱数発生器+サーバー固有の値+ハッシュ関数の組み合わせを使って、数十桁の16進数文字列を生成したり、とか。
ともかくそうやってセッションIDを使ってユーザーを識別できるようにしたら、そのセッションIDをキーにサーバー側で情報を保存する場所を用意する。どこに保存してもいいんだけど、PHPのデフォルトのセッション機能では、指定されたディレクトリ(/tmpとか)の下にセッションIDをファイル名の一部に持つファイルを作成し、その中にシリアライズ(バイト列表現に変換)されたPHPの配列を保存するようになっている。セッションハンドラーを変えれば、DBに保存したり、メモリキャッシュに保存したり、いろいろできる。
これで、
- ユーザーがセッションIDをサーバーに送る
- セッションIDにマッチするセッション保存ファイルを読み込む
- セッション保存ファイルの内容を復元(unserialize)して、$_SESSION変数に入れる
といった形でPHPのセッション機能が実現されるようになる。
って、セッションの仕組みの基本を説明しているだけで、ずいぶん長くなったな。ここまでは前振り。次からが本論。
PHPのセッション機能は、セッション固定攻撃(session fixation)に対して脆弱だ。セッション固定攻撃っつーのは、攻撃者が用意したセッションIDを強制的に使わせることによって、本来推測不可能なはずのセッションIDの、推測(というかあらかじめ知ること)を可能にしてしまう方法。
PHPのセッション機能は通常、Cookie経由のセッションIDもQUERY_STRING経由のセッションIDも、どちらも認識できる(session.use_only_cookiesオプションでQUERY_STRING経由のセッションIDを認識しないようにできる)。また、セッションIDが外部から渡された場合、そのセッションIDに対応するセッションデータ(通常はファイル)が存在しない場合は、自動的にそのセッションIDに対応するセッションファイルを生成し、正常にセッションを開始してしまう。
つまり、あるユーザーがあるWebアプリケーションにアクセスする入り口のところで、何らかの方法(Cookieのドメインによる有効範囲をうまく利用したり、セッションID付きリンクを踏ませたり)でセッションIDを固定してしまえば、そのユーザーはそのアプリケーションで、既知のセッションIDを使ってセッションを開始してしまうことになる。
今のところPHPには、セッションデータが生成されていないセッションIDが渡されたときに、そのセッションIDを利用したセッションを有効にさせない、というようなオプションがない(パッチはある)ので、外部から渡されたセッションIDでセッションが開始されてしまうことは避けられない。
じゃあどうすればいいかというと、
- セッション変数の内容を見て、その正当性を確認する
- セッションIDを変更することによって、危険なセッションIDを無効にしてしまう
あたりの組み合わせが対策となる。たとえば、
session_start();
if (!isset($_SESSION['_SESSION_CHECK']) {
session_regenerate_id();
$_SESSION['_SESSION_CHECK'] = array(
'startTime' => time(),
);
}
などとする。
これで、もしも正しく初期化されていないセッションが開始された場合は、session_regenerate_id()関数を使って、新しいセッションIDを生成しなおすことによって、もしかしたら外部から渡されたのかもしれないセッションIDは使わないことになる。
また、次のようにすることで、より安全性を高めることもできる。
session_start();
if (
!isset($_SESSION['_SESSION_CHECK']) ||
($_SESSION['_SESSION_CHECK']['REMOTE_ADDR'] != $_SERVER['REMOTE_ADDR']))
{
session_regenerate_id();
$_SESSION['_SESSION_CHECK'] = array(
'REMOTE_ADDR' => $_SERVER['REMOTE_ADDR'],
'startTime' => time(),
);
}
これは、セッション変数に入っている(=セッション初期化時の)ユーザーのIPアドレスと、今回アクセスしたユーザーのIPアドレスがマッチしない場合も、同様にsession_regenerate_id()関数を使って新しいセッションIDが生成されるようにするコードだ。
ただし、複数のゲートウェイを持つネットワークからのアクセスなどの場合は、正当なユーザーでもアクセスのたびに別のIPアドレスが使われることもあるので、このような書き方はいつでも使えるわけではない。利用するユーザーの環境が限定できる場合のみ利用できる方法となる(あと、リバースプロキシとか使っている環境でもこれだと無意味)。
また、上記のような特定の(不正な可能性のある)条件にマッチした場合に限らず、たとえば、
session_start();
if (!isset($_SESSION['_SESSION_CHECK']) || (rand(0, 100) > 99)) {
session_regenerate_id();
$_SESSION['_SESSION_CHECK'] = array(
'startTime' => time(),
);
}
のように、ランダムに1%の確率でセッションIDの変更を行うという方法もありだろう。これによって、未知の(準備したロジックでは判別できない)攻撃に対しても、ある程度安全性を高めることができるようになる。
しかし、実際には上記のコードはあまり役に立たない。
というのは、session_regenerate_id()関数は、セッションIDは付け替えるが、古いセッションIDに結びつけられたセッションデータ自体はそのまま残してしまう(PHP 5.1.0以降ならば、session_regenerate_id(true)とすることで、古いセッションIDに結びつけられたデータを破棄してくれるので、以下の話は関係なくなる)。たとえば、元のセッションIDがxxxxxxで、session_regenerate_id()後のセッションIDがyyyyyyyだった場合、セッションデータファイルとしてはその両方が残ってしまう。
そのため、せっかくセッションIDを変更しても、古いセッションデータに有効な情報(たとえばあるユーザーのログイン権限と結びつけられた情報など)が含まれていた場合、せっかくセッションIDを付け替えても、古いセッションIDの方が悪用されてしまう可能性がある。
単純に、session_regenerate_id()でセッションIDを変更するだけで安全性が確保できるのは、あくまでもsession_regenerate_id()する前のセッションデータに、有効な情報が含まれていなかった場合のみなのだ。
そこで、
if (isLoginOk()) { // 認証が通った
session_regenerate_id();
$_SESSION['userId'] = [ユーザーID];
}
のような形で、ログイン処理の後など、セッション内に重要なデータを登録するタイミングで、session_regenerate_id()を実行してセッションIDを付け替えることによって、セッションの安全性を高めることになる。
たとえそれまで使っていたセッションIDが危険なものだったとしても、それには重要な情報は含まれておらず、重要な情報は必ずサーバー側で新しく生成したセッションIDに結びつけられることになるからだ。
しかし、未知の危険性に対策のために、すでにセッションデータに有効な情報が含まれている状態で、セッションIDを変更したい場合もあるだろう。その場合はどうすればいいだろうか。
セッションを継続する必要がないのならば、session_destroy()を実行することで、現在のセッションIDに結びつけられたセッションデータは破棄される。しかし、それでは新しいセッションIDで今までの情報を引き継ぐことができない。
そこで、次のようなコードを使うことになる。
session_start(); $tmp = $_SESSION; session_destroy(); session_id(md5(uniqid(rand(), true))); session_start(); $_SESSION = $tmp;
テンポラリ変数に現在のセッション変数を待避してから、現在のセッションデータを破棄し、新しいセッションIDをsession_regenerate_id()を使わずに独自のコードで生成してから、再びセッションを開始し、先ほどテンポラリ変数に待避してあったセッション変数を、新しいセッション変数にセットし直す、という方法だ(なぜsession_regenerate_id()ではなくsession_id(md5(uniqid(rand(), true)))を使っているかについてはコメント欄参照)。
これで、すでにセッションデータに有効な情報が含まれている場合でも、セッションIDを変更して安全性を高めることができることになる。
何か問題がありそうな記述があったらツッコミください。修正しますんで。
2006/11/20 http://tdiary.ishinao.net/20061120.html#p01に追加情報を書きました



_ strange [対処済みだったんですね!ただ、goo Blogが残っている気がします。 具体的に書くと http://bm.ishi..]
_ ishinao [goo Blogは、サイドバー領域を特定する方法が見あたらなかったんで、対処しなかったんですよね。ひとまずrecen..]