最新

おおいわのこめんと (2005-07)


2005-07-01

[Comp] 自作スクリプト群公開場設置

自分自身、ずぼらなハッカーであるからして、 同じことを2度やるのは嫌、とか、機械でできることを人手で*1やるのは嫌、という人間なので、割と頻繁に ten-liner を書き散らかしているのだが、自分の手元で使いつつ改善していると、「これってひょっとして欲しい人いるんじゃないの?」と思うことがたまーにある。

とはいえ、大抵ドキュメントとか書くのがが面倒くさくて放置されてしまうので、とりあえず最終処分場を設置してみることにした。

本当は研究室サーバから自前サーバへの移転に伴う新 CMS のシステム設計構築とか、いろいろやりたいことがあるのだが、切りがないのでとりあえず手書きHTMLで見切り発車。そうでもしないと時間が足りなくてほんとに何もできないし、場所さえ用意してあればそのうち1つずつ「処分」するくらいなら気力も続くだろう、と踏んでのこと。

とりあえず、第1弾は本当にしょうもないスクリプトにしてみた。

*1 ちなみに頭使う単純作業とか、機械にできないツマランことをやるのは嫌いじゃない。


2005-07-02

[Misc] 銀行ATM

6/25 の話の続き。 今日久しぶりに東京三菱銀行のATMに行ってきたところ、 いつのまにか(?)暗証番号入力画面に「並べ替えボタン」が付いていた……。 見落としてたのか?? 無かったような気がするんだけどなぁ……。

というわけで、早速使ってみました……。 完全ランダムだと*1意外と入力辛いな(笑)。 ちょっと「タッチでウノー」を思い出してしまいました。

セキュリティ的には画面への直接の視線さえ気にしておけばいいのはかなり気は楽ですね。 折角なので積極的に使っていってみることにします。

*1 もちろん今回の問題の場合は順列巡回だけだと10通りしか無くて効果が薄いので、 完全ランダムなのは正しいんですけど。電子錠の場合、指跡すり減り対策なので10通りでも十分平均化されるからOK。 この場合、1つ目の数字さえ探せばあとは探しやすいんですよね。


2005-07-04

[Misc] 研修

旅に出ます。探さないでください(TM)。(これ ばっか。)

1日半つくばで研修。今回は東京の仕事キューエントリも大量に抱えているので、 朝一のバスで移動する予定。


2005-07-05

[Misc] 高速バス

遅れるといやなのでと開始2時間20分前のバスに乗ってしまったので、 超順調に1時間20分前に到着してしまった。

ねむいー。


2005-07-06

[Misc] 帰還

こういう面白い研修なら何度受けてもいいなぁ……。

MAX COFFEE 初めて飲んだ……あむゎぁ〜〜ぃ (>_<)……。

本日のツッコミ(全1件) [メッセージを送る]

Tackey [お疲れ様でした。 MAX COFFEE僕もこの前初めて飲みました。 めちゃくちゃ甘いよね!(笑 ]


2005-07-07

[Security] 証明書の確認 (SSL雑誌原稿追記)

となりの席の先輩から、「ねぇねぇ、大岩君の原稿さぁ、 証明書の確認のところで『Part2 の Column 参照』って書いてあるけど、 これでいいの?」(超意訳)とのツッコミが入る。 6月16日 に書いた通り、この記事を書いた段階で、 Part 2〜3 は全く見ていなかったわけです。 そして、原稿を提出したところ、この部分の()内は編集部側で 挿入され、まぁ校正の時にも「正しいことが書いてあるんだろう」と思い、 特集の記事同士で一体感を出すのは悪いことではないと思い、 スルーしたわけです。まぁ、さすがに Part 2 や Part 3 もマトモな人が書くだろうと 期待していたわけです。

それでもって発売日、Part 3 については FreeCA の話なので ツッコミ所あるだろうと思ってさっさと読んでツッコミを入れ、 一方でPart 2 については商用 CA の話だから別に問題ないだろうと 多寡をくくって、今日に至るまで目にすらしていなかったわけですが……。

orz

……えー、上記の事情で「記事見せろ」ということもなく 編集部挿入の外部参照をスルーしたことについては、 読者のみなさまにお詫び申し上げます orz。「チェック方法については Part 2 の Column を参照」の注記については、削除してください。

ていうかまぢでひどすぎます(*`Д´)。まぁ Part 1 を注意深く読んで理解した人には、 Part 2 のコラムで書いていることがおかしいことは一見してわかるとは思いますが。 今度から他者原稿への参照の要請は二度と受け入れないことにします。 いい勉強になりました、まったく。

ここでツッコミをどかどか入れてもいいんですが、 ツッコミ所満載過ぎて正確にツッコむのが結構大変なのと、 今日は朝10時から夕方まで会議漬けであまりにしんどかったので、 問題点の指摘は読者への宿題にしたいと思います (ぉぃっ。 解答欄はに。(ほんとかよ

怒りをエネルギーに変えて週末には書くよ。

[Security] 証明書の確認 その2 (SSL雑誌原稿追記)

というわけで、罪滅ぼし(?)にここで書きたかったことをちゃんと書いておくことにします。

まぁそうは言っても、元々僕は参照を書いていなかったわけですから、 書くまでもないほど単純なことでして、 サイト証明書の証明内容に含まれる、会社名 (O)・部署 (OU)・住所をきちんと確認して、 自分が本当に繋ぎたい相手先のサイトなのかどうか確認しろ、というだけのことです。 信頼できないオレオレ証明書を導入したりしていなければ、基本的には その部分の確認だけで十分なはずです。 問題の Part 2 コラムにあるようなことをする必要はないし、 あんな不正確な方法で検証してもま〜〜〜ったく意味がないです。

そういうと、「4/18 みたいな話はどうなるんだ、 証明書発行者も見なきゃ信用できないじゃないか」と言われるわけで、 実際 Opera なんかも Organization だけではなく証明書発行者を表示するように 変更されたわけですが、僕の見解では基本的にはこれは Opera のバグではなくて、 この偽証明書を発行してしまった PKI 基盤の問題だと思うわけです。 この時の事件については、当事者の2社で本当にどっちが悪いのかについては、 G 社が「正規の書類で取得しました」とだけ書いて詳細を明らかにしていない以上 僕には判断がつきませんが、いずれにせよ信用できない CA がルート証明書ストアに 登録されている時点で、SSL のセキュリティはないんだ、と思った方がいいです。 あるCAを信用できないなら、信用するルート証明書のリストからはずしてしまいましょう。 *1

もっとも、現状のブラウザがCAの信用に関して「100%信用する」と「信用しない」の2つしか 選べないのは、結構不満でありまして、CAごとに柔軟な選択ができてもいいとは思うんですよね。 「このCA (あるいはその顧客) イマイチ信用ならないから、 一応初回アクセスの時は警告出して確認できるようにしよう」とか、ね。 そういう意味で、証明者の名前を見たときに、CA及び利用するサイトの信用度が 心の中に思い浮かぶのであれば、証明書の発行者を確認してそれと照合するのは悪いことではないでしょう。 この辺りのPKIのユーザへのより安全な見せ方については、 追々探求していきたいと考えています。

あるいは、様々な大人の事情で信用しきれないCAの証明書を登録しなければ ならないのであれば、まぁせいぜい頑張って証明書発行者も毎回チェックしてください。 その場合、「信用できない」の度合いにも因りますが、原稿の図13で示した通り、 信頼されてしまったCAは中間証明書を使い他の正当なCAの名前を名乗ることが できますので、ちゃんと証明書の簡易表示ではなく、証明の検証パスの末端から全部 見て判断する必要があります。 また、原則としては全リクエストに対して毎回チェックしないといけないはず *2 ……やってられないよね。やっぱりオレオレ証明機関は入れないに限ります。

[Security] 今後の予告 (SSL雑誌原稿追記)

ええと、近いうちに書かなきゃならないと思っている記事内容の予告。

  • 僕の考える Web のための PKI の信用モデルの捉え方(実在証明の意義)と、現状の問題点。
  • 問題の記事に対する問題点の指摘。
  • 自分の記事への若干の補足(簡潔のために説明を端折った部分の補遺)。

でも何時になったら書く暇できるんだろう。

*1 もっとも IE の場合、外し方を気をつけないといけないらしいんですが……。それはまた今度。

*2 何時突然偽サイトに誘導されるかわからないため。同じドメインに違うCAからの 証明書が見つかったときに、警告が出るようになっていればいいんですが。今度検証してみようかな。

本日のツッコミ(全4件) [メッセージを送る]

kazuho [*2 についてですけど、ロードバランシング環境での証明書更新作業に支障が出るので、検証パスやサイト証明書が変化する度..]

kazuho [ごめんなさい。寝ぼけてて意味不明なコメントを書いたような気がします。言いたかったことは下のとおり: 「初回アクセス..]

おおいわ [kazuhoさんの言うような問題は確かにあって、(ロードバランサの場合のCAとの契約は良く知りませんが) なかなか(..]

kazuho [なんで気にしてるかというと、過去に、あるロードバランスされているウェブサイトが、それぞれ異なる CA から発行された..]


2005-07-09

[Security] セキュリティ技術に関する的を外した議論を見分けよ

いきなり挑戦的だなぁ(笑)パクリくさいし(笑)(*)

たとえば昨日「orz」した UNIX USER の例の記事の Part 2 コラムも そうだし、高木さんなんかも たとえばこの辺 で「混乱させる」とか「不適切な対応の例」とかでいくつか指摘しているが、 セキュリティ対策業界では割と的を外した議論とか対策法の提案とかが 多い気がします。 これらを産み出している構造的欠陥ってなんだろうなぁ、と日頃思っているわけですが、 つまるところ、議論を組み立てるときにきちんと

  1. 前提となる(既に保全されている)セキュリティのレベルを設定し、
  2. 議論の想定する攻撃の範囲を設定し、
  3. そのなかであり得るあらゆる攻撃を想定して考える

というステップを踏んでいないのではないかなぁ、と思うわけです。 2. と 3. はほぼ同値ですが、よくある誤りに「攻撃の過大評価」と「攻撃の過小評価」 があるんで、敢えて分けてみました。

例えば、

  1. スパイウェアが入っていたら、ルート証明書ストアは信用できないから、 自分で証明書を確認して、確実な認証状態を確認すべきである
  2. CSRF 対策でセッション鍵をフォームに埋め込んで確認しても、Cookie は盗聴されるから安全ではない
  3. SSL ではオレオレ証明書を何も確認せずに使っていても盗聴はされていない

なんかは、それぞれの段階の欠如の例として作ってみた例ですが、 それぞれダメな理由はわかりますよね? 念のため確認しておくと、

  1. そもそもスパイウェアが動作している状態では、 ブラウザに介入して証明書の表示自体を偽造可能だから、 証明書を表示して認証状態だけ確認しても意味がない。 更に言えば、キー入力とかを盗めるので暗号化通信自体も意味がない。
  2. 素の HTTP の通信上での認証を議論するときは、 通信路上の盗聴・差し換え攻撃などは想定していない。 (差し換えができるなら、そもそも認証後のリクエスト本体だけ 差し換えてしまえば認証など意味がない) また、CSRF の防護をするときに、(認証前の段階で攻撃可能な)XSS などが ないことも前提となる。*1
  3. 通信路上の攻撃があることを想定するならば、受動的な盗聴攻撃だけでなく、 能動的な攻撃を想定すべきである。通信パケットを窃取して Man-in-the-middle 攻撃をしかければ、実質的に盗聴と全く同じ効果を 得ることが可能である。

ですが、ここの読者には書くまでもなかったかな?

良心的な間違っている記事も結構多いんで、このタイトルの挑戦的さはあとで不便になる (そして改題する) かも しれませんいきなり改題しました(笑)が、これからしばらく、この視点でいろいろな問題点を指摘していきたいと思います。 最近だと高木さんも書いている通り、CSRF とか XSS などの対策でも間違った記述が多いので、 (記事を書く余裕があれば)結構多岐にわたって議論できるのではないかと思っています。

[Security] ……でもって、例のコラムの問題。

で、例の問題のコラムの話なんですが、ツッコム前に上の前提を再確認しておきましょう。 SSL の安全性の議論をするときは、

  1. セキュリティ上の前提として、
    • 最終的な相手方の Web サーバは健全である。
    • 相手方やCAの秘密鍵は漏洩していない。
    • 手元の OS、ブラウザ など、データを暗号化して送出するまでの部分は健全である。
    • ↑の一貫として、ルート証明書のリストには信頼できるCAのみが保持されている。
    の4点は担保されている。
  2. 攻撃としては、DNS、ルーティング を含むあらゆる通信路上の攻撃を 想定する。すなわち、双方が送ったパケットはすべて攻撃者に取得され、 必要なら改竄され、相手方に届いたり届かなかったりする。 送ってもいないパケットすら届くかも知れない。 また、DNS で返ってくる値も、何も信用できない。
    あえて想定していない攻撃を挙げるとすれば、 消費電力の微妙な増減を誰かが監視してるとか、それ系。

という前提を一般に置きます。

その前提でコラムを読むと、まずは「誰が署名したかまでは確認できてない」 と書いてあって、まぁ「そりゃ確認してないよなぁ」と思うわけです。 そこでまず、証明書を見るわけですが、ここで最初の誤りがあるわけです。 電子署名の検証の段階で、署名者をブラウザが「確認済み、OK」とした段階で、 ブラウザが保持している正しい署名者のリストと照合していますから、 基本的にそれ以上の検証は不要です。 署名者のフィンガープリントが一致しなければ、それは署名者の公開鍵と 署名が一致しないことを意味しますから、「怪しいことになる」などと 人が思うまでもなく、ブラウザは「署名が一致しない」警告を出します。 *2 これ、ブラウザの SSL/PKI 実装のもっとも基本的な部分です。

そして、「フィンガープリントの値が一致しただけでは」の段落は、 はっきり言って意味不明ですね。「偽証」の意味がそもそもわかりませんが、 「フィンガープリントが一致する/しない」ことが、 現状のハッシュ関数解読の進捗状況でどういうことを意味するのか *3、 筆者は理解していないんでしょう。Web ブラウザに偽の証明書を 食わせることのできる(ローカルにソフトウェアをインストールさせられる)環境なら、 もっといろいろな攻撃が可能ですから、 フィンガープリントのチェックなんて意味無いし、攻撃者は わざわざ偽の証明書でユーザに攻撃を気付く余地を与えるなんて阿呆なことはしないでしょう。 一方で、いくつか手動でオレオレ認証機関鍵を入れた場合、 前の記事では「諦めろ」と切り捨てましたが、この問題に限定すれば 証明書みて発行者が「自分の導入したオレオレ認証機関」でないことを 確認すれば十分足ります。*4

一方で、偽の証明書を正式CAから取得できてしまうかどうか、という件は、インターネットの PKIモデルの議論になりますんで、別項でもっと議論したいと思いますが、 その手の社会的攻撃を意図しているのなら、その先に書いてある フィンガープリントの検証なんて無意味ですから、いずれにしろ意味無いんです。

そして、そこから先がさらに阿呆で、わざわざ Entrust の HTTP のサイトに行って、 Fingerprint の値なんて調べてるわけですが、SSL を使う話の議論をしている以上、 通信路は全く信用できないという前提なんで、これも愚かです。 こんな方法で確認できるんなら、「そもそも SSL など不要」なんですから。 IP アドレスを確認したところで、通信路上で相手に伝わってる保証なんてないんで、 意味無いです。多分この人には最近の DNS 系の攻撃が頭に染み付いてて、 Web の内容を差し換えるには IP アドレスを偽証しなきゃいけない、とでも思ったんでしょうね。

で、本人は意図していないと思いますが、結論を慎重に読解すると、結局 「何をやっても無駄です」になっちゃうわけで。コラム全体の意味がないですよ。 以上。まぁひょっとしたら「オレオレの議論を Part 1 でやります」、と編集側に言われて 混乱したのかも知れないけど、総じて技術を理解せずに書いている印象がしました。 こんなんだったらコラムの部分の紙数くらい僕に書かせて欲しかったなぁ……。 今回自分の部分の文章長すぎて校正段階で結構削ったのです。

そして、Part 3 への批判でも書いたけど、そこまでルート証明書を信じられないっていうなら、 完全なルート証明書の署名のリストを、確実なルートを使って調べて、 雑誌記事という形で掲載すればいいんですよ。本当にまじめにそういうことを やれば、ある意味すごく貴重ですよ。但し、これは Internet Explorer の ルート証明書を信用しないということですから、「情報が MS のホログラム入り CD より 信頼できること」が条件です。まぁこの記事 (Part 2〜3) 全体に曖昧な記述が蔓延ってますから、 どうやっても期待できないでしょうが。

*1 一方で、URL は様々な場面、例えば Referer などで漏れると思った方が良い。

*2 Part 1 の図13を作る段階で (ローカルで) いろいろと怪しい証明書を作って 食わせる作業をしましたから、実際にそんな感じの警告も見ました。

*3 もっとも MD5 の衝突は徐々に現実っぽい応用が出つつあるようですし、 SHA-1 もまもなくという感じですが、少なくとも SHA-1 に関してはまだ今日の時点では 実用的なデータに於いてハッシュ値が一致しても同一性を信じられない、という段階には来ていないです。 というか、来たら大パニック必至なので暗号屋はそうなる前に対策を練るべく努力しているわけですが。

*4 但し、Part 1 図13 で示した通り、 中間証明者を偽装できるので、署名の全 Path を検査する必要がある。


2005-07-10

[Misc] 素人に分かる……

たまたま家に寄った親戚 (非情報系の先輩) に、 「最近話題になっているセキュリティ問題って一体何なのよ?」 といきなり聞かれた。 最近のニュースの話題としては多分某 k 社だと思うので、とりあえず SQL Injection でも*1 説明してみますか……っておい。

実際のところ、白紙1枚とボールペンで格闘すること約3分、 SQL Injection は枝葉を省けば割と説明しやすい気がした。 今度資料でも作っておくことにしよう。何かの役に立つかもしれん。 Buffer Overrun は一応説明してみたが、相当枝葉をデフォルメしないときつい。

Cross-site Scripting は、挿入攻撃自体は理解してもらえても、何が悪いのか さっぱりわかってもらえないだろう。Cross-site Request Forgery は……無理です(笑)。

まぁ、この手のセキュリティーホールが人災である、というのをはっきりと一般の人に 理解してもらうのは重要だと思うので、親戚に限らず折りにつけて努力していきたい……嫌われない程度に :-)。

人災であることを理解してもらうのは2つの意味で重要で、1つは この業界で「企業の責任」が何故問われるのか(クラッカーを庇っているわけではないこと)を ちゃんと理解してもらうことと、もう1つは「本来ちゃんとやっていれば安全にできるんだ」ということを ちゃんと理解してもらうこと。 ただ FUD で「ネット怖いネット怖い」だけじゃほんとに怖くて使えないよ、との指摘は真っ当だと思う。

*1 k 社の件が SQL Injection とは推測だけで確認できてないんですけどね……。


2005-07-11

[Misc] 面倒な作業

いろいろとごそごそと物事の因果関係を上流に辿っていくうちに、 英語でメールを書く羽目になってしまったようだ(激謎。 最後まで片付くのかねこの作業。

追記 (7/12 10:42)

英語メール用件2件目〜〜。どうしてこう(略

追記 (7/12 24:00)

英語1件片付き。2件目処理中。日本語1件追加。はぁはぁ。

追記 (7/13 18:00)

英語2件片付き。はぁはぁはぁ。

2005-07-13

[Security] 証明書の検証はそもそも必要か?

サブタイトル: 「実在証明の意義」シリーズ序章。

SSL通信の際の証明書の確認について、例のコラムは論外としても、本当に必要なのか?  という議論。 高木さんは、 『未だに 「安全性を確認するには証明書を開く必要がある」といった誤った解説が(そ れもセキュリティに詳しいとされている記者の記事の中で)なされている」と 指摘。』 と、最近のやたらと証明書の確認を要求する記事に不満を表明していて、一方 で僕の記事見ると「証明書を確認すべき」と書いているわけで、「これは一見 すると矛盾してるなぁ」「何とかしなきゃ」と思った次第。

本論に入る前に簡単にまとめると、

  • 高木さんは、恐らく「正しくURLバーに表示されているサーバにデー タを送信していることの確認には、鍵マークで十分である」という意味で書い ていて、それは正しい。
  • 僕は「正しいほげほげ銀行にデータを送信していることを確認す べき」と言う趣旨で、その方法の1つとしては証明書の発行先を確認しろ、と 書いている

と言うことになるかと思います。

僕が「証明書を確認すべき」と言っている理由はただ1つ、「www.goo.co.jp」と「www.goo.ne.jp」 のどっちが本物の『goo』なのか*1、 証明書の「組織名」を見て確認しなさい、という点に尽きます。 従って、goo.ne.jp が自分の意図する正しいアクセス先であることを 既に知っていれば、証明書の確認は 「鍵マーク」で十分です。また、証明書の確認も 7月7日の記事で書いたとおり、 本当に「一回見るだけ」で十分です。 *2 一部に見られる、「fingerprint を確認しろ」とか、「CAのfingerprintまで確認しろ」とかいった議論は、不要なだけでなく有害です。 *3

逆に言うと、例えば hogehoge-bank.co.jp (こちらを本物とする) の偽サイトとして hogehoge-ginko.co.jp が出てきて、 この偽サイトの運営会社名 (あるいは匿名) でサイト証明書が発行された *4 (しかもphishingサイトだったとする) ときに、 一方が偽物であることを(少なくとも実社会と同レベルで)見破る 唯一の手段は、証明書の組織名を見ること *5 なわけです。 僕が思うところのSSL & PKIの本質的な目的は、 何らかの実社会の identity とネット上の 認証を結びつけることだと思うので、 「鍵マークだけでOKです」、とは僕は言い切りたくないんですよね。

また、根本的な点として、記事にも書きましたが 「社名など広く知られたから用意に類推でき、 ユーザに覚えてもらえるサーバー名を付け、 周知するよう努めるべき」だと考えます。 それは、「正しい送信先ドメイン」と「正しい送信先法人」のギャップを作るな、 ということで、そのギャップがなければ 「正しい送信先法人であることの確認」=「鍵マーク」になるわけです。 *6 そういう意味で、「ホゲホゲ・ドット・コム株式会社」とかいう 「カッコヨダサい」*7 会社名って、実はこの目的には合っていたりするのかも。

そういう意味で、Opera の「例の拡張」は 素晴らしいと思うんだけど、 現状では「セキュリティホール」とか言われちゃうんだよねぇ……。 また、実社会でも偽物を見破りにくいケースがあるのと同様の意味で、 サイト証明書を見ても見破りにくいケースも存在するわけですが、 その問題はこのシリーズの本編で取り上げます。 3月28日の記事の焼き直し+加筆 みたいになると思いますが。

[Security] 某記事の補遺

で、先にこっちを書いておくことにする。

1. 公開鍵暗号の鍵って対称なんだっけ?

とりあえずこれは聞かれた内容のその1。 RSA の場合、本当に公開鍵と秘密鍵は立場的に対称なんですが、 それって一般的なの? というお話。 結論から言うと、鍵を作った時点で、一般には「こっちが秘密鍵」「こっちが公開鍵」 というものは決まっている、と思ってください。 この記事全体、RSA以外の暗号の存在を意識しつつ、 話の単純化のために出来るだけそれ以外には触れないで済むように (かつ出来るだけ嘘にならない様に)苦労して書いているつもりなわけですが……。

まず、鍵の立場で言えば、RSA の場合だけは、 「一般に言われている」秘密鍵 $d$ から公開鍵を計算できないため、 公開鍵 $e$ と立場を逆転して使うことができます。 ただ、$e$ は一般に 17 とか 65537 とか の小さくて2進表現での1の少ない既定の値を使うため、 今自分の手元にある RSA の鍵を交換したら、非常に危険になります (超簡単に推測できてしまうので)。 実際に立場を逆転させるためには、結局「$d$ を公開にするのを前提に 秘密の $e$ を生成する」ことになるんで、そうすると最初から $e$ が秘密鍵という前提で鍵を作っていることになって、あまり意味無いですね。 *8 僕より詳しい人に聞いたところだと、「一般に RSA の秘密鍵の 表現を $N, d$ というのはあまり本質的ではない」というべきで、 本質的にはやっぱり、2つの素数 $p, q$ への分解を秘密にしていることが 極めて重要だそうです。

そして、他の暗号系、例えば ElGamal なんかだと、 完全に鍵そのものは非対称です。これらでは、秘密鍵から 公開鍵を計算できる*9ので、逆転は不可能です。 また、Wikipedia の RSA の項 に出ている "different form of the private key" なんかも、 秘密鍵から公開鍵を計算できるような形になっていますね。

そういうこともあって、暗号化と署名の操作も、一般には非対称です。 こちらも RSA の場合はたまたま完全に対称になっていますが、 ElGamal なんかでは全然違う操作をしますし、 暗号系によっては一方の操作のみをサポートしている場合もあります (たとえば DSS)。 また、署名の検証も、逆方向の「復号」とは意味の違う操作になることもあります。 (DSS とか ElGamal(?) は、鍵を知っていれば元のデータが判明する、というわけではない。)

そういうわけで、「秘密鍵で暗号化←→電子署名」とは言えないんで (特に←は明確に偽)、 記事中では→方向だけになるように微妙な表現をしたつもりですが *10、 そこのところは突っ込まれないうちに補完しておきます。 もっと詳しく知りたければ例えば 稲村さんの 「電子署名≠秘密鍵で暗号化」なんかを読んで下さい。 *11

2. ハッシュ関数

これについては、全然詳しく書く紙面がなくて、本当はちゃんと書いておくべきだったな、 と思っています。

ハッシュ関数にもいろいろあって、例えば有名なところでは Java の文字列ハッシュとか、CRC とか、記事で挙げた MD5 とか SHA-1 とか、あるわけですが、 それぞれに限定された用途があります。

端的に言ってしまうと、

  • 別に多少衝突しても構わない (から、速いのがいい)
  • 偶然の変異に対して、衝突があっては困る
  • 意図的な改変に対して、衝突があっては困る & 逆算ができては困る

の3つに分けられるかな……本当はもっと細かいのかもしれない。 基本的には速度を除いて包含関係にあります。

例えば、Java のハッシュの目的は、所謂ハッシュ表にデータを格納するときに、 できるだけ同じエントリに多数のデータが格納されないで欲しい、という だけの話なので、簡単に推測できても構わないわけです。 *12 実際、最後の数文字を調整するだけで簡単に任意のハッシュ値の文字列を 作れますので、セキュリティ的な用途に使ってはいけません。

一方で、CRCとかECCなんかは、通信路上とかメモリ上でビットが化けたときに検出できるように しようという設計なので、ランダムなエラーに対する検出力が主眼になります。 これも、線形なんで、意図的に結果を合わせるのは簡単ですね。 一時期、無改竄検出の用途に CRC を使ったタコな例を見掛けた気がしますが、 最近はさすがになくなったかな……。

それに対して、MD5 とか SHA-1 とかは「暗号的ハッシュ関数」と呼ばれる類で、 自明な限界(64ビットハッシュなら任意の2つが 2−64 の確率で衝突する) を除いては意図的に攻撃しても衝突が起こらないようにと意図して設計されています。 そういう意味で上の2つとは、ま〜ったく設計意図が違います。 もっとも、上の2つの要件を満たせないようでは 解読が容易になりそうに思えますし、実際のアルゴリズムも 上の2つの要件は自明に満たしているようです。

当たり前のことですが、任意の長い文章を 160bit とか 128bit とかに 縮めるわけなので、どうしたって原理的に衝突は避けられません。 セキュリティの記事中に「ほぼ」とか「大体」とかいう曖昧な記述は できるだけ避けるようにしたのですが、ここは「ほぼ確実」と いう言葉を使わざるを得なかったのが、ちょっと心残りかな……。

[Security] ssh の脆弱性を「blindly accept host key」の前提で議論するのは止めよう

何度も言い続けてるんですが、また見掛けたので……。

「ssh のパスワード認証は中間者攻撃に無力だ」とか、 「ssh に脆弱性を見つけました!」とか、 繰り返し繰り返し見掛けるんですが、 無意味な議論なんでいい加減やめましょう。

判って書いている人も中にはいるみたいだし、 今回の人も判って書いているんだと思いますが、 そういう場合は「あのダイアログは意識せずに yes って答えてると危ないよ」 と大人の書き方をして、「怖い怖い」じゃない正しい理解を広めましょう。

という理由は4つあって、

  1. 本当に脆弱なの? と言われると場合によっては実は微妙
  2. PKI (それもオレオレじゃなくて Verisign とかから本当に買ったもの)を 使うんでない限り、本質的にどうしようもない
  3. 実はなりすましだけなら (パスワード漏洩や中間者攻撃ではないが) 公開鍵認証でも可能
    • 従って、ssh agent forwarding をしている場合は中間者攻撃可能
  4. 暗号通信路上で平文パスワードを流す正当性もそれなりにある

です。順番にみていきましょう。

1. 本当に脆弱性?

「初回の接続」の話なら、本当に危険です。ネットワークが信用できない場合、 ちゃんと安全な方法で鍵を受け渡してください。

でも普段、特定のホスト群から特定のホスト群に接続する場合なら、 (例えば初回はノートPCを信頼できるLANに繋いで接続して、 その後外部のネットワークに持ち出してマシンを使う) 実は今の OpenSSH の実装は大丈夫です。ってのはみんな試してないのかなぁ。

実際にやってみる (port 5022 に別のホスト鍵を持つ ssh を繋ぎました) と、 こんな感じになります。

[yutaka@bluereef] (5) ~>ssh localhost -p 5022
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@    WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!     @
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!
Someone could be eavesdropping on you right now (man-in-the-middle attack)!
It is also possible that the RSA host key has just been changed.
The fingerprint for the RSA key sent by the remote host is
5c:fd:21:9c:59:91:e2:30:f3:18:77:fb:a1:50:07:3d.
Please contact your system administrator.
Add correct host key in /home/yutaka/.ssh/known_hosts to get rid of this message.
Offending key in /home/yutaka/.ssh/known_hosts:28
RSA host key for localhost has changed and you have requested strict checking.
Host key verification failed.
[yutaka@bluereef] (6) ~>

……デフォルト設定(鍵の受け入れの有無を聞いてくる「よく『危険』と言われる」設定)では繋がらないのですよ……。 今回の人の場合、この段階で止まる気がします。

ついでに、デフォルトより弱い設定にしてみました。ついでにやばそうな エージェント転送も on にして。

[yutaka@bluereef] (6) ~>ssh localhost -p 5022 -o'StrictHostKeyChecking no' -o'ForwardAgent yes'
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@    WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!     @
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!
Someone could be eavesdropping on you right now (man-in-the-middle attack)!
It is also possible that the RSA host key has just been changed.
The fingerprint for the RSA key sent by the remote host is
5c:fd:21:9c:59:91:e2:30:f3:18:77:fb:a1:50:07:3d.
Please contact your system administrator.
Add correct host key in /home/yutaka/.ssh/known_hosts to get rid of this message.
Offending key in /home/yutaka/.ssh/known_hosts:28
Password authentication is disabled to avoid man-in-the-middle attacks.
Keyboard-interactive authentication is disabled to avoid man-in-the-middle attacks.
Agent forwarding is disabled to avoid man-in-the-middle attacks.
Linux palm 2.4.27 #1 2004年 8月 9日 月曜日 08:30:15 JST i686 unknown

Most of the programs included with the Debian GNU/Linux system are
freely redistributable; the exact distribution terms for each program
are described in the individual files in /usr/share/doc/*/copyright

Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
No mail.

Last login: Thu Jul 14 01:31:28 2005 from localhost
[yutaka@palm] (1) ~>exit
[yutaka@bluereef] (7) ~>

……繋がりましたが、今回は「パスワード認証」「キーボード対話認証」「エージェント転送」 が無効にされました。この3つは自動的に中間者攻撃に使えますから特にやばいわけですが、 ちゃんと対処されてますね。

さて、公開鍵認証で入れたわけですが、ここまで激しく「@@@@@@@@@@@@」と怒られても、 気付かないですか? 「SOMEONE IS DOING SOMETHING NASTY!」とまで言われてますよ……。 正直、攻撃ではなくて再インストールで本当にホスト鍵が変わっていたケースで このメッセージを見掛けて、背筋が凍った覚えがあります。

2. 本質的な必要性

で、PKI でも使わない限りは、ホスト鍵を何らかの形で人の手で導入するのは やむを得ないわけです。認証の本質として、"ssh apple" と打ったときに、 本当に人間が接続したいホストをコンピュータが推測することなどできないからです。 本当に繋ぎたいマシンは、例えば「ラックの中の上から3台目の Sun のマシン」だったり するわけですが、その人間の意識と、apple でも IPアドレス 192.168.3.4 でも、 機械認識可能なアドレス付けとを無知識で結び付けるのは原理的に不可能です。 当たり前ですね。

まぁ「yes 一言で自動導入するをやめれば安全になる」と思うかも知れませんが、 メッセージを読めない or 読まない人は、 たとえ入力するメッセージを「I understand that this method is inheritantly insecure.」 にしようが黙って打つでしょうし、 正しい fingerprint を手で入力させたところで http とか rcp(!) とかで持ってくるでしょうから、大きくは変わらないと思うのです。

それよりも重要なのは、ユーザ教育とか、管理者が /etc/ssh/known_hosts にちゃんと 同一認証ドメインのホストの公開鍵をあらかじめ入れておくとか、そういう話だと思いますね。 僕が学部生の端末室に ssh を導入したときは、ちゃんと40台ある SparcStation20 のホスト鍵を 全部集めて /etc/ssh/known_hosts に突っ込んどきました。

3. 公開鍵認証の場合は安全?

これ、明確に書いたドキュメントがないんで、かなり悩みました。 一応セキュリティを研究しているので暗号プロトコルの読み方と考え方くらいは判りますが、 厳密な証明をしたわけでないので、ひょっとしたら勘違いしているかも知れませんが……。

1時間くらい ssh2 と ssh1 のプロトコル仕様書を眺めて導き出した結論ですが、

  • 公開鍵認証の場合ホスト鍵を検証しなくても認証自体の流用は防がれる: 認証のために送出される秘密鍵情報を 中間者攻撃に使われ、本来のホストに代理接続される可能性は無い。
  • しかし、ホストの認証はされていない: たとえ秘密鍵に対応する公開鍵を知らなくても、 偽装サーバは公開鍵認証を要求し、かつ認証を成功させることができる
  • 従って、認証エージェント転送を使っていて、ログインに必要な鍵が エージェントに登録されている場合は、中間者攻撃が可能となる。
  • また、ログイン先で偽装に気付かずに秘密情報(例えば root password)を使った場合、 情報は当然盗まれる。

……マシなんだかマシじゃないんだか微妙ですね。 僕なんかの場合、エージェント転送は普通に使うんで、 公開鍵認証の場合は安全、とはあまり思えないですが、この辺りは人によると思います。 ただ、「なりすまし」までは成功する、というのはきちんと押さえておいてください。

4. そもそもなんでこんな設計なの?

それでも平文パスワード怖い! って人はいると思います。 「パスワード認証でも平文を送るべきではない! 別の方法を使うべきだ!」 と言う人もいます。まぁ妥当な感覚だとも思いますが、 歴史的に、あるいは今でも rsh/telnet 代替物として考えたときに、 平文を使うのはやむを得ない面があるのです。

というのは、一回でも /etc/passwd とか /etc/shadow とかで認証するプログラムを 書いたことがあれば判ると思いますが、通常の Unix パスワードの認証には 必ず平文パスワードが必要です。 rsh を ssh に置き換える時に、それだけのために認証機構をぜ〜んぶ置き換えるのは 非現実的でしたから、SSH はそのような認証をサポートできるように 設計されたのです。なんせ使ってもらわないと意味無いですから。

「だったら今なら変えられるだろ!」という意見もたまに聞くのですが、 ……それって単に公開鍵認証だけ受け付けるように自分の管理する サーバを設定すればいいだけじゃん……。 「常に平文OK!」なら脆弱性といわれても仕方がないかも知れませんが、 平文認証を拒絶する設定はちゃんとできるように作られているんで、 サイトポリシーの設定者がきちんと設定をすべき、というだけのことで、 人のサイトの設定まで口出して「脆弱だ!」と騒ぐ必要はないですね。

まぁ今だったら APOP と共通の DB を見に行くようにする、とかは できますけど、それがいいとは思わないなぁ……。

ちなみに、現状よく使われる認証、例えば Unix パスワード、APOP、WindowsNT 認証、PAP、CHAP などは、 サーバ側かクライアント側に平文パスワード(正確には、それを知ればログインできるようなデータ) を必要としています。サーバ側に平文パスワードを必要とするプロトコルは、 サーバ側の管理がそれなりに面倒になるので、実は管理者としては嫌なんですよね。 Unix パスワードは「管理者がパスワードを知ることができない *13」 ように設計されているので、その点は楽です。 少なくとも僕個人的には、「僕ら管理者は君らのパスワード見られちゃうから他のホストと共通の パスワード設定しないように」とユーザに徹底するよりは、 「ssh のあの yes/no の質問は気をつけてね」と徹底する方が気が楽です。 最近はもうちょっとマシなプロトコルも開発されているみたいなんで、 それが普及すればもう少しよくなりますが。

結論

結局、この機能は設計者が当初からいろいろな状況を想定して、 代替の仕様のないやむを得ない事情を考え、使い方を誤ると危険になる ことを十分理解した上で、可能な限りの最大限の対策(例えば 1. で示した動作)と、 危険性に対する喚起をしつつ、残置されている機能なわけです。

もちろん批判するのは簡単ですけど、ちゃんとそういった背景を踏まえて 「それでもこうすべきである」と理の通った否定のしかたをしないと、 本当の意味でのセキュリティには繋がらないです。 まして、それなりに意図して作られて「わざとです」と書いてある機能を 「脆弱性」と騒ぎ立てるのは有害以外の何者でもないです。 「包丁は指を切っちゃうから存在自体が危険だ」とか、 「5000回数字を合わせないと錠の開かない金庫は4回の数合わせで錠の開く金庫より安全である」 *14 といった類の無意味な議論は避けるべきではないでしょうか?

一方で、本当に何も考えずに yes 押してる人はやっぱりいて、 その手の「ドキュメント読まない族」に何を言っても無駄だという話は あるのですが、そういった人たちの啓蒙に繋がる建設的な議論は、 どんどんやっていかないといけないな、とも思うわけです。

*1 ご存知のとおり、goo.co.jp の方が「偽」サイトで、 ドメイン紛争の結果 NTT-X 側に強制移転されました。

*2 まぁそもそも NTT-X が goo を運営していることを知らないと、 何の意味もないんですが、まぁそれも知らずに 秘密情報を送るのは個人的にはどうかと思うんで。

*3 fingerprint を確認しなければいけないような状況 (=ルート証明書ストアが怪しい) を想定するならば、そもそも「確認すべきと表示される fingerprint」自体が既に偽造されている可能性があるため、検証しても仕方がない。万が一そういう状況があった場合、侵犯されている状況を「モデルが想定している正当な状態」と誤認して安心してしまう可能性がある。

*4 これはそれこそ某G社とかに申請すれば O = CN な証明書は簡単に取れますし、 別に会社名の入った証明書も普通にとれるでしょう。 バレたときに足がつくから社会的に抑止力が働きますが。

*5 または、非電子的手段で正当なドメインを調べること。

*6 そういう意味でも、最近の合従連衡で銀行関連企業のドメイン名が 激しく類推しづらいのは、何とかして欲しいんですけど……。

*7 ダサカッコイイ (褒め言葉) の反対 :-P

*8 ひょっとすると両方を秘密にしておくことで、何か面白い応用ができるかな?

*9 正確には、「公開鍵を計算できるのに十分な情報を持っていないと、 秘密鍵を使う操作ができない」と言うべきか。 (よって、秘密鍵を持つユーザに対して公開鍵を秘匿することはできない)

*10 図のcaptionが特に微妙やね...

*11 稲村さんの記事に対する感想としては、 個人的には「秘密鍵で暗号化」という表現は RSAに限ってはあまり気にならないです。 というのは、「公開鍵を知らないと復号できない」 という意味で、操作としては文字通り暗号化になっているわけですから、 鍵を公開するか否か、というのは、応用の問題だと理解しています。
第2の点については、まぁ間違っていると言われてしまえばその通りですね。 本文を書くときに、ElGamal とか DSA の存在はもちろん認知はしていて、 どう書くべきかは相当迷ったんですけど、踏み込むと一般誌に8ページではとてもとても……。 そういうわけでベンドマークですが、ここで立てときます (^^; \font\manfont=manfnt at 14.4pt\manfont\char'177
ただ、DSA が SHA-1 と統合されたプロトコルだ、という表現には ちょっと違和感を感じます。q のビット数の 160 とかの設計が、 SHA-1 と合わせて設計してある (というか、これのために SHA-1 が 160bit に設計されていると言うべきか) のは 事実ですが、別に SHA-1 の特定の性質を使ったプロトコルではなくて、 別に160ビットの別のハッシュアルゴリズムを持ってきても 有効に使えるプロトコルですよね? あるいは、MD5 (いまさら使わないけどさ) の 128bit とか SHA-256 の 256bit に 合わせて q とか L の桁数を設定し直せば、やっぱり有効な気がしますし。

*12 もっとも、最近では意図的に衝突を起こしてパフォーマンスを落とす 攻撃などが現実になっているので、衝突させても構わないと安易に言えなくなってきていて、 例えば最新の perl では 対策が入っています

*13 これはつまり、同じパスワードを流用して他のホストにログインを試みることができない、ということ。

*14 まぁ分かると思うけど、オチは、「結局そんな金庫に誰もお金をいれないので4つの方が安全」。


2005-07-14

[Work] みーてぃんぐ

近況報告……とりあえず研究の肴1つ見つけました、という話。

ネタが増えたわけではない辺りが微妙。というか最近メイン研究以外が忙しすぎる……。

何か出た

んんんんん?

(以下次号に続く

(激謎

[Misc] 室温

基本的に僕の部屋では自家サーバマシンが24時間稼働しているので、 この季節、出勤しようとする度に、「クーラーを付けっぱなしにすべきか」 「部屋の入り口のドアは開けておくか閉めておくか」を悩みます。 特に、その時点では部屋が冷えているんだけど、家族も外出するのでクーラーを止めておきたいとき、 「冷気を逃がさないために扉を閉めておく」か、「熱を篭もらせないために扉を開けておくか」 は思案のしどころです。その日の気温とか日射とかでけっこう微妙なんですよね。

ここは1つ、「室温より外気温の方が低いときだけ扉や窓を開けておく装置」が欲しいですね。 名付けて「マックスウェルのデーモン君」。

本日のツッコミ(全1件) [メッセージを送る]

(わ) [リンク先に書かれているBennettの反論が面白いですね。情報の消去にはエネルギーが必要なんだ。先日亡くなった後藤先..]


2005-07-17

[Misc] 家庭内LAN不調

ここ数日親のマシンが不調なので*1、Norton 2005 やら Windows firewall やら壁の中の配線やらいろいろ疑っていたのだが……。

ふと気が付くと SW HUB の電源LEDが消えている……。

どうやら電源内蔵 SW HUB の電源回路が壊れた模様。 とりあえず予備の SW HUB に差し換えて 復旧したのだが、代替品を買ってこないとなぁ……。 自分のパケットはそのSWを通らないので、気付かなかった。

保証はとっくに切れているっぽいので、ゴム足をはがしてネジを開けてみたのだが、 見たところ外見的に焼けているようなパーツは見当たらないのだけど……。しょぼん。

しかし、我が家の中でこの特定の箇所のハブ(各居室のコンセントから僕の部屋に集まってきた 線を集約するHUB)だけ故障率が高い様な気がする。何故だろう……。

*1 といっても、不調だからと呼ばれて リビングまで見に行って、僕が触ると復活するんだよね…。


2005-07-18

[Security] [Comp] Cross-site scripting と Hungarian-notation

僕個人は所謂 Hungarian-notation (型名の省略形を変数名前の頭に付ける記法) は 大嫌いなのだが、最近いろいろな Web プログラムのソースファイルを見ていて、 ひょっとしたら(あくまで過渡的に)最近の web プログラミングに於いては 実践すべきなのではないのか、という気がしてきた。 といっても、別に整数とか長整数とか、まして「ゼロ終端文字列へのロングポインタ(lpsz)」 なんてタグをつけろというわけではなくて、最近流行りの Web 系の脆弱性に応用する話。 というか、危険なプログラム書くよりはHN使う方がマシ。 でもやっぱり嫌だなぁ……。

Hungarian-notation を否定する時に一番楽な言い方ってのは、

「型なんてプログラミング言語が管理するもので、手で書くなんて冗長だろ」

ってなわけですが、良くありがちな CGI ソースを見ていると、 それ以前の問題として HTML にエンコード済みの文字列データと、URL 形式にエンコードした 文字列データと、生の (escape してない) 文字列データをあまりにごっちゃに扱いすぎ。 結果として、escape し忘れで Cross-site Scripting が生じるとか、 逆に2重 escape して出力画面に "Q &amp; A" とかみっともない表示を 晒している (以下、「&amp; 症候群」と命名) とか、そんなのがあまりに多すぎます。

木曜日の時点で高木さんと話をしていて、 「見つけたセキュリティ脆弱性はちゃんと全部報告してますよー」 と大見得を切ってしまったのですが……、 その日の夜に Web サーフ(死語) ついでにいろいろと調査していて、 あまりのその手のバグ (それも、Wiki に張ってあるソースを見て1秒で判るようなやつ) の多さに萎えました(苦笑)。 無理です。前言撤回 orz。

……と脇道に逸れてもしょうがないので本題に戻る。 その高木さんの「サニタイズ言うなキャンペーン」に賛同する私としては、 『ちゃんと出力の直前に「だけ」エスケープ処理を忘れずに挿入すべし』 というのを強く推していきたいわけで、 その本来の姿はもちろん「最終的な print 文とか、 で出力するその地点に escape 処理を挿入」なわけですが、実際のプログラムだと

  • インタフェースとして、HTML-escaped な文字列を返すことになっている関数
  • 処理の都合上一旦 HTML-escaped な文字列を変数に格納する場所

とかがあって、結構2重エスケープバグとかの原因になってるっぽいんだよね。

例えば、これは Hiki の hiki/command.rb から引用した正しい(っぽい)例なんだけど、

      data[:title]          = title( page )
      data[:toc]            = @plugin.toc_f ? toc : nil
      data[:pagename]       = page.escapeHTML
      data[:md5hex]         = md5hex
      data[:edit_proc]      = @plugin.edit_proc
      data[:contents]       = @plugin.text.escapeHTML
      data[:msg]            = msg
      data[:button]         = save_button
      data[:preview_button] = save_button
      data[:link]           = link
      data[:differ]         = differ
      data[:body]        = preview_text ? formatter.apply_tdiary_theme(preview_text) :  nil
      data[:keyword]        ||= CGI.escapeHTML( @db.get_attribute(page, :keyword).join("\n") )
      data[:update_timestamp] ||= ' checked'
      data[:page_title]     = page_title
      data[:form_proc]      = @plugin.form_proc
      data[:session_id]     = @session_id || ''

とか書いてあって、escapeHTML してるのとしてないのがごちゃごちゃと混在。 特に気になるのは :page_title で、いいのかなぁと思ってみると、 だいぶ上の方に

      page_title = d_title ? d_title.escapeHTML : @plugin.page_name(page)

とかあって、じゃぁ @plugin.page_name は? と思うと plugin/00default.rb で

#===== page_name
def page_name( page )
  pg_title = @db.get_attribute(page, :title)
  ((pg_title && pg_title.size > 0) ? pg_title : page).escapeHTML
end

……というわけで、ここまで追い掛けてやっと正しいと判る。 まぁこんなこと毎回やってればいつかは間違えるし、 そうでなくてもこの辺りのコードいじる度にこんなの意識しなきゃいけないんじゃ 効率下がってしょうがない。

で、こんな「物事を区別する」なんてのは機械でやってくれるのがベストなんですが、 まぁそういっても現状 Perl とか Ruby とかでゴリゴリ書いているような プログラマにとりあえず何を提供できるかといったら、 エンコードの違いに応じて変数名に必ず内容を表すラベルをつけるとか、 そういう古の hungarian-notation 的な手法かなと。 少なくともそうすれば、escape 忘れを探すときに、「あれ、この変数って どっかで既に escape されてるんだっけ?」とプログラムを逆方向に探査する 必要はずっと少なくなるんじゃないかなぁと思ったりして。

ここまで考えて、ふと「なんか自分も似たようなことやってね?」と思ったんですが、 探したらありました。ML 系の言語でプログラムを書いていると、リストの要素を順番に変換して 新たなリストをつくる(但し、1要素が1要素に変換されるとは限らない)ときに、 「逆順のリストを構築していって、最後に List.rev で引っくり返す」 という記述をよくするのですが、その時の構築中のリストが逆順であることを 忘れるとあとで面倒になるので、_rev とかいう接尾辞を必ず 変数名につけて区別していたのでした。 「こんなの型で区別するべきだよねー」ってのはその通りで、今は 「後ろに要素をどんどん追加できるリスト」という抽象モジュールを設計実装して、 それを使ってます。

再び本題に戻って、まぁいまどき XSS 脆弱性とか、対策し過ぎの「&amp; 症候群」なんて 超ダサダサなので、そんなの引き起こすくらいならちょっとダサイ Hungarian-notation でもなんでも使ってバグ撲滅してもいいんじゃないかな。とりあえず例えば、

  • HTML エンコード済みな変数(HTML中にテキストとして出力される文字列)は xxx_html
  • URL エンコード済みな変数(QUERY_STRING の組み立てに使う)には xxx_url
  • URL エンコードしたものを HTML エンコードしたもの(最終的に href とかに出力するもの)には xxx_url_html
  • 何も処理してない生の文字列は xxx (そのまま)か、xxx_str とか

とかつけるとか、そういうの徹底してみるのはどうかなと提案してみる。 もちろん関数名も適切に命名規則を決めないといけないし、上のラベルは 長くて邪魔くさいというなら例えば H と U と UH でもいいけど、 その辺は工夫してみて欲しい。 「データ種類の差を意識する」ことは、 「その場その場で表現変換の必要性を意識する」事に繋がるから、 エスケープ忘れとか2重デコード・エンコードが減るんじゃないかなと期待。

(でもやっぱり hn 嫌いな僕としては自分で hn 推奨する文書書くのは腹が立つな……。)

本来正しい解の1つは、ちゃんと HTML の構造を保ったまま 要素の内容を置き換えてくれる(従って escape 処理もちゃんとやってくれる)様な テンプレート系のライブラリを使うことなんですが、 動的に文書の構造を切り替えたいときだとどうしても HTML 片みたいな物を扱う必要はあって、 型で区別するんでなければこの手の処理はやっぱりいるんじゃないのかな? その辺はやっぱり自分で使ってみないとわからないね。 時間がいくらあっても足りないよ。

追記 (7/21)

天泣記 7/20 #2 から。 「HTML片」という言葉が不味かったかも知れないけど、要は HTree の template definition / template call みたいな機能があれば、操作したい HTML の構文部分木を構文木という「型」のまま 扱えるんで OK なんだけど……ということです。 HTree の場合は内部的には「変数」ではなくて、ローカルなモジュールのメソッドに なっているのかな?

「生のタグとCTEXTの列」が必要なケースは、例外的なケースに限られるんじゃないかと僕も思います。

[Security] サニタイズ? エンコード? バリデーション?

で、ついでに「サニタイズ言うなキャンペーン」に関係して。

ええと、ビール半杯 (150mL) で酔っぱらって書いてるんで、文章怪しげ。

このキャンペーン、本人の言い出した元ネタはもっと古いらしいんですが、とりあえず この辺 (PCweb) から。 えび日記さん辺りにも コメントされているみたいですね。えびさんの視点は多分大枠であっているでしょう。

セキュリティ屋、特に IDS とかアンチウィルス的視点で語られる「サニタイズ」ってのは、 荒っぽく言ってしまうと要は「とりあえず " とか & とか、 256バイト越すような入力はオカシイから事前にフィルタしちゃえ」 みたいな話だったりするわけです。なんとかプログラムの本体には手を加えずに、 入力で何とかするのが「汚染除去」みたいな話。 で、実際にそういうことをする gateway とかもあるみたいなんですが……確かにしょうもないよね。 まぁ今目の前にいるクラッカーと、手元にいないプログラマという状況でなら 仕方がないと思うけど、これから書く新しいプログラムに適用するような話じゃない。

大体そんな汎用でそれっぽい「汚染除去」したところで、「間違ってる」プログラムが 正しく動く保証はないわけですよ。そんなこと言い出したら、 「パス名インジェクションが怖いから ../ は全部削る」とか、 「SQL の数値フィールドに埋め込まれると困るから数字以外は全部削る(!)」とか、 あり得ないことやらないと安全じゃなくなっちゃう。

で、この手の誤動作に対する本来的な対策は、

「入力の正当性チェック」+「出力時の正しいエンコード」

に尽きると思われます。で、それらは本来「サニタイズ」という概念じゃないでしょ、 ということかなぁ。 もはや「やばそうな入力から毒を抜く」という処理はしていなくて、 「正しくない入力を拒絶する」「正しいデータが次段階に渡るようにデータを符号化する」 わけで、この下線部の違いは概念的にはかなり大きいと思います。

入力の正当性チェックというのは、文字列型の値の場合はほとんどないわけですが、 数値型の値(で Perl とか型のしょぼい言語を使っていると)なんかだと重要ですね。 たまに「じゃぁサニタイズしないで " とか入ってたらどうするんだよ、 数値項目は SQL エスケープできないじゃないか」という話があるようですが、 上にあげた「正しい対策」で言えば答えは単純で、 「そもそもなんで入り口で数値でないことをチェック (あるいは、そもそも数値型に変換) してないの?」 という話ですし、敢えて言うなら出力時は「型変換エラーの例外を送出」が 正しい処理だと思われます。

えびさんの気にしていた「パス名チェック」は、多分「文字列」としての値と、 実際にセキュリティ上許される「パス名」の範囲が一致していないわけですから、 「入力の正当性チェック」の概念でいいと思います。 それを「サニタイズ」というのは、概念が広すぎるのではないかと。

実際とある CGI の動作を調べていて、普段は16進数表現の値の渡るパラメータに /etc/passwd とかを渡したところ、サニタイズされて "%2Fetc%2Fpasswd" なんてファイルはないよ、 と返ってきた事がありますが、これってそもそも「変な値渡すなゴルァ」という 返事をするのが正しい設計ですよね。そりゃ大きな問題はそれでも生じないし、 CGI::escape って書くだけで実装楽なのも判るけどさー。

で、それぞれの処理の段階で、「どのデータがどういう『型』か」を意識していれば、 それぞれの処理はほぼ一意に決まります。もっとも型の決め方には多少の任意性があって、 例えばある数値を第1CGIから第3CGIまで渡す必要があって、第2CGIは素通り というケースでは、第2CGI中でこの値を数値として扱っても文字列として扱っても、 どちらかに統一されていれば問題ないでしょう。

上の話とも関係するんだけど、結局高木さんも言われている通り、 SQL injection でも XSS でも、 データの「型」というか「値域」をちゃんと意識していれば、 正しいプログラムは自明に書けて、バグなんて引き起こさないはずなんですよ。 バッファ溢れにしても同じで、この入力が何バイトまで伸びるか、というのを 想定してプログラム書いていれば、別に IDS でフィルタしなくたって 正しく動作するんです。 逆に、それを意識しないで「サニタイズ」「無害化」「闇雲にエスケープ」とか やっていると、「記号を入れられないショボいパスワードシステム」とか、 上に書いた「&amp; 症候群」とか、そんな逆方向のバグも発生します。 2重エンコードはまだいいけど、2重デコードはセキュリティホールになるしね。 その辺の意識改革は、まだまだ時間かかるのかなぁ。

[Security] 安易なサニタイズは危ない?

で、サニタイズみたいな処理って、安易にやるとそれはそれで 脆弱性生んだりするよ、って話も(ちょっと無理があるけど)挙げておく。

半月前に セキュリティホール memoで話題になった HTTP Request Smuggling。 要点は「Keep-Alive が有効なときに、ProxyサーバとWebサーバで HTTP プロトコルの解釈が食い違っていると、 URLとコンテンツの対応が崩れるのでいろいろな攻撃ができるよ」ということなのだが、 主立った攻撃手法が2つあって、 1つは、Content-Length ヘッダを2つ忍ばせておくと、proxyとwebサーバで違う方の ヘッダを見てしまって、その後のリクエストの対応が崩れるという話。これはまぁ 正当でない HTTP request を転送してしまう Proxy のバグといってもいいかも (まぁ、指摘されないと気付かないようなバグなので仕方がないとは思うが)。

で、問題はもう1つの方で、Microsoft の IIS が、Content-type で明示的に Form データである事を指定しない限り、リクエスト読み込みを 48Kbytes で強制的に 打ち切ってしまう、というもの。どうせ「それ以上長いリクエストは不正な攻撃だろ」とか 考えてフィルタしてるとか、そういうしょうもない理由だと思うのだが、 悪いことに前のリクエストの 48K+1 byte 目からを次のリクエストだと思って 解釈してしまうので、HRS が起こる………っておい。 Content-type が違うリクエストは HTTP 的には正当なので、これは明らかに IIS が引き起こしているセキュリティホールで、こんなのに付き合わされる proxy の実装者が気の毒だなぁ。

この手のバッファ長切り捨てって結構やりがちで、たとえば while(gets(buf) != 0) ... 系のコードを書き直すときに、 while(fgets(buf, 512, stdin) != 0) ... とかやるわけだけど、 本当に 512byte 目以降は次の行になっちゃっていいんですか? ってのは 結構見逃しがちじゃないかな。データの受け側が勝手に決めた既定長以上の要求を 切り捨てるときは、エラーを返す *1か、 溢れた分は黙って読み飛ばすか、どっちかの処理をしないといけない。かつ、切り詰めたせいで 意図しない動作が起こらないようにするのも受け側の責任。 脆弱性まで行くケースはともかく、意図しない動作で使い手に迷惑をかけるってのは 結構ありがちなんじゃないかな。指定したつもりと違うファイルに書いちゃうとかさ。

自分も昔は↑みたいな荒いソース書いてたけど、最近は1回は「本当にそれでいいのか」 って考えるようになった。もちろん自分しか使わないツールとかなら大した問題じゃないんだけど、 人が使う可能性のあるツールを書くときはかなり慎重になる。 *2

まぁ、バッファ長制限はある程度やむを得ない面もあって、例えばいくら 「長さで一律に切るのは正しい input validation ではない」といっても、 100GB ものリクエストが送られてきている場合、どこかで切断しないことには メモリ足りなくなったりするわけですが、そういう場合の切り方もちゃんと気をつけましょう、という話でした。 データの中身見ないでこの手の処理を安全にできる、ってのは幻想でしょう。 ま、「1リクエスト全部止めちゃっていい(そして、次のリクエストは読んでも問題ない)」場合なら 比較的簡単 (Web 系だとそういうのも多いかな?) ですけど、一般にはそうじゃないケースもありそうだしね。

*1 IISの場合だったら、次のリクエストが把握できないので keep-alive を拒絶して切断する。 HTTP keep-alive は、たとえクライアント側が次のリクエストを既に送出していても、 サーバ側が "Connection: Close" ヘッダを返して一方的に切断していいことになっているので、 これで問題ない。

*2 というわけで、例のスクリプトのゴミ箱に投棄しているような スクリプトがずっとお蔵入りになっていたのも、書くときにそういう配慮をしていないから 公開するのが怖い、という理由が大きかったんだよね。今回は敢えて「as is」で放出しているからして、 ちゃんと中身読んでから使ってくださいね :-)

本日のツッコミ(全2件) [メッセージを送る]

(わ) [List.rev が面倒だという話がありましたが、Queue は駄目なんですか? ]

おおいわ [おお、そんなものが……と一瞬思いましたが、最終的に List として取り出せないんですね。最終的には Queue の..]


2005-07-19

[Misc] 送別会

大学の研究室のポスドクの先輩が研究室を離れることになったので、 送別会にちょっと遅れて合流。 上野で2次会まで飲んで帰ってきた。酔〜。

酔った勢いで英語を書いてみたが、明日読み返してみてどうなっていることやら(笑)。

[Security] セキュリティ情報の連絡先は目立つところにヨロシク

今年の Linux カンファレンスの鯰の中の人のtalkを見た。 とりあえず1頁目の鯰が可愛いとか、4頁目が何故「高橋メソッド」なのかとか、そういうのは置いておくとして :-)、 5〜6頁と24頁辺りに注目。

実際最近いろいろ調べているついでに気になっているんですが、 純粋に個人でメンテナンスしているソフトウェアはいいとして、 所謂オープンソースで「バザール的開発」しているソフトウェアでは、 バグレポート窓口が公開開発者メーリングリストになっているケースって すごく多いです。これは日本に限った傾向でもなくて、 海外でも結構あります。Bug tracking system しかないところも 結構ありますね。 また、専用のセキュリティ情報窓口を用意しているソフトウェアでも、 一番上位から素直に入れる bug tracking system の辺りに 情報がなかったりすると、非常に悩みます。 そのたびに、まず現在のメインのメンテナが誰なのか調べて、さらに その人のアドレスを個人ページまで辿って調べるとか、 逆にそこまで深く辿っちゃうとそもそもその人で正しいのかなぁ、とか、 悩み所満載です。

Debian なんかはセキュリティ情報処理体制は(人手不足はともかく)整ってるから、 ちゃんと書いてあるかなぁ、と思いきや、少なくとの日本語のバグ報告ページには 書いてないんだよねぇ……。BTS に投げたら公開されちゃうんじゃないのかなぁ? 正解はどうやら「セキュリティ情報」 「セキュリティチームFAQ」と辿った ところに書いてある問12の ようで……ってさらに1つ上には2つもアドレスが書いてあって、差が良く判らないよ……。 「『team@ほげほげ』の方が無難」というのは辛うじて判ったけどさ。 この情報をFAQで済ましちゃうのはちょっと手抜きのような気がするなぁ。

その点、今回(やっと?)整備された Ruby のセキュリティ脆弱性情報の 受付窓口なんかは、 トップページからリンクされていて、 かつ非公開MLであることと対策後に公開することも明記されていて、 割といいんじゃないすかね? 敢えて言うなら今まで無かったのが(略)ではあるんですが、まぁ 「Ruby とは?」のページに作者のアドレスが明記されてるんで、 個人的にはあまり困らなかったっちゃ困らなかったかも。

そういえばIPAの脆弱性報告フォームには「作者への連絡手段」は書く必要がないんですよね。 IPAの担当の方ご苦労様です。


2005-07-20

[tDiary] tDiary 2.0.2

出ました。 早速自分も入れ替え。

一瞬バージョン番号が書き変わらなくて悩んだが、FastCGI を使っているので ruby プロセスを一旦 kill しないといけないのを失念していた(汗)。

関係者のみなさまお疲れ様でした。

[Misc] SSH brute-force attack 来たる

ええ、妙に某マシンに入力パケットが来続ける (200〜500bytes/sec) ので 調べてみたら、ssh ポートに大量の通信が。 定常的なので最初は継続的な通信かと思いなんか鍵でも盗まれたかと思ってビビったが、 良く見たら全部ログイン失敗してるんで、単なる接続試行だったようだ。 whois で見たところそのマシンには接続する必要がない海外のホスト群だったので、 纏めてネットワークごと封鎖……したところ、直後に今度は 3〜5kB/sec の 猛烈な攻撃が来た………。

……こちらもとりあえずの対抗措置は施したけど、このあとどうしようかなぁ。


2005-07-21

[Misc] 追記

akr さんからの参照を受けて、 7/18日の「XSSとHN」エントリに追記。 僕は HTree のそれは実質的には構文木データを返す関数型なのかなーと思った。

HTree の _call の場合はテンプレートの中で呼び出すことになっているので、 組合わせ方法のロジックが全部テンプレートの側に入ってしまうのが 不便じゃないかなぁ、と思ったりするが、 それ以外はほぼ僕の要求を綺麗な形で満たしているなぁと思う。

テンプレートから HTree::Doc 吐けるんだったら、 それを変数に置いておいてそのまま他のテンプレートに埋められたら……ってできるのかな? やっぱり使ってみないとわからないからちょっと HTree 使ってみようかな。 ……ってだから遊ぶ時間がないのよ (;_;/

[Misc] 忙しいって……

結局10時になってから(10時過ぎると夜勤になっちゃうので)帰って、 地元の定食屋で食事にありついたのが10時半。 最近妙に店のおじさんに顔を覚えられている気がするのだが、 今日はお金を払うときに声をかけられた。

「こんな時間まで仕事?」

「忙しいねぇ」

「いいねぇ」

……うん。忙しいって素晴らしい。

本日のツッコミ(全2件) [メッセージを送る]

(わ) [寝る前3時間はものを食べない/糖分を摂取しないという鉄則があります。この規則への compliance は就職後半年..]

おおいわ [ええと、この日は結局寝たのが3時回ってたので、compliant ですね……ってなにか間違えてる気がしなくもない。 ..]


2005-07-22

[Misc] 1週間終了

……というわけで、相変わらず忙しかった。

なんか来週も忙しそうな予感がするぞ。

[Misc] バックアップ

そろそろ研究所だけにあるデータというものが多くなってきた *1ので、 バックアップを取り始めることにした。

といっても自分一人の割り当て予算でテープ装置を準備するのはキビシイので、 とりあえずDVD-Rに焼き焼き。こういうとき、スクリプトが自在に使えると 一旦準備しておけばスクリプト一発叩き込んで 15分位サボるマシンを使わない他の作業をするだけなので 楽でいい。

*1 大学時代の研究の延長にある研究については、家と研究所に常にミラーリングする 体制ができているので、基本的にどちらかのマシンが壊れても困らない。


2005-07-23

[Misc] 無為な1日

そして、土曜日なにも実のあることをしないパターンをまたやってしまった。 この辺りの体調管理は社会人としての今後の課題だろう。

ぼーっとしていると突然巨大な揺れに襲われてびびる。


2005-07-24

[Misc] [Book] 買い出し

いい歳して忙しくなってだいぶ趣味も変わってきてるんですが、 コミックだけは抜け出せないどころか、むしろ収入が増えて悪化しているような……。 今月は偶然だが続けて買っている8作品中6つも一月に集中してしまって大出費……。

読むの? ...

しかし、だんだんとこの「こめんと」でしか面識のない、リアルなおおいわを知らない読者の方々が増えて来ると、この手のネタはここに書きづらくなってくるなぁ。どうしよう…。

[Misc] tDiary 2.0.2

なんとなく日常の巡回範囲くらいの tDiary は大体更新されたっぽい。 当たり前だがみんな素速いなぁ。 同時期にでた Hiki のほうは…… google で見るとなんか全然なのだが、 これは Hiki vs tDiary の差なのか、一般的ユーザ vs 僕的巡回範囲ユーザ の差なのか微妙。

まぁ Hiki を含む Wiki 系ツールの場合、「普段は管理者もログインしないで使う」ような 運用ならあまり問題ないんだけどね。 tDiary は「基本的にログイン必須」とか、「Basic 認証なのでログアウトしづらい」 とか、他にも細かい点でいくつかとか、アプリケーションの性質として CSRFの被害を受けやすい特性を持つので、アップデートを強く推奨します。

ちなみに、今回の修正の技術的要点をいずれちゃんと書いておかなきゃと 思っているのだが、どこにどうやって書こうか思案中。 tDiary のように複雑なツールで、かつ Basic 認証ベースなものでは、 結構微妙なツッコミ所がいろいろあって、 それぞれにきちんと解答を用意したつもりなので、 論点の整理を一回やっておきたい。

本日のツッコミ(全3件) [メッセージを送る]

(わ) [大極宮の古い方のバックナンバーの「安寿=宮部みゆき」が書いている日記「ゲーム女のひとこと」を読むと大いに勇気づけられ..]

K_O_ [まんがの6冊やそこらなんて、英語の専門書を数冊買うのに比べたら誤差でしょう。或は一回余分に呑みがあったと思えばいいの..]

ゆーな [ほら、それは聖地アキハバラですから……。 ]


2005-07-25

[Misc] ダイビル前信号機設置

今日はまた写真特集。

事の始め

…は7月12日だった。ふと見下ろすと、なんかごそごそやっている。
仕事の合間に降りていくと、目の前のガードのところで 信号機の設置工事をしていた。 東側はJR山手線のガード、西側と北側はUDXの歩道橋、 南側は駅前広場からの急カーブとすべて見通しが悪いので、 やたらと台数が多い。
ガードの方から見るとこんな感じ。
なんか見たことのない形なんだけど、新型?
こんな箱に入ってるんだねぇ。
カバーがかけられて暫しお休み。

ここ数日

なんか事務机にいかにも式典用っぽいスイッチが設置されていたのだが、 なんか点灯する気配がないぞ。予行演習か? 人がいないのでじっくり観察したところ、この手のスイッチは 直列繋ぎであることが判明。:-)

今日

通勤してくると……、なんかテントがでてるぞ。信号のカバーも取れてる。
ここ数日時々見掛けたあの机がっ。ふーむ、15000台目をここ秋葉原にしたのか。 この数字ってやっぱり東京都内の台数なのかな。
なんか展示してました。式服(?)な白バイ隊到着。

仕事場でしばらく仕事をしていたところ、なんか外が騒がしくなってきたので 窓から見下ろしてみる。

いつのまにか路面表示も引き直されて、左折レーンができていた。 こっち側の横断歩道も設置された。
……騎馬隊まで来てるっ。
そうかぁ。騎馬隊が来るためにはこういう人も必要なのね……。
……なんか来てるぞ(笑)。交通少年団と一緒に渡り初め……なのだが、 さすがにこの角度はガラス越し撮影はきつい。直接光と2回反射光とで 2重に見えますね。
パレード開始。まずは白バイ隊。ついで横断幕。
なんか目撃証言によると、「さとえり」とかいう人が来てたらしいっす。 それって誰?(ぉ
儀仗隊と音楽隊。さすがプロって感じの揃った足並みがすばらしい。
続いて少年たち。素人らしくほほえましいほど気儘な行進 :-)
ついで騎馬隊。プロ……なんだがご機嫌斜めで結構苦労してのかも (^^;
中央通りを封鎖してパレードしてた模様。渋滞〜。
ピーポ君はパレードには参加せず。おっちゃんに揶揄われるピーポ君。
横断歩道は手を挙げて渡りましょう。(笑)
蒸し暑い中お疲れ様でした。
本日のツッコミ(全1件) [メッセージを送る]

(わ) [ピーポ君は警視庁のマスコットだから、都内なんでしょうね。 ひとつの十字路に4台ずつだと思うと、十字路の数が4,00..]


2005-07-27

[Misc] 新種の歩行者用信号機

本当は昨日貼り付けるはずだったのに、カメラを研究所に忘れた……。

というわけで、一昨日点灯した信号の写真。

とりあえず交差点全体。一見普通の LED 信号のようだが……。
青になると上のところに残り時間表示が出る。
全部消えると点滅開始。
赤信号も同様。今度は下の部分にバーが表示される。

全部消えると青に戻る。
銘板も撮ってはみたけど雨で写りが悪くてイマイチ。

[tDiary] ライセンス話

tdiary-devel にいきなりキッツいメールを投げてしまった。もうちょっと書き方があったかなぁという気もする。

まぁでも、書いた内容自体は妥当なものだと思う。 Debian パッケージ等の関係で今ライセンスを整理しなきゃという気持ちはすごくよくわかるんだけど、 ライセンスが判らない(けど再配布自体はOKと推認できる)ものを再配布しているのと、 それにGPLという特定のライセンスを勝手に適用するのとでは全然意味が違う。

このまま推し進めてしまうと、 下手をすると、たださんが著作権侵犯の汚名を被るとかじゃすまなくて、 tDiary 自体がオープンソース失格の烙印を押されるとか、 Debian から追放されるとか、そういう話になりかねないネタなので、 ちょっと慎重に考えて欲しいと思ってメールを書いた。 別に喧嘩を売りに行ったわけじゃないので、理解してくれると嬉しいな。

追記 (7/28)

たださんが改めてライセンスの確認作業に着手する意思を示してくださったので、 この項は解決。英断に感謝。しかし、5通か……。

その前のGPLのメールはかなり慎重に書いたが、難しいねぇ。いくつか批判は想像できる。

GPL FAQ がある意味で「unfair」であるというか、実体は FSF の主観的な意見表明である というのは、内容を良く読むと所々矛盾している(例えば、GPL と GPL-compatible がごっちゃになってる) とか、論理が飛躍しているとか、FAQ なはずなのに文中でクローズドソースに喧嘩売ってる(笑)とかで 判ると思う。別に文書のすべてが客観的であるべきだなんてこれっぽちも思っていないので、 これが「FAQ」じゃなくて「FSF's position」って名乗っていれば、 堂々と unfair 万歳なんだけどねぇ。 但し、今回の内容では、別に FSF 解釈を全否定する必要はないので、 あくまで「隠された本旨を慎重に読解する」というレベルの解釈をしたつもり。

あと、GPL の derived work 周りの解釈を考えるときに、 LGPL で追加されている条文の裏を読むってのは有効かも、とちょっと思った。 非公開ソフトとのリンクを明示的に許可する言い回しを読むと、 「GPL ではなぜ許可されないと論理づけているか」が見えてくる気がする。

しかし、独立性のあるコンポーネントを統合するときのGPL FAQ流の解釈は、 いろいろと反対解釈をする余地があって、悩み所がいろいろありそう。 敢えて悪く言えば FSF の拡大解釈誘導ぶりが見えてくるなぁ。 次に来るといわれている GPL3 でその辺りは整理されるのだろうか。

ちなみに、今回の tDiary の CSRF 対策部分ですが、あくまで個人的な思案としては 基本的に public domain 的にする方向で考えています。 この手のセキュリティ対策ってのは所詮使ってもらってこその存在なので、 GPL の縛りをかける気はないです。 需要があるようなら tDiary 本体との切り分けは整理するけど、あるのかなぁ。 セッションID使っているアプリにはシンプルな別解があるしね。

本日のツッコミ(全1件) [メッセージを送る]

こんの [メリケンの信号機に、残り時間が数字で 表示されるものがあったのを思い出しました。 でもこれって残り11秒といってい..]


2005-07-29

[Misc] 3DES

最初はとりあえず情けない話。

週末の疲れきった頭で D 論より厚い SSH2 の仕様ドラフトを読んでいて、

Note that since this algorithm only has an effective key length of 112 bits ([SCHNEIER]), it does not meet the specifications that SSH encryption algorithms should use keys of 128 bits or more.

とかいう行で眼が止まってしまった。文献引用までされているので 一瞬ビビってしまったが、文献リストを見るとこれ、

[SCHNEIER] Schneier, B., "Applied Cryptography Second Edition: protocols algorithms and source in code in C", 1996.

論文じゃなくて教科書か参考書っぽいね……。と思ったところで ハッと気付いて見れば、112 = 56 × 2 というわけで、 とっくの昔に既に知っている話だった。最初に止まったところで思考停止してしまって、 気付くのに30秒もかかった自分が情けない orz。 やっぱり疲れてるときに余計な事するもんじゃない。

一応解説じみたことを書いておくと、日本語の Wikipedia には全く書いてないのが謎なのだが、 オリジナルの Wikipedia にはちゃんと書いてある、 いわゆる "Meet in the Middle Attack" と 呼ばれる3DES 暗号の構造的問題に起因する攻撃の話。通信の一部について平文と暗号文の組合わせが判っている 時に、256 オーダのメモリ量と 2112 オーダの時間量で鍵長 168bits の 3DES を破って 鍵を入手できる。

やり方は割と単純で、3DES は3つの鍵を順番に適応するわけだが、 まず暗号結果を 256 通りの第3鍵で復号した結果をソートした辞書を作っておいて、 一方で元の文を 2112 通りの第1・2鍵で総当たり的に暗号化して一致を探す。 但し、2168 通りの鍵の可能性を探索するわけなので、 元の文章が 1 ブロック (264 ビット) だけだと、 大体 2104 個もの鍵候補が一致してしまう。 誤ヒット率が高すぎると確認に手間がかかってしまうので、 ここではとりあえず 3ブロック (192 ビット) 使うことにしておこう。 *1

そうすると、ブロックサイズが 8bytes なので、必要な記憶容量は鍵を入れて 256 × 32bytes = 2EBytes (合ってるかな?)。 我々には気の遠い記憶容量だが、まぁ 112 bit の鍵を全探索しようとする人なら これくらいのディスク容量は用意するできるかもねぇ。ちなみに当然だが、記憶容量を半分にすると 時間は倍かかる (2回に分けて半分ずつ探索するから)。

ちなみに同じ理由で 2DES だと 256 回で破れてしまう事になる。

これもちゃんと例の原稿の補遺に入れておくべき話だな。 「暗号に問題がなければ強度は鍵長に依存する」とだけ書いて、 この手の「問題がある」ことに触れてないのはちょっとまずいかもね。

しかし、SSH2 のドラフト、本当にぶ厚いんだけど (a2ps の2段組み標準フォーマットで177ページ)……。 なにこれ……。

追記 (6/30)

折角なので、極めて怪しいが、必要なDES操作回数を見積もってみた。 めんどくさいのでとりあえず ECB モード。 パラメータとしては、中間辞書を何ブロック (n) のデータで作るかと、辞書に元の56ビット鍵を記録しておくかどうか。 結果が正しいかどうかの検証は3ブロック調べればよいことにする。 なおここでは差分を見るために、普通は「無視される」量も計算している。

まず、辞書の作成には、当然 n・256 回のDES操作が必要になる。 記録に必要なバイト数は、鍵を記録する場合が (8n+7)・256、しない場合は 8n・256

さて、次に、2112 回 2DES 暗号化して辞書内のデータと比較するわけなのだが、 その操作に必要な 2DES 操作の回数は次のように考える。

まず、第1ブロックについては素直に 2112回。 ここで、第1ブロックの値と一致するデータが辞書に登録されている確率は、高々 256−64 = 2−8。よって、この時点で一致しなければ 第2ブロック以降は処理する必要がなく、第2ブロックの処理を要する回数の期待値は 2104 回程度。 第3ブロックはもっと少なくて、240回程度。

DES 操作回数はちょっと考えるのが面倒だが、 第1ブロックは2重ループなので、256 + 2112。 第2ブロックは、結局回数から言ってほぼすべての第1鍵に対して処理されそうなので、 256 + 2104。 第3ブロックは、必要回数のほうが少ないので 2・240 と考える。

そうやって n ブロック処理した結果、 ある 2DES 鍵でランダムに辞書エントリに誤ヒットする確率は、取りうる値の種類の数と辞書のエントリ数に依存するから 2(56−64n)。 これを 2112 回比較するわけなので、誤ヒット数の期待値は 2(168−64n)

ここで誤ヒットすると、これが誤りであることを調べるために、 鍵が記録されている場合は残りの (3−n) ブロックについて 3DES の処理をして確かめる必要がある。 もっとも、大抵の場合は最初のブロックで不一致が検出できる (というか、最初のブロックの処理量に対して、次のブロックの検査の必要回数は無視できる) と思われ、その場合 3・2(168−64n) 回のDES操作が必要。 正解については定数回なので無視。

一方で、鍵が記録されていない場合、まず3ブロック分の 2DES 結果を求めたあとで、 256 個の取りうる第3鍵について全部調べてハズレであることを 確かめないといけない。この時、第1ブロックがたまたま一致して第2ブロック以降でハズレる可能性は 第1ブロックの処理回数に対して無視できるので、第1ブロックのDES操作だけを数えることにして、 2(168−64n)×256 = 2(224−64n) 回のDES操作が必要。 それに加えて、正解について鍵を求めるために平均 255 回の検証が必要。 (第1ブロックの不一致で不正解はほとんど跳ねられるとする。)

で、これを整理してみる。表記が煩雑になるので [n] = 2n とする。

n鍵記録PBytes前処理 中処理 後処理 合計
1× 0.5[56][112] [56] [160] [160]
11.0[56][112] [56] 3[104][112] 1.5[105]
2× 1.02[56][112] [104] 2[56] [96] [112] [104] [96]
21.52[56][112] [104] 2[56] 3[40] [112] [104] [58]
3× 1.53[56][112] [104] 2[56] 2[40] [55] [112] [104] 1.4[58]
32.03[56][112] [104] 2[56] 2[40] 3[−24] [112] [104] 1.3[58]

当たり前だが、折角計算したわりには 2112 に全部マスクされてしまった(苦笑)。 最初の以外はどんぐりの背比べなんだな(笑)。まぁ、差分として、確率の低い衝突のために 3ブロックの辞書を準備する必要はない、ってことは判るか。 あと、常識的に考えると普通は辞書エントリに対応する第3鍵は記憶しておくものだと思うが、 実は計算量オーダ変わらないから記録しないでメモリ節約する、ってのもありなんだねぇ。

うーん、本当にあっているのかイマイチ自信が持てないぞ。

*1 この辺、昔自分で書いた 2DES の破り方のサーベイを元にアレンジして書いているのだが、あってるかな?


2005-07-30

[Security] CSRF のセキュリティ脆弱性としての評価基準

CSRF について Web の過去の記述をいろいろ漁っていたのだが、 やっぱり tDiary のCSRFに対する脆弱さは2004年9月の段階で既に知られているのね。 っていうかまぁみんな気付くよね。対策されなかったのはやっぱり脆弱性の強度が理解されていなかったからか。

いしなおさんが 2.0.2 公開直後 に書いているが、

CSRFに対する脆弱性(フォームの送信元がどこであれ、送信先(action)とパ ラメータが正当ならばそのリクエストは正当と扱う、という標準的な仕様)は、 おそらくほとんどのWebアプリケーションが抱えていると思うんだけど、どの 辺から脆弱性扱いされる範囲になってくるのかな。 「少なくとも認証によって保護された機能については、CSRFによって呼び出しが可能であってはいけない」 ってあたりかな。

という疑問はCSRFには常にあるわけです。別によそのフォームからの クロスサイト・リクエストを受け付ける仕様自体は常に脆弱性というわけではないですよね。 例えば、「ばんばん投票フォーム設置してくださいー」みたいなものもありますし。 問題があるとすれば、やっぱり「認証情報が付加される」というところがキモなわけで、 「任意のリクエストに認証情報が付加されて外から投げ込まれたときに、何かまずいことが起こるのに 対策されていない」のがセキュリティ的な問題に相当します。 従って、CSRF脆弱性の「深刻さ (Severity)」は要するに「まずいこと」の深刻さに依ります。 僕は大体次のような分類をしています。

あ、断っておきますが、以下は人のソフトに対する脆弱性を評価するときの 評価基準です。自分で書いたソフトの場合は、3. までは当然ながらきっちり直します。

1. 深刻度・高: 不可逆な操作

少なくとも僕は、「何か取り返しのつかないやばいことができるとき」はセキュリティ脆弱性と呼んで、 可能な限り届け出ることにしています。「取り返しのつかないこと」という表現は 高木さんが使っていたのですが、例えば

  • 「任意コードのサーバ側での実行」
  • 「パスワード以外の秘密情報(読者からの秘密コメントとか社外秘のコンテンツの内容とか)が読めてしまう」

ですね。tDiary はこの1つ目のケース。「SNS で招待状を出せてしまう」とか 「ワンクリックで物が買えてしまう」も、場合によってはここに入ります。

CSRFによって発動するクロスサイトスクリプティングも、 同一ドメインで別の cookie などの認証を使うアプリを利用している場合は 悪用しうるので、このレベルと同等程度の深刻さはあるかも知れません。 これは運用に依存しますが。

2. 深刻度・中: 半恒久的な侵犯

次にやばいケースは、「半恒久的なアクセス権限の窃取」です。

  • 「Webアプリの独自認証のパスワードが読める」
  • 「パスワードを変える事ができる」

とかです。この場合は僕はケースバイケースですね。 シェルの権限が取られていない限り、取り返しがつく場合も多いでしょうから。 とはいえ、間違いなくセキュリティ脆弱性ではありますし、秘密情報を扱う ソフトでは、管理者権限を得たあとは秘密情報にアクセスできる場合が多いでしょうから、 かなりの確率で上のケースに昇格します。 *1

7/14 に公開された Hiki は基本的にはこのレベルなのかな。 というのは、Hiki には凍結機能はあっても、 特定のユーザにしか見えないページという機能はないようなので。

3. 深刻度・低: 一時的な侵犯

次は、「一時的なアクセス権限の窃取・悪用」です。

  • 「日記に『はまちちゃん』って書ける」
  • 「日記の特定エントリを書ける・消せる」

とかで、これは脆弱性ではあると考えられるけれど、セキュリティ的な深刻さは比較的低いと考えています。 基本的にはヤラレテも「はっはっは、やられちゃいましたー、あれ僕の意見じゃないですー」 とカミング・アウトすれば済む場合が多いからね。 自分の使っているソフトでこれが問題になる場合は、 こっそり直して「直したよー」って作者に教えるレベルかなぁ。 *2 日記が消せるってのは、ちょっと取り返しつかないかなぁという気もするけど、 一番上の事例の「取り返しのつかなさ」とはレベルが違うと思うんですよね。

このレベルで被害が収まると判断された場合は、僕は現状ではスルーしてます。 CSRF の脅威が不用意に扇られたり、あるいは不当に低く評価されたり、 緊急度が低い脆弱性に対して一斉に「今すぐ対策しろー」の圧力が浴びせられたり、 脆弱性情報取り扱い機関がパンクするのはいろいろと良くないと思うので。 実際、CSRF が荒し対策だと思われた時代はかなり続きましたからね。 数が多すぎて、注意喚起みたいな形ならともかく個別には 対処しきれないという現実もあります。

但しこれは「対策しなくていい」と言っているわけではありません。 自分の日記が消えるなんてのは日記ソフトとしては欠陥品ですし、 それを許容できないってユーザは多いでしょうから、 作者さんにはこのレベルの問題もがんばってちゃんと直して欲しいね。 ユーザへの告知もちゃんとやって欲しい。

4. 深刻度・些少: 非権限的な操作

で、最後が「権限の不要な操作の発動」です。例えば、

  • 2ch に「はまちちゃん」って書ける
  • Wiki に勝手にページを作れる

みたいなケース。これは基本的にはセキュリティ脆弱性じゃなくて、 作者さんにとってもケースバイケースでいい事例と考えます。 「Cross Site Request Forgery」という呼び名で呼んでしまうと該当するように思えるけど、 別名の「Session Riding」には該当しませんよね。

まぁでも例えば 2ch のような有名サイトだとそれでも実害(アクセス過多とかスレ埋め立てとか)が 出るんで対策の必要がでてきますが、 これはもう「脆弱性対策」じゃなくて「荒し対策」の範疇でしょう。 2chの場合は「fusianasan」問題もあるけど、個人的には fusianasan はそれ単独では 「取り返しのつかないこと」じゃないと思う。トリップとかと組み合わせられると 嫌だけど、CSRF ではそれはできないので。

もっとも、荒し元のIPアドレスが追跡できなくなりますから、 荒し対策が必要な場面ではCSRF対策と同様の対策は施しておくべきケースが多いでしょう。

[Security] [tDiary] tDiary の CSRF 対策の技術的ネタバレその1

ちなみに、1年前の記事にコメントつけるのは本人もう気付いているかも知れないのでアレかもしれないけど、 「ツール側の対策」の PATH_INFO 案は駄目です。というのは、日記編集画面の「本日のリンク元」や「ツッコミ表示設定」 、あるいはプレビュー中の日記本文から Referer で漏れます。技術的には外部に見えない秘密のデータをリクエストに埋め込むという点で、 今回の CSRF 保護キーとほぼ同じですが、このような手法を取るためには この秘密のデータは徹底的に秘密にしないと駄目なんです。 セッションIDをURLに埋めるのが良くない、ってのと同じですが、 この場合は恒久的IDなんで影響はさらに大きいです。

あと、今年の 7/21 のエントリで、これももう気が付いているかも知れませんが、 僕は Referer チェックは切る必要はないと考えているんで、 基本的には設定画面で切ったつもりでも切れていません。 設定画面で設定できるのはあくまで、空白の Referer を許容する設定です。 変な Referer からリクエストが飛んできた場合には、やっぱり拒絶されます。 どうせ正しい Referer を tDiary が誤判定するような状況では、 tDiary の他の部分にもいろいろと影響がでるんで、ちゃんと根本原因を 直してください、っていうことです。 直し方については tdiary.org の説明を参照。

本当に自分用スタートページに日記更新フォームを設置しているなどで、 どうしても Referer が異なるリクエストを許容したい場合は、 tdiary.conf.sample を見て該当する隠し設定項目を探してください。 ちなみに2通りありますが、正規表現が絡む方です。 もう一方は CMS としての squeeze.rb の利用を前提に、 完全に CSRF 検査をバイパスする設定なので、使わないように。

*1 また、認証済ユーザしか触れない設定の辺りは、いろいろなセキュリティチェックが 甘いことが多いので、複合技で上のケースに相当する場合もあるでしょう。

*2 当然ながら、カミング・アウトによる否認が許されない場面では、最上級の脆弱性になります。

本日のツッコミ(全15件) [メッセージを送る]

Before...

おおいわ [今試してこようと思ったら、うちのプロバイダ荒し規制されてた(苦笑)。 # 結果として無書き込みでテストできたので、結..]

高木浩光 [おっとそうですね。間違えました。cookie