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

高木浩光@自宅の日記

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

2005年12月31日

「逆」にしたERBが登場

27日の「(略)とかERBとか、逆だったらよかったのに」の件、大岩さんが、逆にしたERB改造版を作ってくれた。

さて、使い勝手はどうだろうか。

要約版:「サニタイズ言うなキャンペーン」とは

27日の日記「『サニタイズ言うなキャンペーン』とは何か」は、いろいろ盛り込みすぎたせいか思ったよりわかりにくいものになって いるらしいので、結論から順に整理しなおしてみる。

  • 結論: まず「サニタイズ」という言葉を使うのを避けてみてはどうか。正しく説明することの困難から逃げようとしないで。

    • 例外1: 万が一に脆弱性があるかもしれないことを想定しての保険として、CGIの入力段階でパラメタを洗浄することを、サニタイズと言うのはかまわない。

    • 例外2: 既存のシステムに応急手当としてCGIの入力段階でパラメタに処置をする場面では、サニタイズと言うのはかまわない。

  • 理由1: 「サニタイズせよ」というスローガンは、「危険な文字列は削除する」のが本来的な対策であるかのように誤解させる。または、「危険な文字は変換する」のが本来的な対策であるかのように誤解させる。
    • 事例1: 書籍「PHP実践のツボ セキュアプログラミング編」における(B)の解説
    • 事例2: 「../ を ..%2F にエスケープしましょう」という大間違いな解説。
    • 問題点: 削除という対策は別の危険をもたらす場合がある。
      • 事例: 「..././」が「../」に変換されて攻撃が成功してしまうという、対策の失敗
    • 経緯の考察: 一部の脆弱性について、たしかに文字削除をするのが妥当な対策である場合もあるため、その削除処理が「サニタイズ」と呼ばれるようになり、次第に意味を拡大させて使用されるようになったのではないか。
    • 何が正しいか: インジェクション系の脆弱性では、メタ文字をエスケープするのが正しい。パス名パラメタのチェックおよびディレクトリトラバーサルでは、異常時には例外処理に飛ばすのが正しい。
  • 理由2: 「サニタイズせよ」というスローガンは、「CGIの入力パラメタに対して処置する」のが本来的な対策であるかのように誤解させる。
    • 事例: 「攻撃者視点ではなく開発者視点での解説を」で批判した@ITの記事
    • 問題点: CGIパラメタがプログラム中のどこでどのように用いられるかを把握せずに安全なプログラムにできるはずがなく、その把握は一般には困難である。
      • 事例1: いろいろ
      • 事例2: 「セカンドオーダーSQLインジェクション」(後述)。
    • 経緯の考察1: 既存のシステムに応急手当としてCGIの入力段階でパラメタをサニタイズすることが、セキュリティ対策屋の仕事として普及したが、これが間違って、新規開発の場面でなすべきこと(セキュアプログラミング)として広まってしまったのではないか。
    • 経緯の考察2: 「サニタイズする」という対策屋発想には、「不用意にプログラムの挙動を変えてはいけない」という背景があるように思える。
    • 何が正しいか: 入力段階ではなく「出力段階」で。「出力」というのは(出力というより)、問題を起こす場所。
  • 理由3: 「サニタイズせよ」というスローガンは、「CGIの入力パラメタに依存した式に対してだけ処置すればよい」というプログラミング手法で十分であると思わせてしまう。
    • 事例1: 書籍「PHPサイバーテロの技法―攻撃と防御の実際」における(C)のコード
    • 事例2: 書籍「PHPサイバーテロの技法―攻撃と防御の実際」における、cookieの値をHTML出力するときにエスケープするべきかを議論したコラム。
    • 問題点1: サニタイズ漏れを起こしやすくなる。
      • 事例: User-Agent: や Via: などの値を表示しようとした場合に、クロスサイトスクリプティング脆弱性を生みやすいことが古くから知られている。
    • 問題点2: 対策コードが整然とせず煩雑なものとなりやすいため、Webプログラミングの解説本で、対策を入れることが敬遠されがち。
    • 問題点3: 正しく書かれていることの確認がやりにくくなる。
    • 経緯の考察: 処置はCGIパラメタの入力段階で行うのではなく「出力段階で」ないし「出力の直前で」なすべきだと理解していても、貧民的プログラミングの発想があるため、「サニタイズ」という語感によって、入力に依存するところだけやっておこうというプログラミングスタイルをもたらしているのではないか。
    • 何が正しいか: 文法のあるテキストを文字列連結で生成するときは、全ての箇所で、文法に応じて存在し得るメタ文字をエスケープするのは、本来やるはずのこと(セキュリティに関係なく)。
  • 理由4: 「サニタイズすることがセキュアプログラミングである」と勘違いしていると、それが開発においてオプションであるという発想 (正常系の実装が優先するという発想)に陥りがち。
    • 問題点: Webプログラミングの解説書で、後付けの対策として書かれてしまう。
      • 事例: 書籍「PHP実践のツボ セキュアプログラミング編」で、いきなり最初のサンプルコードからしてクロスサイトスクリプティング脆弱性がある。
    • 経緯の考察: 正常系の実装として本来なすべき処理であるなら、わざ わざ「サニタイズ」だの「サニタイジング」だのいう特別な用語は出てこな いはずという直感が働くため。
    • 何が正しいか: インジェクション系などの脆弱性では、その「対策」と呼ばれるものは、セキュリティ対策という以前に、正常系の実装として本来なすべき処理。
  • 理由5: プログラミングを理解していない対策屋でも、「それさあ、サニタイズしてないのがいけないんだよねー」と、訳知り顔で語ってみせることができてしまう。
    • 事例: 後述。
    • 問題点: 誤った対策方法を教える解説や中身のない解説を増やしてしまう。

既にここまで来ている――サニタイズ症候群の末期的惨状

という連載は、最後まで読んでみてけっきょく質の低い解説だったが、タイト ルの「サニタイズ開発手法」というネーミングからして、そのダメっぷりは当 初から臭っていた。

どのあたりが「質の低い」ものなのか、いくつか挙げておく。

複数ページ間におけるセッションを管理するために、Webブラウザの持つCookie(クッキー)という仕組みが利用されることが多い。このCookie というものは、要約するとユーザーがWebページのフォームに入力した情報を一時的にクライアントPCに保存しておき(保存された情報をCookieと呼ぶ)、Webサーバ側で何らかのフォームを表示するときにCookie情報を使い、フォームの表示データを整形するというものだ。このため、悪意あるスパイウェアなどでCookie情報を抜き取るような行為が問題視されている。

スパム時代のサニタイズ開発手法 第1回, ITmedia, 2005年12月1日

「フォームの表示データを整形」というのが意味不明。この文脈で、cookieを 抜き取る原因を「スパイウェア」としているのがおかしい。「このため」とい う接続詞が前後の文脈につながっていない。なぜcookieを抜き取られるとまず いのかと、cookieを抜き取られる原因としてWebアプリの脆弱性を挙げるべき ところ。

また、プログラム側にバグがない場合でも個人情報が保存されているファイル自体のパーミッション設定(ファイルの読み出しや実行権限などの属性設定)が不適切になっていると、前述のようにブラウザで(ファイル名までの)URLを直打ちするだけで、誰でもそのファイル内容が参照できてしまうことになる。

スパム時代のサニタイズ開発手法 第2回, ITmedia, 2005年12月7日

ファイル丸見え問題を、ファイルの置き場所ではなく、ファイルのパーミッショ ン設定の問題と捉えているところが、いかにも素人臭い。

何が言いたいのかサッパリな記事。「Cookieは悪くない」の理由はきちんと説 明されてないし、「漏洩パターンの真実」なんぞ書かれていない。

ブラウザ上で動作するスクリプトコードとしては、従来からJavaScriptが存在するが、最近はJavaScript自身のバージョンも上がっており、表現力が増している。悪意あるスクリプトコードを受け取って対策が講じられていないと、ローカルPCから情報が抜かれてしまい任意のサーバなどへ自動送信といったこともできてしまう。

IEなどで使われるActiveXは、仕様上でレジストリの読み出しも可能としているため厳重な注意が必要となる。もちろん、便利さゆえの機能ではあるが、セキュリティと利便性は裏腹ともいえるのだ。

スパム時代のサニタイズ開発手法 第4回 Perlは悪くない――CGIセキュリティホールの落とし穴, ITmedia, 2005年12月20日

なんじゃこりゃ。べつに「表現力が増している」わけじゃないし。 ActiveXに注意が必要だとしてべつに「レジストリの読み出しも可能」が事の 本質じゃ全然ないし。「Perlは悪くない」は意味不明だし、 「CGIセキュリティホールの落とし穴」は全然書いてないし。

Perlは“手続き型言語”の一種であり、何らかの処理を行わせたい場合には、あらかじめ用意されている関数を呼び出すことで処理が可能となる。このことはPerlに限らず、ほかのプログラミング言語でも考え方が変わらない。何を意味するかというと、次のような具合だ。

スパム時代のサニタイズ開発手法 第5回, ITmedia, 2005年12月21日

まったく無駄な段落。

そうとはいえ、タグの無効化だけでWebアプリケーションのセキュリティホール(脆弱性)がすべてなくなるというわけではない。あくまでサニタイズはセキュリティホール(XSS)対策のための一手段にすぎないことを認識しておいてほしい。予期せぬ情報漏えいを防ぐための、最後の切り札と考えておくのがよいだろう。

スパム時代のサニタイズ開発手法 第7回 サーバの複雑さが変えたセキュリティ「サニタイズ」とは, ITmedia, 2005年12月27日

「最後の切り札」?? 何が言いたいんだ。

デベロッパーのためにもう少し突っ込んだ見解も示しておこう。(略)

Perlではコメントを「#」で始まる一行で記述することができる。コメントはプログラムの動作には何ら影響を与えないものだが、ソースコードの可読性を良くするために残すものだ。コメントが適切に付けられたコードは、メンテナンスが必要なときに読みやすいプログラムとなる。

Perlでは変数を「$」で始まる文字列で利用することができる。プログラムにおいて変数はいわば一時的なメモリ領域である。

スパム時代のサニタイズ開発手法 第7回 サーバの複雑さが変えたセキュリティ「サニタイズ」とは, ITmedia, 2005年12月27日

「デベロッパー」にとってまるっきり無駄な段落。

実際の処理はタグの置換というシンプルなものだが、プログラム本来の処理ではないため意外と見落とされやすい。

スパム時代のサニタイズ開発手法 第7回 サーバの複雑さが変えたセキュリティ「サニタイズ」とは, ITmedia, 2005年12月27日

意味不明。

オンライン・ムック「スパム時代のサニタイズ開発手法」では、これまで情報漏えいに対する防御策をさまざまな観点から解説してきた。

「サーバの複雑さが変えたセキュリティ「サニタイズ」とは」では、Webアプ リケーションにおけるサニタイズの仕組みを解説し、「巧妙化するネット地雷 原の避け方」と「あのCGIがクラックされてしまった理由」では、Perl言語を 例にして防御策の重要性を示した。いずれもがサービス指向となってきたWeb サイトで重要視しなければならない防御ノウハウばかりだ。

連載最後となる今回のポイントは、

スパム時代のサニタイズ開発手法 第8回 , ITmedia, 2005年12月28日

7回も連載してきてそれだけか。Perlのopenの話と、XSSが書いてあるだけだ。 今のご時勢にこれだけってのは、アリエナイ。

「サニタイズ」とさえ言っていれば、なんとなくそれっぽい解説のようなもの ができてしまうという、「サニタイズ」普及の悪影響もついにここまで達したか! と思い知らされた記事だった。

「じゃあなんと言えばいいのか」って?

次のような疑問が出てくるかもしれない。


「サニタイズ言うな」といわれても、たしかにインジェクション系の脆弱性に ついては、「(文字列連結で構成するテキストの文法に応じて)メタ文字のエ スケープする」と言えばよいのだとして、だけど、blogエンジンのようにHTML の入力を許したいWebアプリケーションにおいての対策のことはどう言ったら よいのか。それこそ「サニタイズ」なんじゃないの?


答えは簡単。「スクリプトの禁止」「スクリプト除去」「スクリプトの無効化」 などと普通の言葉で言えばよい。なぜわざわざ変な言葉を持ち出す必要がある のか。

「HTMLタグの記入を許すblogアプリなどでは、スクリプトの除去が必要です」 というように説明すればよい。

最近では、万能な意味で「サニタイズ」を使う人が増えてきた。英単語として のsanitizeは「消毒する」という意味だが、これをわざわざ意味を変えて「無 害化する」と訳す人が目立つようになってきた。その背景には、「入力で対策 することが誤りである」という指摘に対して、「出力で対策することもサニタ イズと呼びたい」という思考が働いているのだろう。

「消毒する」という表現には、「変数にシュッ・シュッと消毒液をかけておく」 というニュアンスがあるように思える。つまり、入力の段階でパラメタに一律 に消毒をかけておき、あとは自由に使うという開発スタイルをうまく表現した もののように思える。プログラムの最終段であるHTML出力のそれぞれの場所で エスケープ処理することを「消毒する」と表現するのはちょっと不似合いな感 じがする。あらゆる対策に使える言葉として広げようとするものだから、「消 毒」では似合わないので、「無害化」などという異なった訳が出てきたのでは ないか。

「無害化」と呼ぶくらいだったら、「脆弱性排除」と言えばよい。あらゆる脆 弱性対策を「無害化」と呼ぶくらいだったら、「脆弱性排除」と言うのと違わ ない。

そこまで「サニタイズ」の意味が広げられてしまうと、「サニタイズ」と言っ たところで何の説明にもならない。カタカナ英単語を使うことであたかもそこ に何か専門的なものがあるかのような臭い醸し出す役割しか果たさない。

そういうことをやっていると、「サニタイズ」という言葉を使うだけで満足す るような人達が出てきて、「スパム時代のサニタイズ開発手法」のような糞記 事が現れてくる。

「セカンドオーダーSQLインジェクション」ですって?

日経システム構築2005年12月号に、「緊急点検!Webア プリ・セキュリティ 多層の防衛ラインでシステムを守る」という記事が 出ているが、この記事がまた「サニタイズ」の嵐*1になっている。

それは別にして、この記事には奇妙なことが書かれている。

「対策済み」こそ危ない

それでも本誌の読者ならば,既に「対策済み」かもしれない。だが,その安心 感が足をすくいかねない。クラッカは,開発者が対策済みであること さえも悪用し,その盲点を突くような攻撃パターンを編み出す。

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

「対策済みであることを悪用する」というのは、いったいどういう意味か??

読み進めていくと、どうやらこれは次のことを指しているようだ。

最新の攻撃手法に適応していくことは,ユーザー企業やSIベンダーの担当者に は荷が重い。自前のテストでは不足する網羅性や最新動向への適応性を補うた めに,セキュリティの専門家によるセキュリティ監査サービスを適宜活用した い。

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

クラッカは,ユーザーからの入力値をサニタイジングするという,“正しい” とされるSQLインジェクション対策を逆手に取る。仮にユーザー情報を登録・ 変更するようなアプリケーションでこの攻撃が成功すれば,図7のように他人 のパスワードを自由に書き換えられてしまう。

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

「セカンドオーダーSQLインジェクション」 (second-order SQL injection)と は、Next Genration Security Software社が2002年に発表した論文の中で名付けたものであり、それは 以下で読める。

  • Chris Anley, Advanced SQL Injection In SQL Server Applications", Next Genration Security Software Ltd.

    [Second-Order SQL Injection]

    Even if an application always escapes single - quotes, an attacker can still inject SQL as long as data in the database is re-used by the application.

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

    For example, an attacker might register with an application, creating a username

    Username: admin'-- 
    Password: password

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

    The application correctly escapes the single quote, resulting in an 'insert' statement like this:

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

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

    Let's say the application allows a user to change their password. (略)

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

    The query to set the new password might look like this:

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

    sql = "update users set password = '" + newpassword + "' where 
    username = '" + rso("username") + "'"

    Given the username admin'--, the query produces the following query:

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

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

    The attacker can therefore set the admin password to the value of their choice, by registering as a user called admin'--.

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

この話は、日経システム構築の記事図7で解説されている。

これは要するに何が悪いのかというと、

sql = "update users set password = '" + newpassword + "' where username = '" + rso("username") + "'"

の部分で、式「rso("username")」の値に対して「'」のエスケープ処理をして いないのが悪い。

このように書かれたプログラムの問題を指して、

一般的に言われている「SQLインジェクション対策」では防げない

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

と言うのはいかがなものか。

正しいSQLインジェクション対策は、文字列連結でSQL文を構成しようとする全 ての箇所で、「'」で括った部分に埋め込む式の値に対して「'」のエスケープ 処理を施すというものだ。それを淡々と遂行していればこのようなことにはな らない。

記事中に、

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

例えば,データベースに格納済みの値を利用する場合や,ファイルに保存した 値を利用する場合なども,必ずサニタイジングする。

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

と書かれているのがそれを指しているのだろう。だが、それを「さらに」と言 うのはいかがなものか。すべての箇所でエスケープするのが元々当然なのであ り、当然だということを伝えるべきである。

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

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

とあるように、この記事が言うところの「一般的に言われている対策」とは、 「CGIの入力パラメタに対してエスケープする」だとか、「CGIの入力パラメタ に依存する変数に対してエスケープが必要」というものなのだろう。記事は、 「入力値をサニタイズするという対策は正しくない」ということをハッキリ言 うべきだ。

「サニタイズ」なんて言葉を使っているから、「入力値うんぬん」の呪縛から 逃れられない。サニタイズ症候群の悪影響はこういう形で現れてくる。

*1 正確には「サニタイジング」 と書かれている。無駄に「イング」形にしている分だけ、さらに神格化できて いるところが滑稽だ。

本日のTrackBacks(全100件) [TrackBack URL: http://takagi-hiromitsu.jp/diary/tb.rb/20051231]

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

高木浩光先生が、「サニタイズ言うなキャンペーン」を張られている様ですが、 「じゃあなんと言えばいいのか」って? という日記エントリの中で、 「消毒する」という表現には、「変数にシュッ・シュッと消毒液をかけておく」というニュアンスがあるように思える。つまり、..

すでにここまでこの話題が進んでいる段階で遅きに逸している感もあるのだけれども。 高木浩光@自宅の日記最近では、万能な意味で「サニタイズ」を使う人が増えてきた。英単語として のsanitizeは「消毒する」という意味だが、これをわざわざ意味を変えて「無 害化する」..

クエリ文字列を変換・削除すれば「サニタイズ済み」つまり安全、と思ってる人、多いんですかね。便利な言葉はしばしば人を思考停止に陥れる。

...

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

検索

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

最近のタイトル

2024年11月11日

2024年07月28日

2024年07月27日

2024年07月07日

2024年04月07日

2024年04月01日

2024年03月23日

2024年03月19日

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|04|07|11|
<前の日記(2005年12月27日) 次の日記(2006年01月14日)> 最新 編集