がるの健忘録

エンジニアでゲーマーで講師で占い師なおいちゃんのブログです。

セキュリティ関連色々と(セッションIDとCSRFと暗号と)

んっと。先日書いたお話…おもったよりもあちこちで火の手が上がっております(苦笑
まぁ興味ありありのネタなので、色々と。
…微妙にBlogの趣旨からずれますが、まぁ頑張って沿うようにしてみます。


まず、高木先生の記述。しばらく日記をちゃんと書けそうにない( http://takagi-hiromitsu.jp/diary/20060121.html )。
一つだけ、反論……なのかなぁ?


まず、cacheは禁止するのが当然であり、cacheを禁止してもcacheに残る場合というのは、Webアプリケーションの責任ではない。残るような製品の脆弱性である。

んっと。理解は出来るのですが(ただ、確かRFCではSHOULDレベルだったような…記憶が甘いんですが)、現場としては「それでもなお」それを考慮せざるを得ない状況もあるので。
できれば一蹴して終わるのではなく、もうちょっと考察を重ねてもらえると嬉しいなぁと。
とはいえ、どのみち、cacheが残るようなら「hiddenだろうがCookieだろうが」というレベルではあるので。
認識としては
・hiddenのほうがより安全である「可能性」がある。ただし「どのみち一緒」である可能性が残ることを意識する
ってのが現場的発想でしょうか?
以上が、私から高木先生への、唯一反論めいたコメント。


んでまぁ次はGIJOE氏への反論なのだが。…申し訳ないのだがたんまり。
「しばらく日記をちゃんと書けそうにない」への反論 ( http://www.peak.ne.jp:8080/xoops/modules/news/article.php?storyid=82 ) より。

まずここが嘘です。セッション固定とセッションハイジャックは別物です。
単にIPアドレスをセッションIDに結びつけておくだけで、セッションIDが外部に漏れたとしても、セッションハイジャックされないシステムは可能です。

致命的。
まず「正規ユーザのIPアドレスが常に固定である」が必ずしもtrueにはなりえない(実際、過去にこれでえらい目に会いました(苦笑))。
そのために、下手に結びつけると「正規のユーザが(大抵は、ある特定のISPから、なのだが)セッションを維持できない」バグが起こりうる。


で。セッション固定についてですが……。
よしんば「IPを固定しても問題ない」としてなお。IPだって、Cookieだって、hiddenだって、みんなみんな生きてる…のは嫌なのですが、偽装は十分に可能です。
それ以上何をかいわんや。


次。

2005/4/27の日記において、セッションIDをPOSTに積むCSRF対策法が掲げられていたわけですが、これよりもはるか前の時点で、ワンタイムチケット法が実績あるCSRF対策法として、周知されていました。仮にも自称Webアプリケーションのエキスパートが知らなかったとは言わないと思います。

これについてはある程度納得。もうちょっと具体的には「ワンタイムチケット(ワンタイムトークン、って私は呼ぶことが多いですが)法が実績あるCSRF対策法」の部分。実績があるのかはもう一つ存じ上げませんが、少なくとも「考慮に入れる手法の1ピースとして」の有効性は。
もっともこれでも穴が開く可能性がきちんとあるので、そのあたりはある程度意識しなければいけないのですが。
# 正規のユーザが使う前にハイジャック犯がトークンを使ってしまう可能性。「使いっきりのトークンが使われたから正規ユーザが認証から外れる」状況はまぁ想定内として、その場合「ユーザが"攻撃されている可能性が理解できるようなPage"を表示」しないと、結局は「あらあら何かしら? パソコンってよくわからないわねぇ」で片付けられて何の意味も成さない。


で、

それを知っていれば、セッションIDをPOSTに積むCSRF対策のデメリットも予想できたはずで、あえて危険な方法を紹介する意味がわかりません。

この文章に…つながらない。というか何がどのようにつながるのかがよくわからない。
ちょっと理解すべく噛み砕いてみる。
「ワンタイムトークン法が実績あるCSRF対策法として周知されている」から「セッションIDをPOSTに積むCSRF対策法」にはデメリットがある。
………なんで? 単純に比較対象になっていないと思う。
きちんとした理由があるなら「双方を融合して」もいいわけですし。

さらに、この方法では、セッションIDの再生成処理がとても面倒になってしまいます。セッションIDの再生成処理とCSRF対策は本来機能的に独立したものである以上、別々のモジュールとして実装するのが、「近代プログラミングの基本」でしょう?

んっと。…どの辺が面倒なのかが物凄く疑問なのですが。
そうだなぁ…例えば。
CSRF対策クラス::run();
で終わりなのでは?
で、


class CSRF対策クラス {
public:
bool run(void) {
// 必要に応じて
セッションID管理クラス->再生成処理();
}
};
って感じでしょうか?
そらまぁ「最終的に泥臭い部分の実装が面倒である」可能性はあるにしても。一回作っちゃえば概ねOKだと思うのですが。
で、どのあたりが面倒なのか。…わかりません。

そして、私の師匠(高木氏とは人格も技量も桁違い。本当に尊敬できる方です)は一目見てこう指摘しました。「GETだとだめなので、POST必須。POST必須にしたら、<form> とJSだらけの pageになってしまう。」
なるほど。セッションIDをGETで出したら、リファラーから漏洩しますから。一方、ワンタイムチケットならGETで出しても大丈夫です。出たときには、ペアになる半券ごと廃棄されています。

まずPOST必須については、それ以外も含めてあるので特に反証にならず。っつかいまどき、マトモにセキュリティを理解している人間で「GETでOK」などという人がいるとは思えないのですが。
つぎ。hiddenで「FORM必須」はまぁ理解。で、何ゆえにJS(JavaScript、でよいんですよねぇ?)だらけになります? 使わずに行くことなど十二分に可能ですがっていうか実績山盛りですが。
さらに。「FORMだらけのPage」に何か問題があるのでしょうか? ……想定してみる可能性。
・あらゆるリンクがボタンだらけ
imgにしませう。しんどいですが、文字だけのAエレメントよりは「デザイナぶるな」画面になること請け合い。
・デザイナーに負荷がかかる
まぁ特にしょっぱなの負荷は実際しゃれにならんですが。「セキュリティにかけるコストの一環」としてもしincludeできるなら。


…あと、なにかあります?
(いいネタを頂戴したら追記します)


んで、

なるほど。セッションIDをGETで出したら、リファラーから漏洩しますから。一方、ワンタイムチケットならGETで出しても大丈夫です。出たときには、ペアになる半券ごと廃棄されています。

致命的。
ワンタイムトークンの問題点をちゃんと把握しましょう(上述)。


次。プライベートCAで発行した証明書(いわゆる「オレオレ証明書」)でも問題ない発言について。

あいかわらずの説明不足気味で(わざとなのかどうかしりませんが)おっしゃることが良く判りませんが、dns cache poisoningとか中間者攻撃とかの話をしているのでしょうか?確かにそれらの手法を使えば、エンドポイントになるわけですから、そういう意味では盗聴はできるでしょう。

すみませんごめんなさいあやまりますから「いいから勉強しなおして来い」って感じでしょうか。


元々は、「山本勇, PHP実践のツボ セキュアプログラミング編, 九天社, p.213 」にある

非商用サイトなどで単に暗号化の目的だけならプライベートCAで発行した証明書でも問題ありません。

という発言に対して高木先生が何か否定的意見を発言し、それに対してGIJOE氏が

なお、SSLの指摘については、山本氏の書かれたことは特段間違っていません。もしかすると、高木氏は「『警告なんて無視すれば良い』なんて状況を作り上げたら、せっかくのSSLの安全機構が意味をなさない」という主張かもしれませんが、そういう思想的な主張と、書籍の脆弱性を同列に並べると、何を言いたいのか、テーマがぼやけると思います。

と反論している、ってのが経緯。
先に結論を書くと、高木先生の

これは技術的に間違いである。

の一言に全て要約されてしまうのだが。
まず、そもそもの書籍の部分のミスについて。
「暗号化の目的だけならプライベートCAで発行した証明書でも問題ありません。」
あります。或いは「暗号化ってなにを意味します?」っていう部分の追求からになるのですが。
………。
まぁ他の子達への教育もあるので、細かく。
まず暗号について。もうちょっと正確には「暗号強度」について、まずは学びましょう。
現存するありとあらゆる暗号は、1つを除いて「潤沢なリソースさえあれば解読が可能」です。ちなみに余談ですが、除かれているその「1つの」暗号手法は「絶対にアタック(解読)できません」。ただ、普段の実運用には適さないことが多い形式なので、普通あんまり使わないです。で、その暗号形式が「なんなのか」については各自調査。ちゃんとした暗号系の本を読めば載ってますから。
では全ての暗号は「解読が可能であるために脆弱なのか?」という問いに関しては、前提条件が「全ての暗号」である限りにおいて、基本的にNoです。
なぜ「解読できるのに脆弱ではない」のか。答えは「時間」。上記の問いには、時間という要素が(今回は意図的にですが)欠落しているのです。


例題
本日08:00。明朝05:00に実行する作戦の詳細命令書を暗号化方式「い」にて送信。
暗号化方式「い」は、理論的には「マシンリソースに潤沢に資源つっこみまくった状態で解読平均30年」。
これは脆弱か否か?


上述において、ぶっちゃけ「21時間ほど暗号がとけなければOK」なので。暗号化方式「い」は、上述使用の前提条件において「十分な強度を持っている」といえます。
これが暗号強度で一番初めに認識すべき部分です。
次に。解読が出来たって事は「以降全ての暗号が即効で解読できる」ことを意味します。だって「暗号化するための鍵」をゲットしたのと一緒なわけですし。
つまり、解読された瞬間から「その鍵を使ったあらゆる暗号通信は 無駄無駄無駄無駄ムダムダムダムダ〜〜〜」と、なんかどこぞの漫画で出てきそうな状況になるわけです。
ここから「鍵の寿命」という発想が沸いて出てきます。よろしいでしょうか?


さらに。
暗号化のための鍵ってのは、原則的に根本的に「ばれちゃまずい」ものです。ばれていいのは共有鍵暗号における共有鍵ぐらいなもんです。
んで。もし。もし仮に、その鍵が「なんか身元のはっきりしない危ないところからきたもの」だとしたら。で、その怪しいところがその鍵を悪用したとしたら、どうなるでしょう?
是非リアルの鍵屋さんの鉄壁の倫理観に期待したいものです。…おいといて。


以上を踏まえて(やっと本題だよおい)。
「非商用サイトなどで単に暗号化の目的だけならプライベートCAで発行した証明書でも問題ありません。」
は否定されます。
まず「CA(Certificate Authority : 認証局)」ってのは、鍵の「身元が安全であること」を周知します。それがプライベートとか言われてしまうと、利用者がその安全をどうやって保障してもらったらいいのかわかりません。「僕悪人です」っていう悪人っていないですよね?
つぎ。その認証局がよしんば悪意がないとして。ちゃんと運営されていなければ、鍵はいつしか寿命を迎えます。その辺、管理できてるって「利用者に正しく伝達」できますか?
もし。もし仮に「暗号化」って単語を「簡単に解析されちゃうけど暗号ロジックを通した文字列ではある」程度の意味合いで使っているならまぁ文面として誤りではないのですが。
多くの場合において「暗号化目的」とは、ある程度の強度が期待されている文面です。
高木先生のいう「金庫がある。金庫の上には鍵と、明けるのに必要な番号のメモがある。この金庫は機能しているといえるのか?」という問いがそのまんま当てはまる状態です。


でまぁ、以降余談で恐縮ではあるんですがね。

拙著「PHPサイバーテロの技法」(ソシム社)は、高木氏の恣意的な妨害活動にも関わらず、好評な売れ行きを続け、ついに3刷を迎えることになりました。関係者一同、読者の皆様に心より感謝をいたします。

別の意味で興味はあるのですが。現状「教えてる子達への問題集」以上の認識がもてないかも。
具体的利用法としては「本書nPage 〜 nPageを読み、誤りの箇所がある場合、その誤りと理由、対策について述べよ」。まぁよい勉強にはなるのですが。

中身も、象牙の塔の住人の机上の空論ではありません。オープンソースプロジェクトで様々な実戦経験を積んできた筆者の知識と経験がギッシリと詰めこまれています。

これも申し訳ないんだけれども。実戦経験があるからいいってものでもないような(ないのはかなりまずいんですが)。
で、XOOPSのソース見る限り…すみませんアレ汚いです。設計はちゃんと見てないけど、ソースレベルではかなり。


時々、高木先生の発言は「んっと…わからなくもないけど現場では…」っていう発言もあるのですが。それでもちゃんと読めば、そのエッセンスは面白いしうなずけます。まぁ、そも「相手の意見を鵜呑みにする」なんて行為、愚の極地なのですが :-P
一方でGIJOE氏の発言は、ちょっと微妙なところが多くてうなずけません。


というわけで、今回のまとめ。
・セッションIDは死んでも固定するなっていうか固定したら殺!!
・hiddenによるセッションIDの埋め込みは「限定条件付で」有効。ただしデメリット(もっぱら画面遷移&デザイン工数)もあるので、限定条件を理解した上でご利用は計画的に。
・ワンタイムチケットも有益だが万能ではない。っつか、いい加減やめれや銀の弾丸信仰。
・プライベートCA使っていいのは実験環境だけ。グローバルに公開する場合、どんなに頑張ってもプライベートCAは問題ありあり。


こんな感じでしょうか?