<前の日記(2006年01月14日) 次の日記(2006年01月21日)> 最新 編集

高木浩光@自宅の日記

目次 はじめに 連絡先:blog@takagi-hiromitsu.jp
訪問者数 本日: 1079   昨日: 2734

2006年01月15日

続・「サニタイズ言うなキャンペーン」とは

「サニタイズ」という言葉はもう死んでいる

というコメントを頂いた。まず、

これは「サニタイズという言葉を使うな」という主張ではありません。「そもそもサニタイズしなくて済むようにすべきだ」という主張です。言い方を変えると、「サニタイズせよと言うな」という主張になります。

「サニタイズ言うなキャンペーンがわかりにくい理由」, 水無月ばけらのえび日記, 2006年1月5日

とある。「サニタイズせよと言うな」キャンペーンでもよいのだが、 その場合は次の展開が予想される。

「サニタイズせよと言うな」を主張する際の具体例として、XSSやSQLインジェ クションのケースを挙げた場合、正しいコーディングは、「その場の文脈でメ タ文字となる文字をエスケープすること」となるのだが、そうすると、

それをサニタイズと言うのだと思っていました。

のように言われるのがオチだ。「サニタイズせよと言うな」では、有効なキャ ンペーン効果は得られそうにないのだ。

つまり、「サニタイズ」という用語が、各人の都合でどんな意味にも解釈され るという、「汚れた言葉」になっており、専門用語として使い物にならなくなっ ているのだ。もはや、「サニタイズする」は「セキュリティ対策する」と同義 でしかない。そういう言葉には存在価値がない。加えて、特定の意味を指して 使っても別の意味で解釈されてしまうのだから、有害である。

ここで「sanitize」の原語の意味を頼りに、サニタイズを何を指す言葉とする べきか再定義しようとしても、先月31日の日記に頂いたトラックバックのように、次のような展開になってしまうようだ。

Web アプリケーションの出力処理とは、基本的に「他のアプリケーションにデータを渡す」処理だと思っています。(略)

なので私は、「消毒する」という言葉についても、

自分が扱っているうちに汚染されてしまったかもしれないデータを、消毒して から他のアプリケーションに渡す。

と受け取っているので、特に違和感はなかったりします。(略)

自分にとって害が無く、放っておいた場合でも、他のアプリケーションに渡す ときには、そのアプリケーションにとって害があるかもしれません。渡す相手 のアプリケーションにとって害があることが判っているのであれば、それを消 毒してから渡してあげましょう。

サニタイズの語感, Teny’s log 1月8日

このように不毛な話*1になっ てしまう。もうどうしようもない状況なので「サニタイズ」という言葉自体を 捨てたほうがいい。

なお、個人的には「サニタイズせよと言うな」という主張にはかなり 共感できます。この日記を処理している hatomaru.dll というプロ グラムでは、HTMLの出力をサニタイズする処理を一切書いていません。すべてが DOM で処理されている (そして InnerXml に値を直接セットしない と決めている) ので、サニタイズを意識する必要がないの です。これは非常に気が楽でした。

「サニタイズ言うなキャンペーンがわかりにくい理由」, 水無月ばけらのえび日記, 2006年1月5日

この文を見ても、「サニタイズ」が何を指しているのかが不明である。読んだ 人それぞれが勝手にいろいろな意味で読むだろう。

「サニタイズ」が拡大解釈されてきた原因

次に、「サニタイズ」の概念が普及してきた経緯を探ってみる。

先月31日の日記に頂いた別のトラックバック では、次のように主張されていた。

高木浩光さんのところで以前から盛りあがっている「サニタイズ言うなキャン ペーン」に密かに賛同しているのですが、やはり入力段階でHTML実体参照への 書換処理をやっているCGIが多く存在していた事が、「サニタイズは入力段で やるべきもの」という誤解を助長してしまったのが背景としてあるのではない かと思っています。

サニタイズ処理, めもおきば, 2006年1月1日

というよりも、過去に「入力段階でHTML実体参照への書換処理をやっている CGIが多く存在していた」という時代があり、その処理のことを「サニタイズ」 と呼んでいた。そこまではよかった(用語の使い方として)。それが、「CGI の入力段階での処置ではだめだ」という考え方が普及していったときに、なぜ か、正しい処置(HTML出力時のエスケープ処理)のことも「サニタイズ」と呼 ぶ輩がいて、それが現在までその種の「誤解」を引きずらせる原因となってし まったということだ。

こうした流れは、日経システム構築12月号の記事にも見られる。

最新の攻撃手法に適応する(略)

例えば,「セカンドオーダーSQLインジェクション」という攻撃は,自前のテ ストではテスト項目として挙がりづらい。この攻撃は,一般的に言われている 「SQLインジェクション対策」では防げない特徴がある。

クラッカは,ユーザーからの入力値をサニタイジングするという, “正しい”とされるSQLインジェクション対策を逆手に取る。(略)

セカンドオーダーSQLインジェクションは,これらの対策をくぐりぬける。こ の攻撃を防ぐにはさらに,(4)「変数を使ってSQL文を組み立ててい るすべての個所でサニタイジングする」(ラックシステムソリュー ション5部部長倉持浩明ことが欠かせない。

緊急点検! Webアプリ・セキュリティ 多層の防衛ラインでシステムを守る, 日経システム構築2005年12月号

一般に、マスコミは物事を大袈裟に言いたがる。正しい対策をしていれば普通 に防げる話でも、あたかも「新しい攻撃」であるかのように言いたい*2ため、 間違った対策のことを「一般的に言われている“正しい”対策」と言わざるを 得ないわけだ。

「入力でサニタイズ」することが大間違いなのだが、そう言ってしまうと、 「一般的に言われている“正しい”対策」と言ったことと矛盾してしまうため、 「サニタイズ自体は誤りでない」ことにして辻褄を合わせようとする。

その結果、「サニタイズは誤り」という本当のことを書けなくなり、「SQL文 を組み立てているすべての個所でサニタイジングする」と言わざるを得なくなっ ている。

こうやって「サニタイズ」の用法は節操なく拡大されてきた。そして、誤解す る者をいつまでも残す結果となった。

まだまだ残る誤解

次に、「サニタイズ言うなキャンペーン」をはってもまだ残る誤解の事例を挙 げてみる。


「サニタイズ」を「エスケープ」に置き換えればよいと誤読した事例

  • 「サニタイズ言うなキャンペーン」, Notes, 2005年12月29日

    つまり、あって然るべきエスケープ処理(PHPならhtmlspecialchars())を通していないからこそ、「サニタイズ」する必要が出てくるという意味か。(略)

    外部からのパラメータを受け取る部分は、次のように修正した。

    $foo = htmlspecialchars(strip_tags($_GET['bar']), ENT_QUOTES);
    

    (略)HTTP_USER_AGENTやHTTP_ACCEPTを受け取る部分も同様に修正している。

    $baz = htmlspecialchars(strip_tags($_SERVER['HTTP_USER_AGENT']), ENT_QUOTES);
    

CGI入力に対するサニタイズのコードになっている。おそらく、変更前のプロ グラムでは、記号の削除をしていたのであろう。「『サニタイズ』= 文字削除」 と理解されているケースと思われる。

ブラックリスト方式ではなくホワイトリスト方式にせよという話だと誤読した事例

  • Re: サニタイズ言うなキャンペーンがわかりにくい理由, zt日記, 2006年1月7日

    危険な文字を削除っていう手法は危険なので使わないようにしているのですが、 本当にその方法が必要なのでしょうか?

    安全な文字だけを通すようにするという手法ではだめなのでしょうか?

    たとえば、データファイルのファイル名の一部をCGIのパラメータと して受け取るようになっているPerlスクリプトなら/^[a-z]+$/のような正規表 現(Rubyなら\A[a-z]+\z/)で期待している文字しか入っていないこと を確認して(Perlの場合はuntaintもこれで出来る)、違っていたらエラーにする というのが「 セキュリティ対策以前に元来本質的に必要な処理」だと思います。

そんなのは「セキュリティ対策以前に元来本質的に必要な処理」ではない。 「/^[a-z]+$/のような正規表現」を使う手法はサニタイズ処理そのものであっ て、まさにセキュリティ対策のための処理である*3


パス名パラメタどどうするか

元に戻ると、

ただし、hatomaru.dll にもサニタイズのルーチンはあります。たとえば、 http://bakera.jp/hatomaru.aspx/ebi という URL の /ebi 部分はパス名とし て処理されるようになっていて、データディレクトリの中の /ebi/ ディレク トリにあるファイルを見に行くようになっています。ここで ../ などを許し てしまうと、サーバ内の任意の XML ファイルが読まれてしまうおそれがあり ますので、これは意識的に「サニタイズ」しています。

(略)これを「サニタイズせよ」と言わなくて済むような解決策ってあるので しょうか。

「サニタイズ言うなキャンペーンがわかりにくい理由」, 水無月ばけらのえび日記, 2006年1月5日

「サニタイズ」が何を指す概念として語られているのかがわからないし、具体 的にどんな処理で対処しているという話なのかがわからないが、パス名パラメ タの取り扱いの「正しい」コーディング手法は次のようになるだろう*4

方法(a): 言語システムのサンドボックス機構を使う。

方法(b): basename() など、パス名からファイル名部分(最後の部分)だけを 取り出す(言語システムが用意している)APIを使い、ファイルを開く処理の ところで、ディレクトリを示す式と basename() を通したファイル名とを連結 してパス名を指定する。

ポイントは、OSや言語システムに頼るようにし、自前で処理しようとしないこ とだ。「../」をチェックすることを「サニタイズ」と呼ぶとすれば、パス名 がどのように解釈されるかは、ファイルを開くときに呼び出す言語システムの APIやその先のOSのAPIに依存してしまうため、「『../』でサニタイズしたの に、OSは『..\』を解釈した」などということが起きてしまう。究極的には、 言語システムやOSのパス名解釈アルゴリズムを完全にエミュレートした上で検 査しない限り、「サニタイズ」は完全な対策とならないのであり、無理がある。

方法(a)を採用すると、パス名の解釈が(言語システムの責任において)最終 段階までresolveされた段階で、文脈上アクセスを許可しているパス名である かのチェックが自動的に入るようになる。しかし、この方法が使えない言語の 場合や、面倒だから(慣れていないから)嫌だという場合もあるだろう。

方法(b)は、パス名という型と、ファイル名という型を区別する考え方である。 CGIパラメタのひとつをパス名として設計するのを避けて、ファイル名として 設計せよということになる。多くの場合はこの方法が採用できると思われる。

しかし、「ebi/topic/2473」がパラメタであるなら、方法(b)は採用できない。 この場合は、ある意味httpdなみのアプリケーションを作っているようなもの なので、対処が複雑になるのは仕方ないと言えるのではないか。ファイルを開 く時点で、言語システムが用意しているパス名の正規化(パス名解釈を resolveする)APIを使って、目的通りのディレクトリ範囲になっているかをチェッ クして開くようにするのがよいだろう。「目的の範囲」は、ファイルを開こう とするプログラム上の文脈で決まるはずだ。

ところで、

ここで ../ などを許してしまうと、サーバ内の任意の XML ファイルが読まれ てしまうおそれがありますので、これは意識的に「サニタイズ」しています。

「サニタイズ言うなキャンペーンがわかりにくい理由」, 水無月ばけらのえび日記, 2006年1月5日

という文から推察するに、もし、「意識的に対処すること」を「サニタイズ」 と呼んでいるのなら、それは単に「セキュリティ対策として処置する」と言え ばよいのであって、「サニタイズ」という言葉を持ち出す必要性がない。

「サニタイズ」に固執する人たち

最後に、「サニタイズ」に固執する人が絶えない原因について探ってみる。

結論からズバリ言えば、Perlのせいだ。

20世紀の時代、CGIプログラミングといえばPerlだった。Perlは、open 関数のように、手軽な書き方を用意しているのがクイックハック*5に便利であった半面、 堅牢なプログラム開発(正常系以外への確実な対処が重要となるプログラム 開発)の場面では、上級者でない限り脆弱なプログラムを書いてしまいがち (そしてそれはとりあえずは動いてしまう)であるという有害性が大きかった。

そうした時代に書かれた脆弱コードが、セキュリティ対策として修正される際、 入力から危険な文字を削除する手法がとられた。これを指す言葉として「サニ タイズ」の概念が定着していった。

新規に開発される場合でも、「ブラックリスト方式は対策漏れが起きて危険だ からホワイトリスト方式で」ということは言われるものの、それも当初の意味 での「サニタイズ」の範疇であった。

shellを通して実行するopenのような使い方はやめるべきだが、使う場合、 「正しい対策」というのはなかなか難しい。エスケープするといっても、何を どうすれば正しいのかが複雑すぎる。そのため、Perlの世界では、「サニタイ ズ」することが「正しい本来の書き方」であるかのように認識されていった。 (それしかやりようがないと考えられたため。)

さらに、Taint機能がこれに拍車をかけた。Taint機能は本来、脆弱なコードが あるとき(あるかもしれないとき)に、仕方なく使うセーフティネットとして の役割であるはずだ。ところが、Taintにずいぶんと頼って書いている人もけっ こういるようで、Taintがセキュリティ上、本質的な役割を果たすものである かのように思い込んでいる人もいるようだ。

例えば次の発言を見てみる。

処理中に外部からデータを受け取ればもう、それは汚染されている 可能性があるものと看倣しますし、動的に生成するデータも、生成方法によっ ては汚染されている可能性があるという訳ですね。

処理中に汚染されたと言っても、自分にとって害が無いなら放っておいて良い 訳です。自分にとっても害があるなら、その場で消毒すべきですが。

サニタイズの語感, Teny’s log 1月8日

「汚染」という概念があると「消毒」という概念がちょうど対応するように見 えるのだろう。

だが、「汚染」という概念は、Taintという自動セーフティネット機構を実現 するにあたって必要となる概念にすぎない。

Taint機構は、自動的に危険な(可能性のある)操作を実行禁止にするために、 データフローを辿る。様々な入力となる処理に依存したデータフローを「汚染 された」ものと名付けた。これはなかなかうまいネーミングであるわけだが、 それは Taint機構を使う場合にとって「うまい」というだけであって、 本来のセキュアプログラミングにとって「汚染」は必要な概念ではない。

Taintを使わざるを得ないようなPerlの世界によって、「汚染」と「消毒」の 概念が育まれ、そうした古きPerl文化の影響が、「サニタイズ」に固執する人 たちをいつまでも残し続けている原因となっているのではないだろうか。

*1 「他のアプリケーションにデータを渡す」とは、 HTML出力や、SQL文の構成のことを指すと思われるが、HTMLを出力するときに 「<」「>」「&」のエスケープが必要であることや、HTMLタグの属 性値を出力するときに「"..."」に埋め込む値には「"」のエスケープが必 要であること、SQL文を構成するときに「'...'」に埋め込む値には「'」のエスケー プが必要であることなどは、セキュリティとは無関係に、正常系の動作として 当然にやるべきことなのであって、消毒だの、汚染だのは関係ない。

*2 正しい対策をしていると思い込んでいる読者のために、そう言いたいのだろう。

*3 セキュリティ以前の 本来的な処理として、「期待している値しか入っていないことを確認」をする 場合もあるが、それはCGIプログラムや関数などの仕様に基づいて行うべきで あり、アルファベットだけから成るという乱暴な正規表現が、ほんとうにその プログラムの仕様なのかは疑わしい。

*4 このあたりは、構築するアプリケーションの仕様として、ディレクトリの扱い をどのように設計するかしだいなので、一概には言えないが。

*5  ハックとは、リーダース英和辞典第2版によれば、次の意味があるという。

hack
4 《口》 コンピューターやプログラミングに一心不乱に取り組む; ずさんなプログラムを(適当に)作る[でっちあげる]; コンピューターシステムに侵入する〈into〉.
[リーダーズ英和辞典第2版]

hacker
2 《何をやっても》うまくいかない人, 不器用なやつ, ダメな人, 並の人; #《俗》 ずさんな[しろうとの](コンピューター)プログラマー.
[リーダーズ英和辞典第2版]

本日のTrackBacks(全100件) [TrackBack URL: http://takagi-hiromitsu.jp/diary/tb.rb/20060115]
XA_log_tia:汚れた言葉 (2006年01月17日 23:26)

高木浩光さんのサイトより。 >つまり、「サニタイズ」という用語が、各人の都合でど

それは聞き捨てならない。
高木浩光@自宅の日記 - 続・「サニタイズ言うなキャンペーン」とは
結論からズバリ言えば、Perlのせいだ。

高木先生が「サニタイズ言うなキャンペーン」をやっていらっしゃるので参加します。 要約版:「サニタイズ言うなキャンペーン」とは 高木浩光@自宅の日記 - 続・「サニタイズ言うなキャンペーン」とは サニタイズっていう言葉を使わないようにしましょう。 もともと何を..

反応に反応を重ねるうち、どんどん論点が見えなくなってしまっているような気がします。重要なことはこのあたりかな。 処理内容を理解し、その入力と出力が何であるべきかを理解する。 処理内容が多岐にわたる以上、アプリケーションの入り口での一括処理((高木さんの言う..

総論として、Perlのフレキシブルな言語仕様を以って「プログラマが気が抜けないから危険」とし、Perlの安全性を高めるための言語仕様(Taint)を以って「プログラマが気を抜くから危険」とするのは矛盾しているのではないか。

...

「サニタイズ」って言葉がある意味、免罪符のようになってしまって、ユーザ、開発者がともに思考停止に陥ることを危惧しているってことですかね。
本来やるべき対策をやれ。と。

「便利な言葉を使わないでみる」という行為自体は思考停止を防ぎ本質を見極めるのに役立つと思うが、言葉狩りになってしまっては再び本質を見失うことになる。

...

http://takagi-hiromitsu.jp/diary/20060115.html ぶっちゃけ分かりにくいでしょう。 例えば、『「ニート」って言うな!』は、呼ばれるべきではない人々が「ニート」と呼ばれ不利な状況に置かれている現状を踏まえて、「そんなふうに彼ら(または、我々)を呼ぶな!」と..

つまり、「サニタイズ」という用語が、各人の都合でどんな意味にも解釈されるという、「汚れた言葉」になっており、専門用語として使い物にならなくなっているのだ。もはや、「サニタイズする」は「セキュリティ対策する」と同義でしかない。そういう言葉には存在価値が..

検索

<前の日記(2006年01月14日) 次の日記(2006年01月21日)> 最新 編集

最近のタイトル

2024年03月16日

2024年03月13日

2024年03月11日

2023年03月27日

2022年12月30日

2022年12月25日

2022年06月09日

2022年04月01日

2022年01月19日

2021年12月26日

2021年10月06日

2021年08月23日

2021年07月12日

2020年09月14日

2020年08月01日

2019年10月05日

2019年08月03日

2019年07月08日

2019年06月25日

2019年06月09日

2019年05月19日

2019年05月12日

2019年03月19日

2019年03月16日

2019年03月09日

2019年03月07日

2019年02月19日

2019年02月11日

2018年12月26日

2018年10月31日

2018年06月17日

2018年06月10日

2018年05月19日

2018年05月04日

2018年03月07日

2017年12月29日

2017年10月29日

2017年10月22日

2017年07月22日

2017年06月04日

2017年05月13日

2017年05月05日

2017年04月08日

2017年03月10日

2017年03月05日

2017年02月18日

2017年01月08日

2017年01月04日

2016年12月30日

2016年12月04日

2016年11月29日

2016年11月23日

2016年11月05日

2016年10月25日

2016年10月10日

2016年08月23日

2016年07月23日

2016年07月16日

2016年07月02日

2016年06月12日

2016年06月03日

2016年04月23日

2016年04月06日

2016年03月27日

2016年03月14日

2016年03月06日

2016年02月24日

2016年02月20日

2016年02月11日

2016年02月05日

2016年01月31日

2015年12月12日

2015年12月06日

2015年11月23日

2015年11月21日

2015年11月07日

2015年10月20日

2015年07月02日

2015年06月14日

2015年03月15日

2015年03月10日

2015年03月08日

2015年01月05日

2014年12月27日

2014年11月12日

2014年09月07日

2014年07月18日

2014年04月23日

2014年04月22日

2000|01|
2003|05|06|07|08|09|10|11|12|
2004|01|02|03|04|05|06|07|08|09|10|11|12|
2005|01|02|03|04|05|06|07|08|09|10|11|12|
2006|01|02|03|04|05|06|07|08|09|10|11|12|
2007|01|02|03|04|05|06|07|08|09|10|11|12|
2008|01|02|03|04|05|06|07|08|09|10|11|12|
2009|01|02|03|05|06|07|08|09|10|11|12|
2010|01|02|03|04|05|06|07|08|09|10|11|12|
2011|01|02|03|05|06|07|08|09|10|11|12|
2012|02|03|04|05|06|07|08|09|
2013|01|02|03|04|05|06|07|
2014|01|04|07|09|11|12|
2015|01|03|06|07|10|11|12|
2016|01|02|03|04|06|07|08|10|11|12|
2017|01|02|03|04|05|06|07|10|12|
2018|03|05|06|10|12|
2019|02|03|05|06|07|08|10|
2020|08|09|
2021|07|08|10|12|
2022|01|04|06|12|
2023|03|
2024|03|
<前の日記(2006年01月14日) 次の日記(2006年01月21日)> 最新 編集