がるの健忘録 このページをアンテナに追加 RSSフィード

2006-01-30

[][]セキュリティ関連色々と(セッション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は問題ありあり。


こんな感じでしょうか?

2006-01-24

[][]サニタイズとかそーゆー話

んっと。最近騒がれているサニタイズ周りのお話なのですが。

実は私は「データは汚染されっぱなし」派です。…って書くと海よりも山よりも大きな誤解を生みそうですが :-P


一般にサニタイズって言っても、実際には「対DB向け」と「対HTML出力向け」では異なったサニタイズが必要になります。

なので、個人的には「入り口で統一的にサニタイズする」ってことをあんまりやらないですし、ましてや途中でなんとなくなんてぇ恐ろしいことは間違っても。

結局のところ「使うときにやむを得ずするもの」だと思っているので、私は「データは常に汚染されている」ことを前提に、出力(画面だろうがファイルだろうがDBだろうが)タイミングで「出力方式にそぐうサニタイズ」をするようにしています。

そう考えると、一部言われている「サニタイズのための置換を二重三重にやってしまって以下略」という話は十分にフォロー&ガードできてしまいます。


んで。そんな話をしているのは、Jittaさん経由( http://blogs.wankuma.com/jitta/ )、GIJOE氏の…Blogじゃないなぁ。記事、と言ったほうがいいのだろうか? から、なのですが。( http://www.peak.ne.jp/xoops/md/news/article.php?storyid=81 )

ちっと興味を持って拝見するに…正直なところ、個人的には「甘い」としか思えないです。

具体的に、私が個人的に甘さを感じるラインを書いてみたいかと。


まず「idとdateはサニタイズする?」論争。

ここで出てくるのは有名な(有名だと思うんだけどなぁ…どうなんだろ?)高木先生。Blogは必見。今回は http://takagi-hiromitsu.jp/diary/20051227.html を取り合えずご覧くださいませませ。

まずGIJOE氏は概ね「なぜ $row['id'] を、htmlspecialchars() に通さなくて良いのか。それを考えていただくことが主目的となる局面で」、「htmlspecialchars()を通す必要がある型とそうでない型がある、ということです。」等。つまりは「データの形によってサニタイズが必要である場合とそうでない場合があるのに画一的にサニタイズするのは如何なものか」的見地であることが伺えます。

一方で高木先生は「プログラムの全体を精査すれば、「$row['id']」の値が数値しかとらないことを確認できるだろうし、「$row['postdate']」の値が日付を表す文字列しかとらず、HTTPリクエストの値(CGI入力)に依存していない式だとということも確認できるのだろう。だが、そのような確認作業をしないと正しいコードかどうかわからないような、プログラムの書き方をすべきでない。セキュリティ云々以前に、プログラムの開発方法論として、できるだけ局所的な視点でコードの正当性を確認できるように書くのが、近代プログラミングの基本だ。つまり、このコード断片だけ見て、問題がないとわかるように書くべきである」という風な主張をなさってます。

個人的には私は高木先生の意見を支持します。

そもそもデータ型なんてのは「ふわふわしている」もんです。というか、GIJOE氏は「$row[]だからDBの結果セットであるのは明らかですし、'id'は整数型、'*date'は何らかの時間型だと、十分に局所的に判断できます。」とか書いてますが、idが整数型でdateがが時間型である保障なんてどこにもないです。っていうかそのまえに、idって必ず整数型なんですか? 状況にも拠りますが、私は必要に応じて文字型を取る場合がありえますが。

大体、いろいろなところからの「ご無体な仕様変更」についてはどのようにお考えなのでしょうか?

んで、そんな「多分こうだよねぇ」的見地に立って物を作るからこその「脆弱性の混入」なのではないでしょうか?

そも「ここで問題になっているのは、「無駄かどうか」という議論ではないのです。あくまで、正しくデータ型・用途を理解しているかどうか、という問題なのです。」とありますが、では出力時にサニタイズすることがこの妨げになりうるのでしょうか?

もし「表示するタイミングで何が表示されるかによってデータ型の用途を理解させる」ことを目的としているのであれば、土台から根底から誤ってます。ンなモノはis系の関数なりなんなりをきちんと用いるべきです。袋の外から叩いたときの泣き声で中身を判断するような真似は間違ってもしちゃぁいけません。

もしそれが「この形はこういうものだからサニタイズは必要ない」のであれば、それは仕様変更に対してあまりにも脆弱ってぇもんです。そも、近代おぶぢぇくと指向プログラミングにおいて形なんてものがどこまで重要なのでしょう? だってモノでしょ? データなんて、全部 :-P


あと、ここ。

「文字列定数は、明らかにhtmlspecialchars()をかける必要のないものです。「無駄だから」とか、そういう発想じゃありません。そこに、攻撃の入る余地がないことも重要ですが、HTMLとしての要素を期待されることが極めて多いからです。」

んっと。「攻撃が入る余地がない」がまずNGです。もしPHPバグで「文字列定数部分へのアタック」が可能なら? そういう発想は一つ大切です。いやまぁレアではあるんですがね。

で、それ以上に根本的に根源的に大切なこと。ここ試験に出ます(笑)。

HTMLエレメントプログラム中に書くな!!」。

最低限の基本的な部分じゃなかかと思うんですがどげんなもんでしょうか?

ビタ1bit(byteですらない。いやまぁ電子データにビタがあるかどうかは別として)たりとて、HTML要素は書いちゃいかんです。そんなことをするからデザイン変更で面倒な思いをするとです。

それを…なにをどこからどんな風に血迷えば「HTMLとしての要素を期待されることが極めて多い」などという文面につながるのでしょうか?

ちなみにこの部分で「セキュリティ的には…」という発言には一切耳を貸しません。業務上メンテナンス/保守性を確保し、その上でセキュリティも確保する。双方は分離して語られるべきではありません。相反して分離させざるを得ないときでなお「保守性の観点からはこうだがセキュリティの観点からはこう」と、セットで語られなければならないものです。

で、保守性を前提に、HTMLプログラム中に埋め込むなど、言語道断今後横断です。で、セキュリティ上に何らかのメリットがあるかといえば、あるようには到底思えません(あるならそれはそれで考慮されるべきだと思うのですが)。


私は「例え初心者に教えるときにですら」MVCの理念とかサニタイズの考え方とかは叩き込みます。思うに、少なくとも現在、その辺の教育は躾レベルです。一番初めに「有無を言わさず」叩き込み刷り込むべきです。

それをまがりなりにも「PHPサイバーテロの技法」という、セキュリティへの警鐘を鳴らすべく作られた書籍がこれでは…目も当てられません。

まだ書籍をちゃんと読んでいない中で恐縮ですが、高木先生の記述とGIJOE氏の記述/反論を読むに、現時点においてはGIJOE氏の発言のほうに多くの違和感を感じてしまいます。


…で終わるとこのBlogの意味がないので、まとめます(笑

サニタイズは出力直前におこなうのがガル流。サニタイズは「お客様(出力先)のお好みに合わせて」お出しいたします。

・データの形なんてものは信じちゃいけません。何時誰がどんな仕様変更するかわかったもんじゃないですし :-P

プログラム中にHTMLなんか1bitたりとて書いてみろ、その場で(以下残虐描写につき検閲削除


こんなところでしょうか。

皆様からのご反論ご意見お待ちしております。

2006-01-20

[][]いいから使うなscanf

んっと。C++ってかC言語のお話なのですが。

C言語ライブラリにおいて「使うな」といわれている関数がいくつか存在するのですが。

取り合えず筆頭に上げたいのがscanf。

なにせこの子、入力で文字次第で平気でバッファにデータを残す、データ種別が違うと「バッファにデータを残したまま」プログラム自体が異常終了するなど、問題山積み。

なんていうか「何があろうが絶対に」使っちゃいけません。


ただ、キーボード入力が簡単にとれるとかいうクソヌルイ理由からなのか、どうも大学だの専門学校だのでC言語を教えている現場では「普通に」使わせているフシがありまして。

取り合えずそんな教師連中を /dev/null にリダイレクトしてみたいものです :-P


「じゃぁなに使えってのさ」って話になるのですが。getsを使えば簡単…とかいうと、さらに巨大な裁きの雷が舞い降りてきます(getsもまた「絶対に」使っちゃいけない関数です)。

入力はfgetsを使いましょう。ちゃんと入力データが取れますし、変なデータは自力で切り分けられますし、getsのように「バッファオーバフロウが原則」なんてことはなく、ちゃんと最大長を「自前で」指定できますので。


っていうか、そーゆー事を教えるのが学校の役目なんじゃないんでしょうか???

2006-01-17

[][]PHP session関数群について

えっと。まず前提として、sessionで使える文字は限定されているっていうのがあります。 …いやまぁ、PHP4系(4.3.10、4.3.11、4.4.1 でチェック)はa-zA-Z0-9、PHP5系(5.0.4、5.1.1でチェック)はa-zA-Z0-9のほかに、カンマ,とハイフン−がOK、っていう微妙な差異があるのですが…まぁとにかく「OKな文字とNGな文字」ってのがあります。


4系のルーチン

 for (p = key; (c = *p); p++) {
   /* valid characters are a..z,A..Z,0..9 */
   if (!((c >= 'a' && c <= 'z') ||
       (c >= 'A' && c <= 'Z') ||
       (c >= '0' && c <= '9'))) {
     ret = 0;
     break;
   }
 }

5系のルーチン

 for (p = key; (c = *p); p++) {
   /* valid characters are a..z,A..Z,0..9 */
   if (!((c >= 'a' && c <= 'z')
       || (c >= 'A' && c <= 'Z')
       || (c >= '0' && c <= '9')
       || c == ','
       || c == '-')) {
     ret = 0;
     break;
   }
 }

………。閑話休題


で、まぁ。上述以外の文字が使われている場合、通常「アタック」であることが予想されるのですが。おかしな文字をセッションIDの文字列で用いられると、エラーをログに吐き出します。具体的には、 "The session id contains invalid characters, valid characters are only a-z, A-Z and 0-9" というメッセージでエラーを吐き出します。

さて。大抵通常当然のごとく、上述の「奇妙なCookie値が設定されてきた」などはプログラム上で捕捉したいと思うのが世の常人の常というものだと思うのですが。上述のログを吐き出しているのは、 php-X.X.X/ext/session/mod_files.c というファイルにある、ps_files_open という関数です。


static void ps_files_open(ps_files *data, const char *key TSRMLS_DC)


復帰値、void?これは「復帰で何も返さない」ことを意味します。で、肝心のチェック部分。

   if (!ps_files_valid_key(key)) {
     php_error_docref(NULL TSRMLS_CC, E_WARNING, "The session id contains invalid characters, valid characters are only a-z, A-Z and 0-9");
     return;
   }

ご覧頂いてわかるとおり(C言語読めねぇよとかいう突っ込みはなしの方向で)、ステータス、なにも保存していません。この時点で「invalidが取得できない」事がほぼ確定します。

それ以外にもまぁ「基本的に認証系の機能欠けてるよねぇ」とか色々と突っ込みはあるのですが。


…え〜っと。取り合えず「僕は使ってない/自作で認証系のクラス実装してる」とだけ述べておきます(苦笑

2006-01-16

[]占星術:四つの窓

※別Blogからの転記です


えっと…まずはお詫びを。年末年始、プライベートビジネスともにトラブルが発生してまして、更新ができませんでした。

取り合えず…大分よくはなったのですが、なんとなく全体的にかなりヘビーな風邪が流行っているようなので(わたしもきっちり引っかかってました)、皆様もどうかお体にはご注意のほどを。


さて。前回予告してました4つの窓のお話を。

比較的大雑把な見方なのですが、その人を端的に知るにはとても便利であり、また同時に「自分を知る」ためにも便利なので。

一言(表ですが)で表現すると


他人\自分|知ってる| 知らない

−−−−−−−−−−−−−−−−−

 知ってる| 太陽 |アセンダント   

 知らない| 月  |  ??


とまぁこんな感じなのですが。…このままじゃ「なにこれ?」って感じなので、ちと解説をば。


まず、一般に皆さんが「自分の星座」として認識されているのは、正確には「太陽星座(サンサイン)」という呼び方をします。あなたが生まれた「瞬間」に太陽がどの星座の場所にいたか、ってのがその意味合いになります。

サンサインの星座の特徴は、自分からも他人からも「見えやすい」気質を表します。だから一般的にはこのサンサインを用いることが多いんですね。


一方で。サンサインと同じような意味合いで、「月星座(ムーンサイン)」というものがあります。生まれた瞬間の月の位置ですね。

このムーンサインが暗示する性質は「自分自身は認識しているんだけど他人には見えにくい」気質を表します。


また、生まれた瞬間の星の配置を記すときに、12分割された円に書き込むものなのですが(ネイタルチャートとか呼びます)、その各分割されたエリア(室:ハウス って呼びます)にはやはり、それぞれ星座が割り当てられます。

で、第一室の星座を「アセンダント」と呼びまして。このアセンダントの星座は「他人からは見えるんだけど自分からは見えにくい」気質を示してくれます。


さて。ここからどんなことがわかるんでしょう?

たまにある「他人と自分の評価にずれがある」人は、この4つの窓の星座が相反する気質であることが多いのです。特にアセンダントと月が相反する場合、「自分にしか見えない」気質と「他人にしか見えない」気質とのぶつかり合いなので、かなりのギャップを伴います。

例えば、アセンダントが獅子で月が乙女の場合「周囲からは豪胆に見られるんだけど実は繊細」だったりします。この場合に周囲から「豪胆なリーダーであることを期待される」と、本人の気質(月:乙女)からかけ離れたものになり。これで責任感とかそういうものが強ければ、時として大きくストレスを生み出してしまいます。


こういった苦労をしている方、結構実はいらっしゃいます。


サンサインに表されるように「自分も他人も見えている」気質はよいのですが。

そのほかに、「自分にしか見えていない」ムーンサイン、「他人にしか見えていない」アセンダントサインのような「一方向からしか見えない気質」を人が併せ持っていることを考えると、相手の気質や自分の気質を決め付けることなく、もう少し柔軟に人を見ることが出来るのではないでしょうか。

サンサインと違い、ムーンサインとアセンダントサインは調べるのがちょっと大変ですが、チャンスがあれば自分のサインについて調べておくと、以外な自分が発見できるかもしれません。


そうそう余談ですが。「自分も他人もしらない」、4つ目の窓には???がはいっています。これは「誰も知らないから検証のしようがない」ので不明なまんまです。

でもこれも見方を変えると、全ての人は誰も知らない第三の可能性を持っている、って考えると。ちょっとワクワクしてきませんか?


自分を他人を知るうえで。ちょっとしたヒントにでもなれば幸いです。

[][][]FF XI のマクロPerlで切り出す

えっと…本気でメモなのですが。

Final Fantasy XI online ってのがありまして。で、PC(Windows)版ってのがあるのですが。

マクロ周りでチェックをいれてみたのですが…

mcr9.dat

とかって名前で入ってるのはいいのですが…もろバイナリなんです。

んで…私のように「PS2と混在」の場合、とりあえずPC版のマクロのリストとかが作りたくなりまして。でもバイナリを読み上げるのはちょっと人としてどうかと思いまして。


でまぁ「取り合えず簡易的に抜き出すっぽいPerl」を作りました。

文字コードは変換してないですし(元々はShift JIS)、かなり作りも荒いのですが。

まぁ本格的に使いたかったら適当に修正してください :-P


ってか…同アカウント内であれば、PCとPS2とでマクロのやり取りくらい通信とかでやりたいよぉ ;;


そうそう。

tab変換した文字列は、:で囲まれてよくわからんバイナリ化しています。

そんなんの辞書なんぞ用意するほど丁寧じゃありません(笑

#!/usr/bin/perl

$fn = "./" . $ARGV[0];

open (IN, $fn);
$data = "";
while(<IN>) {
  $data .= $_;
}
close(IN);

#
my @ret;
$count = 0;

sub cut { my ($a) = @_; $count += $a; }
sub add {
  my ($a) = @_;
  $wk = substr($data, $count, $a);
  $wk =~ s/[\x00]//g ;
  $wk =~ s/[\xFD]/:/g ;
  $count += $a;
  push @ret, $wk;
}

# 初期ヘッダ切り出し
cut(28);

# データ取得
for($i = 0; $i < 20; $i ++) {
  add(61);
  add(61);
  add(61);
  add(61);
  add(61);
  add(61);
  add(14); # タイトル
  push @ret, "------";
}

# 出力
$fn = $fn . ".txt";
open (OUT, "> $fn");
foreach $wk (@ret) {
  print OUT $wk . "\r\n";
}
close(OUT);

2006-01-12

[]spamらしいspamっていうかPhishingらしいPhishingっていうか

いやぁ初めて頂戴いたしました、Phishingメール。

Return-Path: <support@ebay.com>

とかなってるのに

Received: from www (ftp.ksiu.or.kr [211.171.244.50])

とか書いてあるしだいたい

Message-Id: <20060112105440.92F652BBFE@うちのどめいん>

ってどうよ(多分うちのMTAがつけたんだろうなぁとか推測)。

でまぁお決まりのHTMLメールで。Webビーコンないのはまぁ百万歩ゆずるとして。

まずは

It has come to our attention that your eBay Billing Information records are out of date.

That requires you to update the Billing Information If you could please take 5-10 minutes out of your online experience and update your billing records, you will not run into any future problems with eBay's online service.

However, failure to update your records will result in soon account termination. Once you have updated your account records, your eBay session will not be interrupted and will continue as normal. Failure to update will result in cancellation of service, Terms of Service(TOS) violations or future billing problems.

で危機感を適宜煽った後

To update and login to your eBay account, click on the link below:<br><br>

<a href="http://210.101.192.9/UpdateCenter/Login/?MfcISAPISession=明らかにBASE64でencodeしたげな文字列">http://cgi4.ebay.com/ws/</a><br>

と流れてくる。

素晴らしい。一部の隙もないほどに完全で典型的なPhishing

Content-Type: text/html; charset=koi8-r

ロシア系かぁ。でも、Mailのヘッダを見てる限りだと韓国だよなぁ。.krだし。まぁどっちでもいいんだが。


いやぁしかし。まさかこんな、古典的といってもいいような典型的なものが頂戴できるとは。

というわけで、記念に。

2006-01-11

[]状態遷移プログラム

えっと……ちょっと難しい説明になるのですが。とはいえ、ある程度のレベルのプログラマであれば知って損はないっていうか知らなきゃ損するネタなので、頑張って説明してみたいと思います。

まず、状態遷移図ってのがあります。これについてはてけとうにぐぐって(www.google.com)ください。


さて。例題としてCSVを取り上げます。且つ、例題なので簡略化します :-P

CSVの文字列を二つのモードに切り分けてみましょう。

つまり

・通常モード

・二重引用句内モード

です。


通常モードにおいて、,はデータの区切り、改行はレコードの区切りを表します。

二重引用句内モードにおいては、,も改行も「そのまんまデータとして」取り扱います。


また、

通常モードで二重引用句”が出てきた場合、二重引用句内モードに移行します。

二重引用句内モードで二重引用句”が出てきた場合、通常モードに移行します。


ここまではOKでしょうか?


さて。

通常プログラムを組むときって、多分if文を連打して、

foreach ( 対象文字 <- 文字列) {
 if (モード == 通常) {
  // 通常モード の処理
  if (対象文字 == ',') {
   データ区切りの処理
  } else
  if (対象文字 == '\n') {
   レコード区切りの処理
  } else
  if (対象文字 == '"') {
   モード = 二重引用句内
  } else {
   対象文字をデータに足しこむ
  }
 } else if (モード == 二重引用区内) {
  // 二重引用句内モード の処理
  if (対象文字 == '"') {
   モード = 通常
  } else {
   対象文字をデータに足しこむ
  }
 }
}

って感じで書くかと思うのですが。

今回はモードが2つですからまだいいのですが、これで状態がもっと沢山あったり、或いは「Aの状態からはBとCになりえて、BからはAとCとDとEになりえて、CからはBとDとEになりえて…」みたいな複雑な状態遷移図をコード化すると、なんか物凄いネストの嵐になって、可読性が低下すること請け合いです :-P


そこで状態遷移です。

私はもっぱら、クラス or 関数ポインタを用います。

今回はクラスを用いてみましょう。

クラスは、「処理クラス」を基底クラスとして、その派生クラスとして「通常モード処理クラス」と「二重引用区内モード処理クラス」を実装します。

関数ポインタ使うなら、引数戻り値をあわせておけばOKです。

で、以下がソースになります。

// クラス宣言:っつかほとんど構造体ですが
class データクラス {
private:
 通常インスタンス;
 二重引用句内インスタンス;

 分解したCSVが保存できそうなデータタイプ
}

// 初期処理
データクラス->通常インスタンス = 通常モード処理クラス;
データクラス->二重引用区内インスタンス = 二重引用区内モード処理クラス;

処理インスタンス = 通常インスタンス;	// 取り合えず初めは通常インスタンススタートってことで。
foreach ( 対象文字 <- 文字列) {
 // 処理
  処理インスタンス = 処理インスタンス->処理(データクラス, 対象文字);
}

こんな感じです。

え? 短すぎてよくわかんない?

では順を追って。


まず初めは、「処理インスタンス->処理()」ってのは実際には「通常インスタンス->処理()」がcallされます。

で、通常モード処理クラス内の処理メソッドは、前述のまんま「,はデータの区切り、改行はレコードの区切り、それ以外はデータ」という処理をします。

また、二重引用句”が出てきた場合、二重引用句内モードに移行しなければならないので、returnに「データクラス->二重引用句内インスタンス」を、そうでないばあいはreturnに「データクラス->通常インスタンス」を復帰します。

同じように、二重引用句内モード処理クラスの処理メソッドも同じような処理をします。

そうすると、もし通常モードで二重引用句が出てくれば「処理インスタンス」のオブジェクトへのポインタが切り替わるので自動的にモードが二重引用区内モードに切り替わり、その処理が行われ、その逆もまたしかり、となります。


状態遷移プログラムはこんな感じでそれぞれの状態にそった処理が簡単に記述でき、割合にシンプルに処理がかけます。

っていうか、状態遷移図のそれぞれの○ごとにクラス(ないし関数)を書くだけなので、かなり複雑な状態遷移でも楽に書けます。


実際にCSVを処理するときは、私は


*set_nomal:通常モード

最も基本的な状態。以下の挙動を行う。

',' cellの区切りを意味する文字と判断する

'"' エスケープモードへのモード切替を行う

'\r' 改行だが、CR-LFの可能性を考え、CRLFモードに切り替える

'\n' 改行。一行のデータの終わりと判断する

any 通常のデータとみなす


*set_crlf:CRLFモード

CR-LFを想定しているモード

'\n' '\r\n'であったため、ここで一行のデータの終わりと判断

any '\r\n'ではなかったため、現在のデータを通常モードで再処理


*set_esp:エスケープモード

'"'や','を入れるためのモード。','はただのデータとして扱われる

'"' モード切替かデータかわからないため、エスケープチェックモードへ切り替え

any 通常のデータとみなす


*set_esp_chk:エスケープチェックモード

エスケープモード中に出てくる'"'を処理するためのモード

'"' '""'となっているため、データに'"’を追加、モードはエスケープ。

any エスケープモードから通常モードへの切り替え指示とみなす。

モードを通常に切り替え、現在のデータを通常モードで再処理


の4つのモードの切り替えで処理しています。


…って、Perlでよければサンプルコードのっけたほうがよいんですかねぇ?

2006-01-10

[]CSVについての覚書

なんかどこかで書いた気がするのですが…どうも見当たらないので、覚書。

CSV。そのまんま「カンマ","をつかってデータを区切る」書き方なのですが。


データ1,データ2,データ3,データ4,データ5

データ6,データ7,データ8,データ9,データ10


無難に穏当にこんな感じなのですが。


疑問1:データにカンマはもてないの?

答1(a):持てません無理ですあきらめましょう。

答1(b):データを二重引用句(ダブルクォーテーション)で囲みましょう。


んっと…こんな感じです。

"1,000","2,000","3,000"

これで、1,000と、2,000と、3,000っていう3つのデータが表現できます。

めでたしめでた…くないし。


疑問2:んじゃ、データに二重引用句はもてないの?

答2(a):いいからあきらめろって言ってるだろ?

答2(b):んっとね。""って感じで、二重に書くんだよ。


例えば、1,000とab"cdってデータを持ちたい場合。

"1,000","ab""cd"

って持ってください。これでOK。


ちなみに、二重引用句内では改行コードとかも「データとして」持ちまわれます。

覚えておくと便利です。


で………こんなCSVを「ちゃんとカッティングできる」ロジックってのが気になりますが。…書くと長くなるので書きません(笑

頑張って各自実装してみましょう。

こういう実装は、状態遷移っていう手法を使うと便利です、って事だけ書いておきます。


……リクエストがあったら、C++関数とかいきなり貼り付けるかも(笑

2006-01-06

[][][]DBD::mysqlインストール

PerlのDBD::mysqlインストール関連のお話です。


基本は

http://y-kit.jp/saba/xp/cpan.htm

を参照していただくのがぐっどなのですが…ちょいとはまったところなどを軽くメモ。


そうそう。私は

/opt/db/mysql-バージョン番号

インストールしてますんであしからず。


とりあえず

ln -s /opt/db/mysql-4.0.24/bin/mysql_config /usr/local/bin/mysql_config

しておきます。

んで…


まず最大のポイントは

 /usr/local/mysql/bin/mysql_config --libs

で、吐き出されたデータをメモ。次に、

 /usr/local/mysql/bin/mysql_config --cflags

で、吐き出されたデータをメモします。

のあたり。

ディレクトリの指定には気をつけましょう。特にMySQL 4.0系を使いたくて別途インストールしたんだけど「実はディストリビューションが自動的に4.1系とか5系とかをインストールしてくれちゃってた」なんてときに地獄を見ます(苦笑


ようはinclude先の問題だったのですが。

通常、/usr/include/mysql配下に入ってる…と思ってつい「4.1系のincludeファイルをとりこんでしまう」と、

make test でエラーが出るわ、実際にconnectしようとすると

/usr/bin/perl: symbol lookup error: /usr/local/lib/perl5/site_perl/5.6.2/i586-linux/auto/DBD/mysql/mysql.so: undefined symbol: mysql_autocommit

とかって怒られたりします。

そりゃまぁ mysql_autocommit は4.1系からの導入だから、4.0系のsoファイル見てれば「ないのは当然だよねぇ」って話になるのですが。

具体的には mysql_version.h ファイルにあります MYSQL_VERSION_ID っていう定数を使って#if つかってコンパイルを色々やってるわけでして。

これで4.1系のincludeファイルみてれば、そりゃおかしなことになりますって(苦笑


というわけで。私の場合

perl Makefile.PL --cflags=-I/opt/db/mysql-4.0.24/include/mysql "--libs=-L/opt/db/mysql-4.0.24/lib/mysql -lmysqlclient -lz -lcrypt -lnsl -lm"

というコマンドでOKになるわけです、はい。


そうそう。一応、コンパイル後の

/usr/local/lib/perl5/site_perl/5.X.X/iX86-linux/auto/DBD/mysql/

付近にあるんじゃないかと思われる

mysql.so

を ldd mysql.so して、依存ライブラリ関連はチェックしておきませう。

libmysqlclient.so.12 => /opt/db/mysql-4.0.24/lib/mysql/libmysqlclient.so.12 (0x40011000)

libz.so.1 => /usr/lib/libz.so.1 (0x4004f000)

libcrypt.so.1 => /lib/libcrypt.so.1 (0x4006b000)

libnsl.so.1 => /lib/libnsl.so.1 (0x40099000)

libm.so.6 => /lib/libm.so.6 (0x400af000)

libc.so.6 => /lib/libc.so.6 (0x400d2000)

/lib/ld-linux.so.2 (0x80000000)

これでもしlibmysqlclient.so が libmysqlclient.so.14とかなってたりすると、4.0系を使いたい的にはのーぐっどかもしれないです。


…これだけのために結構深いところまでDBI.pm触ったりmysql.pm触ったり色々してしまった……

2006-01-05

[][]second-order SQL injection ( セカンドオーダーSQLインジェクション )

高木先生のBlogより。

http://takagi-hiromitsu.jp/diary/20051231.html#p05

…いやまぁ「リンク先に移動して読んでね」で片付けたほうが早いんだけど。

まぁ一応ここは「めも」なので、必要なところを書いておきますっていうか引用しておきます。

たとえアプリケーションが常にシングルクオートをエスケープしていても、攻撃者はなおも、データベース中のデータがそのアプリケーションで再利用されるときにSQLをインジェクトすることができる。


Username: admin'--

Password: password


例えば、攻撃者がアプリケーションに登録して、ユーザ名「admin'--」、パスワード「password」のユーザ名を作ったとしよう。

このアプリケーションはシングルクオートを正しくエスケープし、このようなINSERT文が作られる。


insert into users values( 123, 'admin''--', 'password', 0xffff)


このアプリケーションが、ユーザにそのパスワードを変更することを許しているとしよう。


パスワードをセットするクエリはこんな感じになるかもしれない。


sql = "update users set password = '" + newpassword + "' where

username = '" + rso("username") + "'"


ユーザ名 admin'-- が与えられると、以下のクエリが生成される


update users set password = 'password' where username = 'admin'--'


したがって攻撃者は、admin'-- というユーザを登録することによって、admin のパスワードを自由にセットできる。

んっと…まぁ「エスケープ処理を忘れただけジャン」とかいう突込みが頭に浮かぶし高木先生も同じように突っ込まれておりますが。

とはいえ、他人様のプログラムをチェックする際には考慮しておきたいポイントの一つなのかもしれません。