PEAK XOOPS - 「プログラミング解説書籍の脆弱性をどうするか」への反論のようなもの2 in englishin japanese

Archive | RSS |
PHP
PHP : 「プログラミング解説書籍の脆弱性をどうするか」への反論のようなもの2
Poster : GIJOE on 2006-01-21 05:42:22 (25926 reads)

in englishin japanese
前記事
プログラミング解説書籍の脆弱性をどうするか

高木氏が12/27のブログエントリで書かれた、拙著「PHPサイバーテロの技法」に対する批判は大きく2点に分けられると思います。

(1) 「サイバーテロ本」では、その場しのぎ的な「サニタイズ」を行うコーディングを推奨している
(2) 「サニタイズ言うなキャンペーン」



このメインとなる2点以外についても、拙著「PHPサイバーテロ本」についていくつか書かれているので、それについての回答や反論を先に片づけておきます。

「書籍に脆弱性があることについて」
高木氏、12/27エントリの冒頭部:
Quote:

印刷されて流通する書籍に脆弱性がある、つまり掲載されているサンプルコードにズバリ脆弱性があるとか、脆弱性を産みやすいコーディングスタイルを身につけさせている解説があり、それが脆弱なプログラマを生産し続ける根源になっている問題は、「なんとかしないといけないねえ」と以前から言われてきた

実はこの部分はまったく同感です。
私が書店でざっと立ち読みした限りでも、かなり多くのPHP入門書のサンプルコードには脆弱性があり、しかも、それが暫定的なコードであってそのままでは公開してはいけないものだ、という説明すらないものが数多く見られます。
今回、私が「PHPサイバーテロの技法」という本を執筆するモチベーションは、まさに、その状況をなんとかしたい、という思いでした。

ご存じの方も多いと思いますが、今は本格的な出版不況で、ごく一部のベストセラー以外はほとんど売れていません。今回の「PHPサイバーテロの技法」の印税なんて、執筆にかかった時間を自分の仕事に回した時の収入と比較すれば微々たるものです。今時、収入のために書籍を書いている人=専業テクニカルライターなんてほとんどいないんじゃないでしょうか。

現実に、脆弱性についての解説がない入門書が書店にあふれているのなら、それと同時に購入していただけるような、「薄くて安いけど、入門書に欠けているセキュリティについての情報がキッチリと書かれている本」を書店の並べれば良いだろう、という論理です。だから、この本は薄くて安いのです。そのように、出版社にお願いしたのですから。(現実には、なかなか普通の書店に並ばないのですが…)

ともあれ、不必要な敵視をする前に、問題状況についての思いは高木氏と一緒だということをご理解いただければ幸いです。


「書籍の間違い訂正について」
引き続いての部分:
Quote:
ソフトウェア製品の脆弱性は、指摘があればパッチが提供されたり修正版に差し替えられたりするが、書籍の脆弱性はどうか。正誤表が差し込まれるとか、回収する措置がとられるかというと、それは望めそうにない。言論には言論で対抗すればよいということになるだろうか。

ソフトウエア製品やオンラインドキュメントと違って、書籍の修正が簡単でないことは、書籍を書いている本人が一番知っていることです。それだけの責任を感じながら、執筆にも校正にも臨んでいます。
もちろん、それでもミスは起きてしまうことは多々あり(事実ミスをしました)、一般的な書籍であれば、書籍サポートサイトなどに載ることになります。「PHPサイバーテロの技法」についてもそのようにします。
また、増刷のタイミングでも修正は可能です。もちろん、その前の書籍を入手された方については、サポートサイトをご覧いただく他ありませんが。

なお、山本氏の書籍「PHP実践のツボ セキュアプログラミング編」については、校了後に流し読みした程度ですが、とりあえずWebアプリケーションのセキュリティ、というよりは、全体的なサーバセッティングとかそういうイメージの本のように思えました。高木氏の指摘する2点についても、おそらくは正しいのだろうとは思いますが、それらすべてを勘案したとしても、「焚書」などと思想弾圧に使われた言葉を用いるのは、あまり見ていて気持ちの良いものではありません。

実は、山本氏には一度だけお会いしたことがありますが、とても気さくな良い方でした。もちろん、それとこれとは無関係です。

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


「その他の細かな部分」
該当エントリの脚注部で、いくつかいただいている指摘:
Quote:
また、4-1-7節「SSLの効果」のp.125の記述に、パケット盗聴されたときの問題について、
Quote:

Webアプリケーションを作るために、そのレベルでのクラッキングの可能性まで考えなければならないなんてナンセンスです。*15
逆に、SSLを利用し、かつ、クッキーに「SSL以外ではやりとりしない」という属性をつけていたとしても、XSSすら防げません。

と書かれていて、何を言いたいのかちょっと意味不明になっている。

ここで言いたいことは、「パケット盗聴よりも、XSSなどの方がはるかに現実的な攻撃方法であり、緊急性がある」ということだけなのですが、文章が良くなかったかもしれません。

Quote:
もうひとつ問題点を挙げると、p.228のコラムで「magic_quotes_gpc」について、
Quote:

magic_quotes_gpc機能についてはその副作用から批判も強く、この設定はOff とすべきと書かれた文献も多く存在しますが、プログラマーのスキルレベルが信用できないWebアプリケーションを利用するケースでは、magic_quotes_gpc をOnにする方が、ほんの気持ち程度は安全と言えます。

と書かれているが、magic_quotes_gpcをOnにすると、CGIパラメタがShift_JIS で渡されたときに文字化けが発生してしまうため、これが邪魔になるという問題が起きているようだ。そのため、酷いことに、 magic_quotes_gpc がOnのPHP環境でも動くようなプログラムを作るテクニックと称して、PHPプログラムの冒頭で、CGIパラメタの全部に対して「stripcslashes」をかけるという「前処理」が、一部のPHPプログラマの間で定番となっているようだ(この本に書かれているわけではない)。 magic_quotes_gpc = On したり stripcslashes したり、また htmlspecialchars してみたりと、ほんと汚いPHPコードがたくさん Googleで見つかる。magic_quotes_gpc は Off で徹底がよいだろう。


これは多分、単なる読み違いだと思います。プログラムを作る人間に、magic_quotes_gpc onを勧めている箇所など、1点もありません。もしあったらご指摘ください。

この部分だけでも素直に読んでいただければ十分にお判りいただけると思いますが、あくまで「すでに存在しているプログラムを利用する場合」の安全性です。事実、SQL Injection脆弱なアプリケーションは数多いのですが、secuniaなどのレポートを読む限り、magic_quotes_gpc on で「偶然」守れているケースも多いのです。そんなアプリケーションであれば、他にも穴がある可能性も高いので、本当に使い続けるべきかどうか、という部分から考え直した方が良いかもしれません。だから「ほんの気持ち程度は安全」という表現になるのです。

Quote:
それから、p.197の「7-1 ソースコードが手元にないときの脆弱性の見つけ方 7-1-5 実際に攻撃してみる」で、
Quote:

本当の悪意あるクラッキングであるなら、当然、プロキシやネットカフェを利用するなどのアクセス元の隠蔽も必要ですが、その手段については本書の範囲外です。

などと書かれているのが危ない。不正アクセス行為にあたらないことが確信できる操作しかしてはいけないのに、これでは勘違いする読者もいるのではないか


すみません。ここは一種の冗談の部分です。唐突で判りづらかったかもしれませんが、アラをさがそう、という視点でもなければ、特段かみつくような場所でもないはずです。
ちなみに、「本書の範囲外です」の後ろには、 マークがつきます


さてここからが本題であり、まさに反論になります。とりあえず今回は時間の都合で(1)についてだけにします。

「『貧民的プログラミング』という嘘」

12/27のエントリは「プログラミング解説書籍の脆弱性をどうするか」というタイトルになっていますが、拙著「PHPサイバーテロの技法」については、「掲載されているサンプルコードにズバリ脆弱性がある」という指摘ではなく、「脆弱性を産みやすいコーディングスタイルを身につけさせている解説」が該当するのだと思われます。

その批判点はここです。

Quote:

たとえば、p.28のクロスサイトスクリプティング脆弱性の対策コードを見てみる。――(C)

Quote:

ここを以下のように修正します。

    while ( $row = mysql_fetch_array( $result , MYSQL_ASSOC ) ) {
        echo '<p>' ;
        echo 'No.'.$row['id'].'<br />' ;
        echo '題名:'.htmlspecialchars($row['title'],ENT_QUOTES).'<br />' ;
        echo '名前:'.htmlspecialchars($row['name'],ENT_QUOTES).'<br />' ;
        echo '日時:'.$row['postdate'].'<br />' ;
    (略)

ソースコードの違いは一目瞭然だと思います。過去の投稿内容の各テキストが、ブラウザに表示される直前*04に、htmlspecialchars((テキスト),ENT_QUOTES) を通過しています。これが「HTML出力用サニタイズ」です。

GIJOE, PHPサイバーテロの技法―攻撃と防御の実際, ソシム, p.29


これのどこが悪いかというと、「id」と「postdate」について htmlspecialchars を通していない点である。

たしかにこれは脆弱性ではない。プログラムの全体を精査すれば、「$row['id']」の値が数値しかとらないことを確認できるだろうし、「$row['postdate']」の値が日付を表す文字列しかとらず、HTTPリクエストの値(CGI入力)に依存していない式だとということも確認できるのだろう。

だが、そのような確認作業をしないと正しいコードかどうかわからないような、プログラムの書き方をすべきでない。セキュリティ云々以前に、プログラムの開発方法論として、できるだけ局所的な視点でコードの正当性を確認できるように書くのが、近代プログラミングの基本だ。つまり、このコード断片だけ見て、問題がないとわかるように書くべきである

    while ($row = mysql_fetch_array($result, MYSQL_ASSOC)) {
        echo '<p>';
        echo htmlspecialchars('No.' . $row['id']).'<br />';
        echo htmlspecialchars('題名:' . $row['title']).'<br />';
        echo htmlspecialchars('名前:' . $row['name']).'<br />';
        echo htmlspecialchars('日時:' . $row['postdate']).'<br />';

ここで、「'No.' や '題名:' や '名前:' や '日時:' の定数文字列まで htmlspecialchars に通すなんて無駄じゃないか」などということを考えてはいけない。いまどき、そんな貧民的プログラミング思考をするのはプログラム職人として恥ずかしいことだ。

なるほど。おっしゃりたいことは判ります。
ただ、これがどこで書かれているか、お判りでしょうか。
P.28 まさに導入部分です。
なぜ $row['id'] を、htmlspecialchars() に通さなくて良いのか。
それを考えていただくことが主目的となる局面で、なぜ「思考停止」コーディングを推奨しなければならないのでしょうか?

ここで重要なのは、htmlspecialchars()を通す必要がある型とそうでない型がある、ということです。ここはPart3-2のつなぎにもなっていますし、そこの対策3にも書いているように「必要のないものは最初から受け取らない」方がむしろベターです。<>'"& を受け取る型の方が例外であると考えるのがよいでしょう。

「このコード断片だけを見て問題がないとわかるか」それについては、Noでしょう。しかし、私自身、このような場当たり的なコーディングは勧めていません。P.143の「本書のサンプルコードについて」でも、「このような『用途』の混同こそが脆弱性の元凶である」とも書いています。それでも「脆弱性を産みやすいコーディングスタイルを身につけさせている解説」となりますでしょうか?

書籍後半のP.143になって、それまでのサンプルコードをすべて否定する、というとんでもない反則技をやっているわけですが、最初から順を追って読んできていただけた方なら、ある程度納得していただけると思います。テーマをぼやけさせないことは、他者に情報を伝えるためにもっとも重要なことの一つです。

実際には、このような作りが「章立てが回りくどい」という批判にもつながっていることは承知しています。編集者にも「こういう順番での書き方は判りづらいんじゃないですか」と指摘もされましたので、私の手法が間違っている可能性は否定できません。

そのP.143での大どんでん返しの前、Part4-3で私がお勧めしているのは、Part4-3で書いてあるように、用途に応じた変数名をつけることです。そうすることで、「htmlspecialchars()のかけすぎ」を防ぐこともできます。

翻って、高木氏推奨のコードを見てみましょう。このコード、全体の確認作業をせずに、
「htmlspecialchars()のかけすぎ」かどうかわかりますか? わからないはずです。つまり、
Quote:

だが、そのような確認作業をしないと正しいコードかどうかわからないような、プログラムの書き方をすべきでない。セキュリティ云々以前に、プログラムの開発方法論として、できるだけ局所的な視点でコードの正当性を確認できるように書くのが、近代プログラミングの基本だ。つまり、このコード断片だけ見て、問題がないとわかるように書くべきである

残念ながら、この言葉はそっくりそのまま高木氏のコードにもあてはまってしまいます。

htmlspecialchars() は、2重にかけるとおかしくなる関数です。リクエスト変数について「かけないこと」ほどは問題にならないものの、「かけすぎ」ればやはりおかしく表示されます。

局所的な視点で確認するために大事なのは、その変数がどの「型」と「用途」を持っているか、明示的に使い分けることです。もちろん、その方法はPart4-3に示した方法に限りません。これはあくまで一例であり、Part3の時点で、問題点をすべて列挙していますから、経験のある人であれば、クラスでも関数でも、はたまたPHPコード自動生成でも、好きなようにコーディングしていただいて構いません。それまで積み上げてきたものがあるのでしょうから、それにうまく載せる形ができれば一番です。Part4-3 はそうでない読者のために書いた章です。

この本を書くに当たってもっとも難しかったのは、プログラミングそのものの初心者と、C++などではバリバリの経験者、という2種類の読者が想定されたことです。私自身は、後者の人に最大限の敬意を払って原稿を書いたつもりです。そのために、コーディングスタイルそのものにはあまり口をださず、なるべく問題点だけを列挙する、という方針になっています。プログラマーとしてのスキルのある方であれば、問題点さえ判れば、あとは自力でどうとでもなるからです。
それが本当に良いことなのかどうかは私には判りませんが、やねうらおさんのような、バリバリのプログラマー(プログラマーとしてのスキルでは明らかに私よりはるかに上)の人から高く評価いただいたことは、まさに狙い通りであり、何よりも嬉しく感じています。


高木氏は「$row[] だからDBの結果セットなのは明らかで、2重にかかっていないこともここだけで判る」と反論するかもしれませんが、もしそれを許すのであれば、私の書いたコードも問題ありません。$row[]だからDBの結果セットであるのは明らかですし、'id'は整数型、'*date'は何らかの時間型だと、十分に局所的に判断できます。

高木氏はこうも書いてます。
Quote:

ここで、「'No.' や '題名:' や '名前:' や '日時:' の定数文字列まで htmlspecialchars に通すなんて無駄じゃないか」などということを考えてはいけない。いまどき、そんな貧民的プログラミング思考をするのはプログラム職人として恥ずかしいことだ。

実のところ、「貧民的プログラミング思考」というものを初めて聞きました。ただ、ここで問題になっているのは、「無駄かどうか」という議論ではないのです。あくまで、正しくデータ型・用途を理解しているかどうか、という問題なのです。

高木氏の書いたコードへの批判を、高木氏風に書くとこうなります。
Quote:

「何も考えず全部にhtmlspecialchars()かけとけば安全だ」なんて愚民的プログラミングを行うことが、プログラム職人として最も恥ずべきことだ。


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

例えば、ある文字列定数にコピーライトマークを入れたい、となった場合にどうしましょうか。その都度、htmlspecialchars()を消すんですか? htmlout() となっている部分を、htmlout_tag()に書き換えるのですか? そういう場当たり的な対応こそ、「脆弱性を生み出す諸悪の根元」です。まったくもって正しいプログラミングスタイルではありません。

ご丁寧に、「関数を使いましょう」なんてことも書いていただいていますが、そういうレベルの話はしていません。さらに'htmlspecialchars'がつづりとして長い、というくだりは、冗談ではないかと疑ってしまいます。入力支援でもソース色分けでもいくらでも手段はあるでしょう。いまどきなら、普通はテンプレートを使うでしょうし、プレースホルダータイプのもの(生データをセットし位置に応じた動的なサニタイズを行う)もあります。さらに、注意力に依存しないシステムとして、.NETやPHP自身で、PHPコードそのものを生成するなんてものさえあります。

繰り返しますが、htmlspecialchars()に通すべきデータかどうか、それを考えるのはXSSやScript Insertionを考える上で、実はとても重要です。なぜなら、htmlspecialchars() で安全になるとは限らないからです。

ここから先の詳しい話については、次回「『サニタイズ言うなキャンペーン』の嘘」で書きます。一週間ほどお待ちください。

もちろん、人間の注意力に依存しないコーディングスタイルは重要です。本書をお持ちの方であれば、P.143でそう書いてあることをご確認いただけるでしょうし、その一例がPart4-3に示してあることもお判りいただけるはずです。

しかし、そのシステムの前提が間違っていたらまったく意味がありません。少なくとも、「HTML出力と見たらhtmlspecialchars()をかける」、なんて思考停止な方法では、XSSやScript Insertionは完全には防げない、ということだけはここで明確に主張しておきます。

Printer friendly page Send this story to a friend

Comments list

GIJOE  Posted on 2006/1/21 7:41
今読み返していてふと気づきましたが、高木氏はPart7-1まで読んでらっしゃるんですね。

だとすれば、Part4-3も読んでいらっしゃるはずですよね。

私自身は、単にPart2やPart3までしか読んでいない故の誤解、のだと思っていたのですが、Part4-3まで読んだ上で、Part2の該当部分をもって「脆弱性を産みやすいコーディングスタイルを身につけさせている解説」などと批判するのは、あまりにも恣意的じゃないでしょうか。

「先に結論ありき」だとしか思えません。
Login
Username or e-mail:

Password:

Remember Me

Lost Password?

Register now!