仙石浩明の日記

2006年

2006年10月16日

迷惑メール送信者とのイタチごっこを終わらせるために (1) hatena_b

迷惑メール (UCE, UBE, スパム メールなどとも呼ばれる) が沢山届いて困る、 というのはメールアドレスを公開している人にとって共通の悩みのタネであるはず。 SpamAssasin などの メールフィルタを使っている、というかたも多いだろう。

しかしながら、メールの内容を見て迷惑メールか否かを判断するフィルタでは、 迷惑メール送信者とのイタチごっこは避けられない。 送信者は迷惑メールと判断されないよう、 どんどん内容を巧妙に変化させていくからだ。 例えばフィルタリングアルゴリズムとしてよく使われる ベイジアン フィルタ(Bayesian Filter) は、 ワード サラダ (Word Salad) を食わされることによって精度が落ちてしまう。

したがって 迷惑メール送信者とのイタチごっこに終止符を打つには、 迷惑メール送信者が変更できない情報にのみ依存した 迷惑メール判定方法を用いるしかない。

迷惑メール送信者が変更できない情報とは、つまり 送信元 IP アドレスである。 そんなものはプロバイダ (ISP, Internet Service Provider) を 変更すれば変えられる、 と言われればその通りなのであるが、 単に別のアドレスに変えられるというだけであって、 望み通りのアドレスに変更できるわけではない。

例えば私が使っているメールサーバの IP アドレスは 60.32.85.220 であるが、 送信元 IP アドレスとしてこのアドレスを使える人は特定少数の人のみであり、 この IP アドレスから迷惑メールが送信されるような事態は、 まず起きないと言えるし、 万一「特定少数」のうちの誰かが迷惑メールを送るようなことがあれば、 直ちに止めさせることができる。

この IP アドレスからは迷惑メールを送信させない、というポリシーでもって 運用されている IP アドレスは数多い。 きちんと運用されているサイトの多くが同様のポリシーで運用されていることだろう。 だからそのような、「きちんと管理された」IP アドレスから送信された メールのみ受付け、 迷惑メールの送信元となる可能性がある IP アドレスからのメールを拒否すればよい。

つまり IP25B (Inbound Port 25 Blocking) である。 既に IP25B を実施しているプロバイダ もあるようであるが、 インターネットにおける通信は end-to-end を基本にすべきであって、 通信インフラを提供する側であるプロバイダが、 他のプロバイダと連係して IP25B を実施することについては違和感を覚えなくもない。

もちろん沢山ある IP アドレスの全てについて、 きちんと管理されているか否かを調べ上げることは困難であるが、 迷惑メールを送ってくる IP アドレスというのは実はそんなに多くはない。 私のサイト宛に迷惑メールを送ってきた IP アドレスを、 私は数年間にわたって記録しているが、 大多数は、ダイアルアップと思しき IP アドレスであり、 しかも、いくつかの国に集中している。

ここでいう「ダイアルアップ IP アドレス」とは、 個人ユーザがプロバイダと契約してインターネットに接続するときに、 プロバイダから割当てられる IP アドレスを指す。 「ダイアル」して接続する場合だけでなく、ADSL 等による接続も含む。 多くの場合、接続が切れるたびに異なる IP アドレスが割当てられるが、 固定的な IP アドレスが割当てられている場合もある。

このような IP アドレスは、 逆引きしても、「P061198164231.ppp.prin.ne.jp」といったような プロバイダ名しか分からないような「匿名」ホスト名しか得られないか、 あるいはそもそも逆引きが設定されていないケースが大半である。 ちなみに「P061198164231.ppp.prin.ne.jp」というホスト名は、 数字の部分を三桁づつ区切ると「061」「198」「164」「231」になり、 このホスト名に対応する IP アドレス「61.198.164.231」から 規則的に名付けられたホスト名であることが分かる。

多くのプロバイダにおいて、 「ダイアルアップ IP アドレス」には、 このような規則的に命名されたホスト名がつけられているようだ。 逆に言うと、 逆引きして規則的なホスト名が得られたときに、 その IP アドレスを「ダイアルアップ IP アドレス」と見なすことは、 ある程度の合理性を持つ。

「規則的なホスト名」=「ダイアルアップ」という認識が広まるにつれ、 ダイアルアップ以外の IP アドレスには、 規則的でないホスト名をつける風潮が強まるだろう。 実際、 私が知っているあるデータセンタは、顧客が使用する IP アドレスに、 規則的ではないホスト名をつけるよう推奨している。

したがって、メールの送信元 IP アドレスを逆引きしたときに、 規則的なホスト名が得られたら、 そのメールは高い確率で迷惑メールと予測できる。 他の迷惑メール判別方法と組合わせ、 送信元が規則的なホスト名であることを必須条件とすれば、 排除するメールを迷惑メールのみに限定する (つまり false positive の可能性をほぼゼロにする) ことが可能となる。

一方、逆引きしたとき規則的でないホスト名が得られたら、 そのメールは十中八九、マトモなメールである。 仮に迷惑メールだったのなら、 ホスト名を元にその管理主体がどんな組織であるかある程度想像つくだろうから、 迷惑メール対策が期待できそうなら連絡すればよいし、 その組織からのメールを受け取る必要がなければ、 以後受け取りを拒否すればよい。

したがって問題となるのは逆引きができない場合である。 逆引きを設定していないような管理不十分なサイトからのメールは受け取らない、 と言ってしまえるのなら楽なのであるが、 残念ながら逆引きを設定していないサイトは数多い。 その全てからのメールを拒否してしまうと、 必要なメールまで失いかねない。

そこで役に立つのが自前のブラックリスト/ホワイトリストである。 今まで受け取ったメールを集計して、 迷惑メールしか送ってこない送信元 IP アドレスはブラックリストに載せ、 必要なメールを送ってくる送信元 IP アドレスはホワイトリストに載せる。 そして、ブラックリストに載っている IP アドレスから送られてきたメールは 「ダイアルアップ IP アドレス」に準じる扱いにし、 ホワイトリストに載っている IP アドレスから送られてきたメールは、 迷惑メール判定をスキップして無条件に受け取るようにする。

今まで受け取ったメールを全て保存していれば、 ブラックリスト/ホワイトリストを作るのは容易だろう。 が、マトモなメールならいざ知らず、 迷惑メールまでも全て保存している人は稀かも知れない。 迷惑メールを受け取ったら、 内容を保存するかどうかはともかく、 送信元 IP アドレスだけは記録するようにしておきたい。

とりあえずお手軽にブラックリストを使って、 逆引きできない送信元 IP アドレスを分別してみたいというかたのために、 私が個人的に使用しているブラックリストを公開する。 送信元 IP アドレスが A.B.C.D であるとき、 D.C.B.A.rbl.gcd.org の TXT レコードが引けたなら、 その IP アドレスはブラックリストに載っている。 例えば IP アドレス 127.0.0.2 がブラックリストに載っているか調べるには、

% host -t txt 2.0.0.127.rbl.gcd.org
2.0.0.127.rbl.gcd.org text "Listed 127.0.0.2"

などと DNS 問合わせを行なえばよい。 "Listed 127.0.0.2" などの結果が返ってくれば ブラックリストに載っていることを意味し、 NXDOMAIN つまりレコードが存在しないという結果が返ってくれば ブラックリストに載っていないことを意味する。 私はこのブラックリストを利用した迷惑メール判別フィルタを用いることによって、 私のメールボックスに届く迷惑メールのほとんど全てを排除できている。

前述したように、 このブラックリストはあくまで送信元 IP アドレスが逆引きできないときに限り 利用することを想定している。 逆引き可能な IP アドレスに対してこのブラックリストを利用した場合に 得られる結果は無意味であるので注意して欲しい。 また、もちろん利用は at your own risk でお願いしたい。 このブラックリストに対するご意見は歓迎するが、 このブラックリストを利用したことによって、 あるいは利用できないことによって発生するいかなる損害に対しても 私は責任を負わない。 この条件に同意して頂けるかたにのみ、 このブラックリストの利用を許諾する。

Filed under: システム構築・運用 — hiroaki_sengoku @ 06:48
2006年10月6日

SED 教室

久しぶりに sed の話題を見かけたので、 思わずトラックバックしてみます。

アキバ系!文京区本郷四畳半社長」曰く

最近はSEDとかみんな使わないのかなあ 便利なのに
...
Rubyスクリプトさえ書きたくないときにはSedです。
Sedの過激な使い方については 往年の名著「MS-DOSを256倍使うための本 vol.2」が めっぽう面白い
これこそハックだよなあ

手前ミソながら、sed の過激な使い方にかけては、 SED 教室 も そこそこいい線行っているんじゃないかと自負しておりますが、 いかがでしょうか?

例えば、 SED 教室 第十一回 「正規表現、再論」 で紹介している、 sed で「uniq -c」コマンドを実現するスクリプト:

x
1s/.*/    /
H
y/ 0123456789/11234567890/
G
s/.*\([^0]0*\)\n.*\n\(.*\)[^9]9*$/\2\1/
x
s/\n.*//
$!N
/^\(.*\)\n\1$/!{
  x
  G
  s/\n/  /
  P
  s/.*/    /
  x
}
D

なんてのは、ぱっと見では何をやってるんだか、 まるで分からないこと請け合い ;-)

Filed under: プログラミングと開発環境 — hiroaki_sengoku @ 11:38
2006年10月5日

グループウェア・サーバを社内に置こう! hatena_b

何をいまさら、という声が聞こえてきそうですが、 社内からの情報漏洩が問題となっている今だからこそ、 あらためて社内情報を扱うサーバを、 社内LAN に置くことの重要性を訴えたいと思います。

もともと、グループウェアといえば社内のサーバに置くのが当たり前だったのですが、 いろいろな情報がグループウェアに蓄積されるにつれ、 社内からだけでなく、社外にいるときもグループウェアにアクセスしたい、 というニーズが高まってきました。

グループウェアを社外からも利用するには、 サーバをどこに置くかで分類すると、 次の 3 通りの方法があります。

  1. 社内LAN に置く
    ファイアウォールに穴をあけて社内のサーバへアクセスできるようにするか、 あるいは VPN などの方法で社内からのアクセスを社内へ導く方法です。 正規のアクセス以外の、招かざる客を確実に排除できなければなりません。
  2. DMZ 上に置く
    社外からもアクセスできる非武装地帯 (DMZ) にサーバを置く方法です。 ファイアウォールで守られない場所に置くのですから、 サーバは自分自身を守ることができなければなりません。
  3. 社外に置く
    他社が提供するグループウェアASP サービスを利用する方法です。 情報管理を他人任せにできるので一番手間がかかりませんが、 万一情報漏洩が起きたときに誰が責任をどうやって取るのか、 契約等ではっきり決めておかないとトラブルの種となるでしょう。

いずれも一長一短があるので、いちがいにどれがいいとは言えませんが、 それぞれどのようなリスクがあるかきちんと把握した上で利用することが重要ですね。

手軽さだけで言えば、もちろん 方法3 が一番簡単なのですが、 手軽なだけにリスク管理が出来ていない人が利用すると、 情報のダダ漏れが起きます。

【警告】Googleカレンダーで情報流出? から引用:

無防備な人が多いには驚きます。 Googleカレンダーで、 まるでソーシャルブックマークみたいに公開設定をしている人が何人もいます。 実に詳細な仕事のスケジュールが公の場にさらされており

ということも実際に起きているようです。

じゃ、公開設定しなければ安心か、というとそうとも言えません。 別に ASP サービスを提供している会社を信用しないわけではないのですが、 サーバに情報をため込めば、サーバの運用管理を行なう過程で、 どうしたってその情報が漏れるリスクはあります。 万一漏れたときに ASP サービス提供会社がどう責任をとってくれるのか、 確認しておきたいところです。

他人任せにするのは、どうも気持ち悪い、という場合は 方法1 あるいは 方法2 を選択することになります。 方法2 は、ASP サービス提供会社が行なっているのと同等のことを 自社で行なうイメージですね。 自社で運用するので、情報漏洩が起きたときの責任の所在ははっきりしていて いいのですが、 どうやって外部からの攻撃を防ぐかが問題となります。

インターネット上でサーバを安全に運用することが困難だからこそ、 各種 ASP サービスが提供されているわけで、 きちんとしたサーバ運用管理体制を整えずに運用したりすると、 あらゆる攻撃を受けて侵入されてしまうかも知れません。 また、サーバそのものは運用できていても、 グループウェアの側に脆弱性があって、漏洩事故が起きてしまうケースもあります。 そもそも、きちんとサーバを運用できるだけの体制を整えられるのなら、 ASP サービスの提供側になったほうがよさそうです。

と、いうわけで結論は、方法1 の「グループウェア・サーバを社内に置こう!」です。 この方法のいいところは、社内で使っているグループウェア・サーバを、 変更なしにそのまま使えるという点で、 気をつけなければならないのは、正規のアクセス以外の不正侵入を どうやって確実に排除するか、という点です。

社内で使っているグループウェア・サーバをそのまま使うわけですから、 何らかの脆弱性があることを前提としなければなりません。 脆弱性がないなら DMZ に出しておけるわけで、 社内に置く最大のメリットは、多少の脆弱性は許容できるという点にあります。 だから、 正規ユーザ以外からのアクセスは決して、 社内サーバに到達できないようにしなければなりません。

では、どうやって不正アクセスを排除すればいいのでしょうか? ファイアウォールに穴を開ける方法にせよ、 VPN を使う方法にせよ、 何らかの「入口」を設置して、 そこで正規アクセスと不正アクセスを選別することになりますが、 この「入口」を適切に運用管理することは結構大変です。 不正アクセスを試みる人は、なんとかこの「入口」をだまして 通ろうとするわけで、 「入口」をきちんと運用管理する体制を整えなければなりません。

あれ? 結局これでは 方法2 と同じですね?

そこで、「VPNワープ」です (我田引水... ^^;)。 VPNワープは、この「入口」を提供する ASP サービスなんです。 グループウェア・サーバ自体は社内に置いて情報漏洩のリスクを抑えつつ (方法1 の長所)、 「入口」の運用管理だけ他社 (つまり KLab) 任せにして手軽さも確保する (方法3 の長所)、 方法1 と 方法3 のいいとこどりの「入口ASP」、それが VPNワープです。

今月末まで無料スタートキャンペーン中ですので、 ぜひこの「入口ASP」をお試し下さい。 BIGLOBE会員のかたは、「エージェント」と「SSL証明書」を ダウンロードするだけで利用できますし、 BIGLOBE会員でないかたも、 初期費用・月額費用が無料の 「コンテンツ」コースに入会すれば、 すぐ VPNワープをお試し頂くことが可能です。

Filed under: システム構築・運用 — hiroaki_sengoku @ 13:56
2006年10月2日

2000年、ケータイJAVA がベンチャーと技術者を結び付けた

技術をウリにする会社は、その立ち上げメンバに三種類の人種が含まれていることが必須なのだと思います」と以前書いたのですが、 「人種」が異なる人が出会う事って、 実はかなり稀な現象なのではないかという気がしています。

先日、某大学へ遊びに行く機会があったのですが、 日頃ベンチャーの中ではあまり感じることがなかった 「人種の近さ」のようなシンパシーを 感じてしまいました。 そういえば、私の大学時代の友人には、 大学に残って学究の道を進み、 教授や助教授にまで上り詰めた人が少なくありません。 大学に残らず大企業の研究所などに就職した人もいるのですが、 いつのまにか ;-) 大学に戻っていたりします。

彼らの大半は、私なんぞよりはるかに頭がよく、 その能力をベンチャー発展のために使ってもらえたら、 日本のベンチャーはもっと活気付くのにと、 つい思ってしまうのですが、 彼らの興味がベンチャーに向くことが稀なのだから仕方ありません。

つまり、大学志向の人とベンチャーを興そうという人とでは、 興味の対象が異なるのです。 日本の大学でインターネットの研究が盛んだったのは '80年代の終わりごろです。 インターネット黎明期と呼ばれる頃ですね。 日本を代表するような大企業の研究所では、 当時からインターネットに注目していましたが、 ビジネス的にはまだ海のものとも山のものとも分からず、 ましてこれから起業しようとする人たちが興味を持つような 代物ではありませんでした。

1992年ごろにインターネットの商用利用がはじまりましたが、 インターネットでベンチャーを興してみようと思う人たちが現れたのは、 1994年ころからです。翌年 1995年はインターネット元年と呼ばれていますね。 ところが大学では、 1992年ころまでにインターネットは すっかり日常生活の一部となってしまっていました。 いまさらインターネットで何をするんだ、と思ってしまっていた人も 多かったのではないでしょうか。 今となっては先見の明の無さを恥じるばかりですが、 私自身 1992年ごろには、インターネットにはもはや技術的に新しいことは 何も残ってはいないと思っていました。

ところが、みなさんもご存じの通り、ベンチャーにとってインターネットは '90年代終わりになってからが本番で、 2000年のネットバブル崩壊をものともせず、 数多くのベンチャーが果敢に挑戦を続けています。

学問的に盛り上がってしばらくして下火になる頃から、 それがビジネスの種になりベンチャーが盛り上がる、 こういう順番になるのは当たり前と言えば当たり前すぎるのですが、 こうした時間のずれが、 学問の世界の人たちと ベンチャーの世界の人たちが 出会う機会を減らしているのでしょう。

そんな中、2001年に始まったケータイJAVA は、 学問志向の人とベンチャー志向の人が同時に関心を寄せた、 数少ない例外の一つだったのではないでしょうか。 当時私はベンチャーに対しては何の興味もなかったのですが、 ケータイでユーザプログラムを動かすことができれば、 何か面白そうなことができそうだと思っていました。 一方この年は、iモードの成功が誰の目にも明確になった年で、 ケータイJAVA は iモードの可能性をさらに広げてくれるものとして、 多くのベンチャーが大変な関心を寄せました。

そうして、ベンチャー志向の人と、大学志向の人との出会いが数多く生まれました。 あれから 6年たった今、 こうした出会いを産み出す共通の関心事には何があるでしょうか?

Filed under: 元CTO の日記,技術と経営 — hiroaki_sengoku @ 07:38
2006年9月27日

ssh-agent を screen の中から使う方法 hatena_b

GNU screenバグ報告を行なう ついでに screen-devel ML に参加したら、 次のようなメールが ML に流れてきた:

There is a much simpler solution
http://www.2701.org/archive/200406150000.html

The key is that SSH_AGENT need not point to a socket, it can point to a symbolic link to a socket.

なるほど~

ssh-agent と通信するための UNIX ドメイン ソケット を指す (パス名固定の) シンボリック リンクを作るようにしておけば、 環境変数 SSH_AUTH_SOCK には、そのシンボリック リンクのパス名を 設定しておけば済むので screen の中で ssh を使うとき便利、 というわけである。 つまり、

senri:/home/sengoku % ssh asao
Last login: Sun Sep 10 08:24:20 2006 from senri.flets.gcd.org
Linux 2.6.16.28.

asao:/home/sengoku % echo $SSH_AUTH_SOCK
/tmp/ssh-chKJY25976/agent.25976
asao:/home/sengoku % screen -r

senri で ssh-agent を走らせておいて、 asao へ ssh でログインするさいに、 ForwardAgent を有効にしておくと、 上の実行例のように、SSH_AUTH_SOCK に UNIX ドメイン ソケットの パス名が設定され、このソケットを介して senri の ssh-agent と通信ができる。

ところが、前回のログイン時に使っていた screen を reattach すると、 screen の中では、SSH_AUTH_SOCK の値は、 前回のログイン時のパス名のままである:

asao:/home/sengoku % echo $SSH_AUTH_SOCK
/tmp/ssh-ptnuvb3346/agent.3346

ForwardAgent はログアウトと共に終了するので、 screen の中の SSH_AUTH_SOCK の値は、 ログインするごとに設定し直す必要がある。 これはとてもメンドクサイ。

ログインし直すたびに SSH_AUTH_SOCK の値が変化するから、 このような問題が起きるわけで、 SSH_AUTH_SOCK の値が常に同じなら、 reattach した screen の中でも同じ SSH_AUTH_SOCK の値を使い続けることができる。

すなわち、 SSH_AUTH_SOCK が直接 UNIX ドメイン ソケットを指し示すのではなく、 UNIX ドメイン ソケットを指し示すシンボリック リンクを作成しておいて、 SSH_AUTH_SOCK にはこのシンボリック リンクのパス名を設定しておけばよい。

さっそく ~/.cshrc に次の行を追加した:

set agent = "$HOME/tmp/ssh-agent-$USER"
if ($?SSH_AUTH_SOCK) then
        if (! -S $SSH_AUTH_SOCK) unsetenv SSH_AUTH_SOCK
endif
if ($?SSH_AUTH_SOCK) then
        if ($SSH_AUTH_SOCK =~ /tmp/*/agent.[0-9]*) then
                ln -snf "$SSH_AUTH_SOCK" $agent && setenv SSH_AUTH_SOCK $agent
        endif
else if (-S $agent) then
        setenv SSH_AUTH_SOCK $agent
else
        echo "no ssh-agent"
endif
unset agent

私は、かれこれ 20年近く csh をログイン シェルとして使い続けてきているので、 ~/.cshrc なのだが、今となっては (極めて?) 少数派だろう。 bash など、sh 系をログイン シェルとして使っている場合は、 ~/.profile などに

agent="$HOME/tmp/ssh-agent-$USER"
if [ -S "$SSH_AUTH_SOCK" ]; then
        case $SSH_AUTH_SOCK in
        /tmp/*/agent.[0-9]*)
                ln -snf "$SSH_AUTH_SOCK" $agent && export SSH_AUTH_SOCK=$agent
        esac
elif [ -S $agent ]; then
        export SSH_AUTH_SOCK=$agent
else
        echo "no ssh-agent"
fi

などと書いておけばよいだろう。

Filed under: プログラミングと開発環境 — hiroaki_sengoku @ 07:56
2006年9月23日

設定10分、月額525円の「VPNワープ」を BIGLOBE と共同で提供開始 hatena_b

昨日、NECビッグローブ株式会社と 共同で、BIGLOBE法人会員および個人会員向けに 「VPNワープ」の提供を 開始しました。 これまで VPN-Warp 入門編 6回、応用編 3回を書き綴ってきましたが、 「VPNワープ」サービス 開始により、 より多くの方に手軽に VPN-Warp を使って頂けるようになったと思います。

なお BIGLOBE会員でないかたも 初期費用・月額費用が無料の 「コンテンツ」コースに入会すれば、 VPNワープをご利用頂くことが可能です。

「設定10分ですぐ使える SSL VPN」を目指して、 「VPNワープ」で提供するリレー・エージェントは、 relayagent フリーダウンロード で公開しているものより、 さらに簡単な「簡易インストール方式」を採用しています。 10分で設定できるかは、もちろん個人差があるとは思いますが (^^;)、

  1. VPNワープのページの 管理者メニューの「購入」を選ぶ
    (現在、無料スタートキャンペーン実施中につき、10月末まで無料)
    指示にしたがって進んでいくと、 証明書 relay,4000017.pfx (数字の部分はユーザごとに異なります) が ダウンロードできるので、これをダブルクリックしてインポートする
  2. 「リレー・エージェント」インストール用プログラムをダウンロード
    このプログラム VPN-Warp_RelayAgent_Setup_Biglobe.exe をダブルクリックすると 「VPN ワープ relay エージェント(Biglobe版)」ウィザードが開くので、 以下のように、ウィザードの指示に従って必要項目を入力していく
    • イントラネットの Web サーバをアクセスするときの URL のサーバ名部分 (例えばトップページのURLが「http://intra/index.html」であれば「intra」) を入力
    • 証明書ストア内の証明書の一覧が表示されるので、 その中から 1. でインポートした証明書 (上述の例では relay,4000017) を 選択する
    • Windows にログオンするときのパスワードを入力 (リレー・エージェントが証明書ストアにアクセスする際、 ユーザ権限で Windows にログオンする必要があるため)
    • 「インストール」ボタンを押すと、インストールが行なわれ、 「relay エージェントサービスを開始しますか?」という 問合わせが表示されるので「はい」を押す

これだけで、証明書をインポートずみの PC であれば、ブラウザから
「https://biglobe.klab.org/」へアクセスするだけで
イントラネットの Web サーバにアクセスすることができるようになります。

「VPNワープ」で提供するリレー・エージェントも、 本ブログ上で公開している relay agent も、 相互に互換性がありますので、 「VPN ワープ」にて本ブログ上で公開している relay agent を使うことも可能です。 ただしこの場合、BIGLOBE への問い合わせはご遠慮下さい。 本 VPN-Warp ブログで公開している relay agent は、 本ブログの読者のかた限定で公開しているものであり、 この relay agent を使った際に生じた問題等は、 本ブログに対するコメント等で問い合わせて頂きたいと思います。

  • 入門編 (1) VPN-Warp の特長: ふつうの SSL VPN と比べて
  • 入門編 (2) VPN-Warp の特長: ssh のポートフォワードと比べて
  • 入門編 (3) stone & relayagent の設定方法
  • 入門編 (4) stone の代わりに OpenSSL の s_client を使ってみる
  • 入門編 (5) stone の代わりに普通の WWW ブラウザを使ってみる
  • 入門編 (6) WWW ブラウザを使う場合の注意点
Filed under: システム構築・運用 — hiroaki_sengoku @ 08:46
2006年8月28日

screen 4.0.2 のバグ hatena_b

GNU screen の 最新バージョンである 4.0.2 において、 SJIS な端末で screen を走らせて screen のウィンドウで eucJP を使おうとすると、 1 バイト文字の前に 0x8E が挿入されてしまう。
つまり、 screen のコマンド「encoding eucJP SJIS」 (kanji euc sjis) を実行した場合とか、
あるいは「KJ=SJIS」を指定した端末で「defencoding eucJP」 (defkanji euc) を指定した screen を使うといった場合である。

なぜだろうと思い、ソースを確認すると、encoding.c の 1154 行目あたりが 次のようになっている:

          if ((0x81 <= c && c <= 0x9f) || (0xe0 <= c && c <= 0xef))
            {
              *statep = c;
              return -1;
            }
          return c | (KANA << 16);

え? これってもしかして 2 バイト文字 (全角文字) 以外は 全て 1 バイトカナ (半角カナ) 扱いにしてしまっている?

screen 4.0.2 は、2004年1月27日に公開されていて (私の知る限り) これが最新版だと思うのだが、 このような単純なバグが 2年以上にわたって放置されているとは信じられないので、 すでにパッチが出回っていて、 開発元にも連絡が行っているのではないかと思う。 ご存じの方はご指摘頂ければ幸いである。 しばらく様子をみて、ご指摘が無いようであれば、 念のため開発元にパッチを送ってみる予定。

言うまでもなく、0x80 未満 (最上位ビットが 0) の文字は、 「KANA」扱いしてはいけないので、 上記コードは以下のようであるべきだ:

          if ((0x81 <= c && c <= 0x9f) || (0xe0 <= c && c <= 0xef))
            {
              *statep = c;
              return -1;
            }
          if (!(c & 0x80)) return c;
          return c | (KANA << 16);

このような修正を加えることにより、例えば ~/.screenrc

defkanji euc
terminfo xterm KJ=sjis
terminfo kterm KJ=euc
terminfo vt100 AB=\E[4%p1%dm:AF=\E[3%p1%dm:KJ=euc

などと設定して、term=xterm な端末 (term は xterm であるが「シフトJIS」な漢字を表示できる) を使うような場合でも、 漢字を正しく表示できるようになった。

Linux の多くは EUC を標準的な漢字コードとして使っているはずで、 その一方で Windows は SJIS が標準的な漢字コードだったはず (最近は UTF8 の方が多い?) なので、 このような SJIS な端末で EUC な screen を使うケースは 決してレアケースではないと思うのだが、 なぜこのようなバグが放置されていたのかとても不思議である (ちなみに私は Windows 上の TeraTerm を EUC の設定で使っていたため、 このバグに今まで気づかなかった)。

このバグは、端末の漢字コードが SJIS で、かつ screen のウィンドウの漢字コードが SJIS 以外の場合 (つまりコード変換が行なわれる場合) に発現する。 全ての 1 バイトコード (0x00 ~ 0x1F のコントロールコードさえも!) の 前に「0x8E」をつけてくれるので、 screen の detach すらできなくなるという凶悪なものである。
念のため screen 4.0.2 に対する patch の形で修正点を示しておく:

--- encoding.c.org        Mon Sep  8 23:25:23 2003
+++ encoding.c        Mon Aug 28 18:11:57 2006
@@ -1151,6 +1151,7 @@
               *statep = c;
               return -1;
             }
+          if (!(c & 0x80)) return c;
           return c | (KANA << 16);
         }
       t = c;
Filed under: プログラミングと開発環境 — hiroaki_sengoku @ 19:55
2006年8月25日

潜在意識が働いて、新しい洞察が得られる

いま読んでいる本:

フェルマーの最終定理 (文庫)
サイモン シン 著

の中につぎの一節を見つけた (323 ページ):

大事なのは、どれだけ考え抜けるかです。 考えをはっきりさせようと紙に書く人もいますが、 それは必ずしも必要ではありません。 とくに、袋小路に入り込んでしまったり、 未解決の問題にぶつかったりしたときには、 定石になったような考え方は何の役にも立たないのです。 新しいアイディアにたどりつくためには、 長時間とてつもない集中力で問題に向かわなければならない。 その問題以外のことを考えてはいけない。 ただそれだけを考えるのです。 それから集中を解く。 すると、ふっとリラックスした瞬間が訪れます。 そのとき潜在意識が働いて、 新しい洞察が得られるのです。

ついにフェルマーの最終定理を証明したワイルズの言葉であるが、 「潜在意識が働いて、新しい洞察が得られる」という部分に大変共感を覚えた。 「どうやったら無意識の思考をより活性化させることができるか」 考え続けてきた私としては、 我が意を得たりの感がある。

どうすれば無意識の思考をより働かせられるか、 ワイルズは「長時間とてつもない集中力で問題に向かわなければならない」と 表現した。 私は「同時に考えよう (1)」で書いたように、 「日頃から深く考え続けているような事に関しては、 ひらめく頻度が高いように感じる。 おそらく無意識で考え続けているのだろう」と思う。 意識した思考を長時間続けることが必要、 という点で共通しているのが興味深い。

なぜ、無意識の思考を働かせるには、 長時間の意識した思考が必要なのだろう?

なぜ、新しい洞察は、 意識した思考によってではなく、 無意識の思考によって得られるのだろう?

自身の脳の中で何が起っているのか、 そもそも無意識の思考とは何なのか? それが分かれば、 もっと「頭を使う」ことができるかもしれないし、 また自らの能力の限界がどのあたりにあるのか知ることも可能だろう。 ホフスタッターが言うように、 おそらく自由意思は錯覚なのだろう。 受動意識仮説は 「不思議の環」をとてもうまく説明する。

ゲーデル,エッシャー,バッハ―あるいは不思議の環 (単行本)
ダグラス・R・ホフスタッター 著

とはいえ、 脳が自分自身の動作原理を理解する、 などということが本当に可能なのだろうか?
自己言及の環となってパラドックスに陥ったりしないのだろうか?

マインズ・アイ―コンピュータ時代の「心」と「私」〈下〉 (単行本)
ダグラス・R・ホフスタッター/ダニエル・C・デネット 編著

の中の、クリストファー・チャーニアクの短編 「宇宙の謎とその解決」(第17章) に出てくる 「謎の昏睡」を、ふと思い出した。

Filed under: 自己啓発 — hiroaki_sengoku @ 08:27
2006年8月18日

stone 2.3c リリース

stone 2.3c を リリースした。 現時点ではスナップショット扱いであるが、重大なバグが発見されない限り、 このバージョンを stone 2.3 に代えて正式リリースとする予定 (今度こそ!)。 stone 2.3b からの 変更点は以下の通り

depth 値に依存せずに root CA 識別名を指定できるように

stone の SSL 認証 (3) で説明したように、 root CA から数えた階層数で「re数字=正規表現」を指定できるようにした。 root CA を「-1」とし、root CA の子CA が「-2」、以下順に数字が減っていく。

busy loop が起きるバグを修正

stone 2.3b のバグ」 に書いたように、 stone 2.3b には SSL 接続が確立する前に TCP 接続が切れてしまうと、 まれに busy loop が発生するバグがあった。 stone.c 2.2.3.12 で修正済み。

さらに、万一 busy loop が起きたときに、それを検知するコードを追加した。 stone.c 2.2.3.13 には、 busy loop の誤検出するケースがあったので、 stone.c 2.2.3.14 で修正した。

SSL_accept 前に EOF となった場合にエラーを出さない

TCP レベルのヘルスチェックを行なっている場合、 SSL プロトコルを喋らずに shutdown する設定で運用するケースがある。 このような場合に、stone が SSL エラーとして出力してしまうと、 ログが無意味に肥大化してしまう。 そこで accept 直後に EOF になった場合は DEBUG メッセージのみ出力し、 エラーは出力しないようにした (stone.c 2.2.3.13)。

SSL close notify を送信できていなくてもエラーを出さない

SSL close notify を送信する前に通信相手が接続を切ってしまうケースがある。 あまり好ましいことではないが、 SSL セッションの再利用ができなくなる点を除けば実害はなく、 行儀が悪い通信相手のためにエラーログを肥大化させるのは割が合わないので、 これもエラーメッセージから DEBUG メッセージへ降格した (stone.c 2.2.3.13)。

「/udp」指定を転送元、転送先とで区別

従来は、転送先あるいは転送元のどちらかに「/udp」を指定していれば、 udp の中継を行なっていた。 今後は、udp の中継を行なう場合は、両方に「/udp」を指定する必要がある。 片方のみ「/udp」を指定した場合は、 udp から tcp への、あるいはその逆の変換を行なう指定とする予定(未実装)。

Filed under: stone 開発日記 — hiroaki_sengoku @ 08:25
2006年8月15日

stone の SSL 認証 (3)

前々回前回で 説明したように、 stone で 通信相手の SSL 認証を行なうには、 通信相手がクライアントの時 (クライアント認証) は、

-z verify -z CApath=ディレクトリ

という設定で実行し、通信相手がサーバの時 (サーバ認証) は、

-q verify -q CApath=ディレクトリ

という設定で実行する。 「CApath=...」で指定したディレクトリに、 root CA 証明書を「ハッシュ値.数字」という形式のファイル名で 置いておくことにより、 通信相手が提示した証明書を検証することができ、 検証に成功したときのみ通信を許可する、 などのアクセス制限を行なうことができる。

ある root CA が発行した証明書、 あるいはその root CA の子, 孫, ... CA が発行した証明書、 いずれの証明書でも内容を問わず通信を許可して構わないのであれば、 これ以上の設定は不要であるが、 現実問題としては正規の証明書であれば何でも OK というケースは稀だろう。

メジャーな root CA だと、沢山の子 CA を持ち、 それぞれの子がさらに沢山の孫 CA を持っていたりする。 root CA 以外の CA を中間 CA と呼ぶが、 沢山の中間 CA がそれぞれ沢山の証明書を発行しているわけであるから、 その証明書の全てを許可していては、 不特定多数との通信を許可するのと大差ない。

そこで SSL 認証では、証明書を検証するだけでなく、 証明書の内容をも確認することが必要となる。 stone では証明書の識別名が満たすべき条件を正規表現の形で指定することができる。 証明書の識別名とは、例えば次のようなものである:

C=JP
ST=Kanagawa
L=Kawasaki
O=GCD
OU=Hiroaki Sengoku
CN=test
emailAddress=sengoku@gcd.org

これを「/」で区切って一行にした文字列:

/C=JP/ST=Kanagawa/L=Kawasaki/O=GCD/OU=Hiroaki Sengoku/CN=test/emailAddress=sengoku@gcd.org

この一行で表現した識別名が満たすべき正規表現を設定する。 この形式は、 前々回説明したクライアントが 既知の root CA (の子 CA) が発行した証明書を提示した場合の stone の出力例の 中に出てきている:

depth2=/C=JP/ST=Kanagawa/L=Kawasaki/O=GCD/CN=GCD Root CA/emailAddress=root@gcd.org
depth1=/C=JP/ST=Kanagawa/L=Kawasaki/O=GCD/OU=Hiroaki Sengoku/CN=GCD_Sengoku_CA/emailAddress=sengoku@gcd.org
depth0=/C=JP/ST=Kanagawa/L=Kawasaki/O=GCD/OU=Hiroaki Sengoku/CN=test/emailAddress=sengoku@gcd.org

「depth2=」の行が、root CA 「GCD Root CA」の証明書の識別名であり、
「depth1=」の行が、「GCD Root CA」の子CA 「GCD_Sengoku_CA」の証明書の識別名であり、
「depth0=」の行が、「GCD_Sengoku_CA」が発行した証明書の識別名である。
root CA, 子, 孫, 曾孫, ... と、中間CA の階層数が増えて証明書の連鎖が続く場合、 「depth」の数字は大きくなり、 頂点である root CA の「depth」の数字が最も大きくなる。 一方、 サーバないしクライアント自身の証明書は常に「depth0」である。 stone では、depth0 から depth9 まで、扱うことができる。

各識別子 「depth0」~「depth9」が満たすべき正規表現を、
それぞれ 「-z re0=正規表現」~「-z re9=正規表現」(クライアント認証の場合)
あるいは 「-q re0=正規表現」~「-q re9=正規表現」(サーバ認証の場合) で指定する。
stone の設定ファイルの一例を次に示す:

-z key=key.pem
-z cert=cert.pem
-z verify
-z CApath=/usr/local/ssl/certs
-z re2="/CN=GCD Root CA/"
-z re1="/CN=GCD_Sengoku_CA/"
-z re0="/CN=test[0-9]*/"
localhost:25 465/ssl

指定した全ての「re0=正規表現」~「re9=正規表現」が、 それぞれ証明書連鎖の「depth0」~「depth9」とマッチするときに限り、 stone は接続を許可する。

stone 2.3c (近日公開予定) 以降では、 root CA から数えた階層数で「re数字=正規表現」を指定することもできる。 すなわち、root CA を「-1」とし、root CA の子CA が「-2」、 以下順に数字が減っていく。 したがって、上述の設定は以下の設定と等価である:

-z key=key.pem
-z cert=cert.pem
-z verify
-z CApath=/usr/local/ssl/certs
-z re-1="/CN=GCD Root CA/"
-z re-2="/CN=GCD_Sengoku_CA/"
-z re0="/CN=test[0-9]*/"
localhost:25 465/ssl

CA の階層数が 2 (すなわち root CA が depth2) の場合、 「re2=」と「re-1=」、および「re1=」と「re-2=」は、 それぞれ同じ証明書を示す。 両方指定した場合、後者が優先される。 この指定方法を用いると、 中間CA の階層数が一定でなくても、 root CA あるいはその子CA の識別名が満たすべき正規表現を指定することが 可能である。 例えば、

-z re-1="/CN=GCD Root CA/"
-z re0="/CN=test[0-9]*/"

などと指定すると、 中間 CA の階層数にかかわらず、 root CA が「GCD Root CA」であり、 CN が「test[0-9]*」にマッチするような証明書を許可する。

(次回に続く)

Filed under: stone 開発日記 — hiroaki_sengoku @ 08:37
2006年8月13日

stone の SSL 認証 (2)

前回説明したように、 stone で SSL クライアント認証を行なうには、

-z verify -z CApath=ディレクトリ

という設定で実行すればよい。

クライアント認証の代わりにサーバ認証を行ないたい場合、 すなわちサーバが提示した証明書を検証して、 通信相手であるサーバが正に意図した通りの相手であるか確認したい場合は、 「-z」を「-q」に置き換える。 例えば、 ローカルホストの 12345番ポートへの接続を https://www.klab.org へ 中継しつつサーバ認証を行なう場合、 次のように実行する:

% stone -q verbose -q verify -q CApath=/usr/local/ssl/certs www.klab.org:443/ssl 12345
Aug 13 16:13:35.576345 16384 start (2.3c) [3925]
Aug 13 16:13:35.588527 16384 stone 3: m139.tdc.klab.org:https/ssl <- 0.0.0.0:12345
Aug 13 16:13:41.364823 16384 3 TCP 6: [depth2=/L=ValiCert Validation Network/O=ValiCert, Inc./OU=ValiCert Class 2 Policy Validation Authority/CN=http://www.valicert.com//emailAddress=info@valicert.com]
Aug 13 16:13:41.383216 16384 3 TCP 6: [depth1=/C=US/ST=Arizona/L=Scottsdale/O=Starfield Technologies, Inc./OU=http://www.starfieldtech.com/repository/CN=Starfield Secure Certification Authority/emailAddress=practices@starfieldtech.com]
Aug 13 16:13:41.383495 16384 3 TCP 6: [depth0=/O=*.klab.org/OU=Domain Control Validated/CN=*.klab.org]
Aug 13 16:13:41.465200 16384 [SSL cipher=AES256-SHA]
Aug 13 16:13:41.482583 16384 [SSL serial=3db9d6]
Aug 13 16:13:41.482633 16384 [SSL subject=/O=*.klab.org/OU=Domain Control Validated/CN=*.klab.org]
Aug 13 16:13:41.482658 16384 [SSL issuer=/C=US/ST=Arizona/L=Scottsdale/O=Starfield Technologies, Inc./OU=http://www.starfieldtech.com/repository/CN=Starfield Secure Certification Authority/emailAddress=practices@starfieldtech.com]

この実行例では、 stone を実行した後、ローカルホストの 12345番ポートへ (telnet 等のプログラムを使って) 接続を行なっている。 すると、stone は www.klab.org の 443番ポートへ接続する。 www.klab.org が提示した証明書を受けて、 stone はその証明書を発行した root CA を調べる。

上記実行例 4行目「depth2=...」 に表示されているように、 root CA は「ValiCert Class 2 Policy Validation Authority」である。 この root CA の証明書 (ハッシュ値は bcdd5959) は、 「/usr/local/ssl/certs」ディレクトリに 「bcdd5959.0」というファイル名で用意してあったので、 stone はサーバ認証を行なうことができている。

Firefox などの WWWブラウザは、 メジャーな root CA の証明書を最初から全て持っている。 したがって https な URL を開くとき、 自動的にサーバ認証を行なうことができる。 stone の場合はデフォルトの状態では何も root CA 証明書を持っていないので、 サーバ認証/クライアント認証を行なおうとする場合は、 root CA 証明書を置くディレクトリを用意し、 CApath で指定する必要がある。

なお、WWW ブラウザで普通に「サーバ認証」を行なう場合は、 単にサーバが提示する証明書が既知の root CA から発行されているだけでは 充分ではなく、 その証明書の識別名において、 「CN=...」が示す FQDN がサーバのホスト名と一致しなければならない。
stone でも「CN=...」が示す FQDN をチェックすることができるが、 その方法については 次回説明する

上記実行例 6行目「depth0=...」が、 サーバが提示したサーバ証明書である。
なお、「CN=*.klab.org」 と表示されていることから分かるように、 このサーバ証明書はワイルドカード証明書であり、 klab.org ドメインの任意のホストの身元証明に使用できる。

さて、これで stone を使って通信相手がサーバの時もクライアントの時も、 通信相手を SSL 認証することができるわけであるが、 逆に認証してもらう側はどのような設定を行なえばよいのだろうか?

実は、stone がサーバ認証を受ける側であるときの設定方法は、 すでに前回説明している。 サーバ証明書の秘密鍵および公開鍵が、 それぞれ「key.pem」と「cert.pem」というファイル名で 保存してあるなら、次のように stone を実行する。

stone -z key=key.pem -z cert=cert.pem localhost:80 443/ssl

stone がクライアント認証を受ける側であるときの設定方法は、 「-z」を「-q」に置き換えるだけである。 すなわち、

stone -q key=key.pem -q cert=cert.pem warp.klab.org:443/ssl 12345

このように実行しておいて、 ローカルホストの 12345番ポートへ接続すれば、 クライアント認証を要求する https サーバ「warp.klab.org」へ 接続することができる(もちろん、key.pem および cert.pem が適切であれば)。

(次回に続く)

Filed under: stone 開発日記 — hiroaki_sengoku @ 16:19
2006年8月12日

stone の SSL 認証 (1) hatena_b

stone の SSL 暗号化/復号の機能は、 おかげさまで沢山の方々に使って頂いている。 任意の TCP/IP 接続を手軽に SSL 化できるので、 SSL 化のためだけに stone を使っている、というかたも多そうだ。

例えば 25番ポートで接続を受付ける SMTP サーバがある場合、

stone -z key=key.pem -z cert=cert.pem localhost:25 465/ssl

などと実行するだけで、 SSL 化した SMTP を 465番ポートで受付けることができるようになる。 ここで、「key.pem」および「cert.pem」は、 それぞれ秘密鍵と公開鍵のファイルであり、 OpenSSL のコマンドを使って作ることができる (日経Linux に以前私が書いた連載記事の 「第 6 回 stone (後編) 公開かぎと秘密かぎ」でも作り方を説明した)。

SSL (Secure Socket Layer) というと 暗号化を思い浮かべる人が多いかも知れないが、 暗号化に負けず劣らず重要なのが、通信相手の認証である。 認証、つまり通信相手の確認をせずに通信内容だけ暗号化しても、 通信相手が意図した相手でなく盗聴者だったりしたら、 少しも「セキュア」ではない。

もちろん stone には通信相手を SSL で認証する機能がある。 クライアント認証、すなわち通信相手がクライアントの場合は、 「-z verify」を指定し、 サーバ認証、すなわち通信相手がサーバの場合は、
-q verify」を指定する。

ちなみに stone の SSL 関連のオプションは 全て「-z」か「-q」が前につく。 「-z」は stone がサーバとして振る舞うときのオプション、 「-q」は stone がクライアントとして振る舞うときのオプションである。 通信相手がクライアントの場合というのはつまり stone がサーバとして振る舞う わけだから、「-z verify」になる。

前述した「SSL 化した SMTP」を受付ける stone の場合であれば、 通信相手はクライアントであるから、 「-z verify」を指定する。 このオプションを指定すると、 stone はクライアントに証明書の提示を要求する。 そして提示された証明書を検証するためには、 その証明書を発行した root CA の証明書が必要である。

もちろん、「証明書の提示」といっても、 証明書を送信すれば済む、というものではない。 証明書自体は公開情報 (公開鍵) なので、 それを送信してもクライアントの身の証にはならない。 証明書には対応する秘密鍵があって、 この秘密鍵を持っていることこそがクライアントの身の証である。 SSL プロトコルによってクライアントは秘密鍵をサーバに送信することなく、 自身が秘密鍵を有することをサーバに納得させることができる。

そして、クライアントの身元を第三者的に証明するのが CA の役割である。 ここで言う CA は、 Certificate Authority (認証局) のことであって、 もちろん Cabin Attendant のことではない。 CA を認証する親 CA といった形で CA の階層構造が作られ、 クライアントの証明書を発行するのは末端の CA であることもあるが、 stone が持っている必要があるのは階層構造の一番上、 root CA の証明書のみである (root つまり「根っこ」)。 root CA の証明書一つで、 root CA の子 CA, 孫 CA, ... 階層構造に含まれる全ての CA が発行した 証明書の検証を行なうことができる。

root CA の証明書を置くディレクトリは、 「-z CApath=ディレクトリ」で指定する。 例えば「/usr/local/ssl/certs」ディレクトリに root CA の証明書を置く場合は、
-z CApath=/usr/local/ssl/certs」と指定する。

stone がクライアントに証明書の提示を要求し、 クライアントがそれに答えた場合、 stone はクライアントが提示した証明書を発行した root CA を調べ、 その識別名の「ハッシュ値」を求める。 root CA の識別名のハッシュ値は、 root CA の証明書のファイル名を「CA-cert.pem」とすると、 次のように「openssl x509」コマンドで求めることができる。

% openssl x509 -hash -noout -in CA-cert.pem
ee31d843

次に stone は、 「-z CApath=ディレクトリ」で指定された証明書ディレクトリ (この例では「/usr/local/ssl/certs」) の中の、 「ハッシュ値.数字」というファイル名の証明書を用いて、 クライアントが提示した証明書の検証を行なう。

例えば root CA の識別名のハッシュ値が「ee31d843」であり、 「/usr/local/ssl/certs/ee31d843.0」が存在するなら、 このファイルを root CA の証明書として用いる。 なぜ ファイル名に「.0」という拡張子をつけるかというと、 この証明書ディレクトリに複数の root CA 証明書を置きたい場合、 「たまたま」ハッシュ値が一致してしまう場合があり得るからである。 その場合は、どちらか一方の証明書の拡張子を「.1」にする。

root CA 証明書は、 「ハッシュ値.数字」という形式のファイル名でなければ stone は参照しないが、 かといって「ハッシュ値.数字」というファイル名では、 どのファイルがどの root CA の証明書だか分からなくなってしまうので、 次のように root CA 証明書「CA-cert.pem」のシンボリックリンクを 作成しておくとよいだろう。

% ln -s CA-cert.pem /usr/local/ssl/certs/ee31d843.0

Windows など、シンボリックリンクが存在しない OS の場合は、 単にコピーしておくだけでもよい。

C:\usr\local\ssl\certs> copy CA-cert.pem ee31d843.0

以上、まとめると stone の設定は次のようになる:

-z key=key.pem
-z cert=cert.pem
-z verify
-z CApath=/usr/local/ssl/certs
localhost:25 465/ssl

この設定を例えば stone.config というファイル名で保存し、 「stone -C stone.config」などと実行すれば、 正しいクライアント証明書を提示したクライアントからの接続のみ受付け、 証明書を提示しないクライアントや、 証明書ディレクトリに証明書が存在しない root CA が発行したクライアント証明書を 提示したクライアントからの接続を拒否する。

クライアントが、既知の root CA (の子 CA) が発行した証明書を提示した場合の例:

# stone -z verbose -C stone.config
Aug 12 08:04:13.769309 16384 start (2.3c) [21093]
Aug 12 08:04:13.773038 16384 stone 3: 127.0.0.1:smtp <- 0.0.0.0:465/ssl
Aug 12 08:04:26.534690 16384 3 TCP 5: [depth2=/C=JP/ST=Kanagawa/L=Kawasaki/O=GCD/CN=GCD Root CA/emailAddress=root@gcd.org]
Aug 12 08:04:26.551203 16384 3 TCP 5: [depth1=/C=JP/ST=Kanagawa/L=Kawasaki/O=GCD/OU=Hiroaki Sengoku/CN=GCD_Sengoku_CA/emailAddress=sengoku@gcd.org]
Aug 12 08:04:26.551674 16384 3 TCP 5: [depth0=/C=JP/ST=Kanagawa/L=Kawasaki/O=GCD/OU=Hiroaki Sengoku/CN=test/emailAddress=sengoku@gcd.org]
Aug 12 08:04:26.573916 16384 [SSL cipher=AES256-SHA]
Aug 12 08:04:26.573974 16384 [SSL serial=13]
Aug 12 08:04:26.574000 16384 [SSL subject=/C=JP/ST=Kanagawa/L=Kawasaki/O=GCD/OU=Hiroaki Sengoku/CN=test/emailAddress=sengoku@gcd.org]
Aug 12 08:04:26.574022 16384 [SSL issuer=/C=JP/ST=Kanagawa/L=Kawasaki/O=GCD/OU=Hiroaki Sengoku/CN=GCD_Sengoku_CA/emailAddress=sengoku@gcd.org]

1行目のコマンドラインで「-z verbose」と指定しているが、 これは SSL 関係の詳細ログを表示させるためのオプションである。 「depth2=...」(4行目) が、 root CA の証明書の識別名である。 この証明書は stone にとって既知の証明書なので、 検証が成功する。 「depth1=...」(5行目) は、 root CA の子 CA の証明書の識別名であり、 「depth0=...」(6行目) は、 クライアントの証明書である。

クライアントが、未知の CA が発行したクライアント証明書を提示した場合の例:

Aug 12 08:05:15.587108 16384 3 TCP 5: [depth1=/C=JP/ST=Tokyo/L=Minato-ku/O=K Laboratory Co.,Ltd/CN=KLAB Root CA/emailAddress=root@klab.org]
Aug 12 08:05:15.587172 16384 3 TCP 5: verify error err=19 self signed certificate in certificate chain
Aug 12 08:05:15.587415 16384 3 TCP 5: SSL_accept lib error:140890B2:SSL routines:SSL3_GET_CLIENT_CERTIFICATE:no certificate returned

1行目に、別の root CA の識別名を表示しているが、 この root CA は証明書ディレクトリの中に証明書が存在しないので、 この stone にとって未知である。 したがって、2行目 「verify error err=19 self signed certificate in certificate chain」 つまり「クライアントが自分で署名した証明書 (いわゆる「オレオレ証明書」) を 提示した」と、 検証に失敗した旨のエラーメッセージが出力されている。 クライアントからの接続はこの直後に切断される。

(次回に続く)

Filed under: stone 開発日記 — hiroaki_sengoku @ 08:45
2006年8月3日

人の「意識」は心の中心ではなく、脳の様々な活動のロガーに過ぎなかった! hatena_b

唐突に何かを「ひらめく」という経験は誰しもあるだろう。 「ひらめき」が天から降ってくる、というのは考えにくいので、 意識はしていないものの何らかの思考が脳の中で行なわれ、 その思考の結果が意識にのぼったとき、 「ひらめく」と考えるのが自然だろう。

この意識していない思考、すなわち「無意識の思考」を積極的に活用すれば、 同時に沢山のことを考えられる。 時間を効率的に使えるだけでなく、 自身の脳の中で何が起きているのか理解するきっかけになるのではないかと、 今まで考察を重ねてきた:

意識の「下」に、意識を支える広大な「無意識」がある、 というイメージで考え、 その無意識をもっと活用したい、という思いからいろいろ考えてきたわけであるが、 前野隆司氏のページを読んで、 文字通り天地が引っくり返ってしまった:

脳はなぜ『心』を作ったのか」から引用:

1つの面白い実験結果がある。 人が指を動かそうとするとき, 脳の中の,「動かそう」と意図する働きを担う部分と, 筋肉を動かそうと指令する運動神経が, どんなタイミングで活動するかを計測したカリフォルニア大のリベット博士の実験だ。 結果は実に意外だった。 筋肉を動かすための運動神経の指令は, 心が「動かそう」と意図する脳活動よりも,0.5秒も先だというのだ。 常識的に考えると,まず人の心の「意識」が「動かそう」と決断し, それにしたがって体が動くと予想されるのに,結果は何と逆なのだ。

そうだったのか! それで全て辻褄が合う!

人の「意識」とは, 心の中心にあってすべてをコントロールしているものではなくて, 人の心の「無意識」の部分がやったことを, 錯覚のように,あとで把握するための装置に過ぎない。

まさに、 地球が宇宙の中心で、太陽や星が周囲を回っていると思っていた人が、 地動説を聞かされたときの気分だった。 「無意識の思考」と「意識した思考」の二種類があるのではなく、 「無意識の思考」が全てだったとは。

「あとで把握するための装置」という説明は私にとって、 とても納得のいく考え方だ。 すなわち、無意識の思考は様々なことを「同時に考えている」が、 実際に何を考えていたか、ほとんど忘れてしまう。 ごくわずかな例外が、「意識にのぼった思考」、否、 「意識という記録装置」によって「すくいあげられた思考」ということなのだろう。

同様のことが「夢」にも見られる。 外部刺激が夢に影響を与えることがある。 例えば、目覚まし時計が鳴る音が、 夢の中で電話の呼び出し音として登場するなど。 しかし、因果律で考えれば、目覚まし時計が鳴ることが原因で、 夢の中で電話が鳴ることが結果であるはずだ。 なぜ、

  1. 夢の中で、何かをしているとき、
  2. 電話が鳴る音を聞き、
  3. 受話器を取り上げようと行動しているうちに、
  4. 目覚め、
  5. 目覚まし時計が鳴る音を聞く、

という順番になるのだろうか? 電話が鳴る前に何も夢を見ていないのならまだ理解できるが、 夢なりに脈絡があるシチュエーション (1) で電話が鳴る (2) のである。

どうして外部からの刺激 (2) が原因なのに、 それが結果となるような夢 (1) を「たまたま」見ることができるのか、 とても不思議だった。 私が考えた仮説は、 外部刺激を受けた一瞬のうちに、 夢の全て (1)~(3) (電話が鳴る前の全ての状況を含む) を見て、 そして目覚める、というものだった。

「夢」とは、 寝ている間の無意識の思考の一部を「すくいあげた」ものである、 と考えれば辻褄が合う。 寝ている間、無意識の思考は勝手にいろいろなことを考えるが、 そのほとんどは忘れてしまう。 唯一例外的に覚えているのは、「夢」として意識したエピソードなのであろう。 だから、時系列でいうと、

  1. 様々な無意識の思考が進行中...
  2. 目覚まし時計が鳴る
  3. 目覚まし時計の音の刺激を受けて、無意識の思考「電話が鳴る」が進行する
  4. 目覚める
  5. 「電話が鳴る」思考が、「夢」として意識される

「意識」は元々、「無意識の思考」の後に来るものなので、 因果律的には矛盾がない。 つまり、電話が鳴る音が先で、目覚めるのが後、と 意識する (正確に言えば、そういう記憶が残る) のは錯覚に過ぎない。 意識とは元々そういうものなのだ。

意識とは、脳というコンピュータにおけるロガー (unix で言うところの syslog ;-) に過ぎないのだろう。 つまり、自由意思で何かをしようと決断し、何か行動を起こす、のではなく、 「決断して行動した」という「記憶」が残っている、ということなのだろう。

にわかには信じがたい (人によっては不快とさえ思うかも知れない) 説ではあるが、 「単純なものほど真実に近い」はずであり、 「意識」が「エピソード記憶」のためにある、 という説はとても単純であるように思われる。 ちょうど、「地動説」が (ガリレオの時代の人々にとっては) 信じがたい説であったが、 惑星の見かけの動きを単純に説明できたように。

さっそく前野隆司氏の著書:

脳はなぜ「心」を作ったのか
「私」の謎を解く受動意識仮説
前野 隆司 著

を注文した。 将来のロボットは、本当に心を持つことができるようになるのだろうか?

Filed under: 自己啓発 — hiroaki_sengoku @ 09:33
2006年8月2日

成長する秘訣は、今の仕事を捨てて自分を変えること hatena_b

ピーターの法則って知ってますか? ウィキペディアから引用すると:

  1. 能力主義の階層社会に於いて、人間は能力の極限まで出世する。 すると有能な平構成員も無能な中間管理職になる。
  2. 時が経つに連れて人間は悉く出世していく。 無能な平構成員はそのまま平構成員の地位に落ち着き、 有能な平構成員は無能な中間管理職の地位に落ち着く。 その結果、各階層は無能な人間で埋め尽くされる。
  3. その組織の仕事は、まだ出世の余地のある、 無能に達していない人間によって遂行される。

確かに自分の能力を超える地位まで登ってしまうと、 能力が発揮できなくなってしまう、というのはありそうな話です。 地位が上がって無能扱いされるくらいなら、 同じ地位に留まって「有能」であり続けるほうがマシというものです。 特に、 成果主義が浸透しつつある昨今、 「無能に達する」ことは大変なリスクを伴います。 そんなリスキーな出世より、 特定の仕事を極めてスペシャリストになることを選ぶ、 という人のほうが多数派なのかもしれませんね。

しかしながら、 同じ仕事が同じ価値を持ち続けるかどうかは、 時と場合によります。 職人技が価値を生む分野であれば、 一つの「技」に一生をかける価値があるでしょう。 例えば、従来日本が得意としてきた「モノ作り」の分野ですね。 熟練工の「技」は、 機械には真似ができないという価値を持っていました。

では、我らが「ソフトウェア開発」はどうでしょうか? 「ソフトウェア開発はモノ作りではない」ので、 モノ作りのアナロジーで考えていると大きく価値判断を誤ります。 ソフトウェア開発においては、モノ作りと違って、 熟練自体は価値を生まないからです。 10年の経験を積んだプログラマが、 プログラミングを始めて 1ヶ月の新人に負かされる、などということが 起り得るのがソフトウェア開発でしょう。

一つの仕事に一生を賭けようとするなら、 自身の能力のうち普遍的な価値を持つのはどんな能力なのか? 他の人には真似ができない自分ならではの良さとは、どんなことなのか? 自問し続けることが重要だと思います。

一つの仕事に一生を賭けるのではなく、 仕事を変え、自分を変えていく、という道もあります。 単に仕事が変わる (例えば昇進する) だけでは、 ピーターの法則通り、いずれ無能に達してしまいますから、 この道を選ぶにあたっては自分を変えることが必須です。

つまり受け身の昇進ではなく、 積極的に今の仕事を捨てるべきでしょう。 部下 (or 後輩) が成長してきて、 自分の代わりがつとまるようになったら、 全てその部下に任せてしまい、 新しいことにチャレンジするわけです。 そうすれば部下も育つし、 自分を変えることができます。 運がよければ新たな成長フェーズに入れるかもしれません。

Filed under: 元CTO の日記,自己啓発 — hiroaki_sengoku @ 08:31
2006年7月29日

「ソフトウェア開発」は「モノ作り」ではない (2) hatena_b

「ソフトウェア開発」は「モノ作り」ではない」を とても多くの方々に読んで頂けた。 コメント/トラックバックを頂いた方々、 はてなブックマーク して頂いた方々に 感謝申し上げる。

これだけ多くの方々に読んで頂くと、 誤解するかたも少なくないようだ。 まあ、私の文章力が至らないのだから仕方ないが、 誤解したかたも、もう少し説明を補足すれば理解し合えるのかも知れず、 もう少し書いてみようと思う。

一番の失敗は、 日経ビジネス online の記事を引用してしまったために、 この谷島氏の記事「ITの常識は世間の非常識」の主張が、 私の主張 (の一部) と思われてしまった点だ。 谷島氏の記事では、

「そもそも情報システムと自動車を同一視することもいかがなものかと。 情報システムを何か出来合いの産業機器のように受け止めているわけですよね。 やはり、顧客の意思が反映されるソフトウエアというものをお分かりではない、 ということでは」

ということにまで言及しているが、 私が主張したかったのは「ソフトウェア開発とは何か?」ということであって、 私が言う「開発」とは狭義の開発であり、 谷島氏のメインの主張である要件定義の話まで踏み込むつもりはない。

言うまでもなく要件定義はシステム開発を請け負うにあたって 最重要なステップであり、 要件定義の良し悪しがプロジェクトの成否を分けると言っても過言ではない。 しかし、だからといって他のステップを 無視してしまっていいというわけでもないだろう。

「システムを開発する技術者は、コンサルタントを目指すべし」くらいの勢いで 主張されるかたも多いし、 日経BP 等の Web ページを見ていると、 技術者にとって必要なスキルはコミュニケーション能力だ、 という主張ばかりが目立つ。 確かにコミュニケーション能力は重要ではあるが、 技術者の本分はあくまで「技術力」であって、 それをないがしろにしていいわけがない。

なので、私が主張したいのはあくまで、 技術者がどうすれば技術力を磨くことができるか、 という点にある。 そして、技術力を磨く上で最大の障害になっていると私が感じるのが、 ソフトウェア開発が何であるか、 技術者をとりまく人たち (特に経営側) が分かっていないことが多いし、 いやそれどころか当の技術者さえ、きちんと理解できていないことがある、 という点なのである。

ソフトウェア開発が何であるかが分かっていなければ、 すなわちソフトウェア開発を「モノ作り」と考えていては、 技術者を育てようとしても、 あるいは技術者自身がスキルアップを目指していろいろ勉強しても、 本質を外して徒労に終わるリスクが高い。 せっかく勉強するなら、きちんと本質をとらえて、 「技術力」を確実に伸ばしていって欲しい。

Filed under: 技術と経営 — hiroaki_sengoku @ 07:54
« Newer PostsOlder Posts »