用語「サニタイズ」について
サニタイズ
話題 : セキュリティ
英単語 "sanitize" は「消毒してきれいにする」というような意味です。プログラミングの用語としては、危険な文字列を含む「汚染された」入力から危険な文字を取り除き、無害化することを指します。
たとえば、フォームで入力された文字を表示するような場合、入力された文字列を HTML 文書の中に出力することになります。単純に入力されたものをそのまま出力していると、ユーザが "<script>" のような文字列を入力したときにどうなるか、想像に難くありません。これは「クロスサイトスクリプティング脆弱性」と呼ばれるセキュリティホールとなります。
HTML では < (小なり記号)、> (大なり記号)、& (アンパサンド)、 " (二重引用符) などがマークとして解釈される場合がありますので、ユーザが入力したこれらの文字がそのまま出力されてしまうと危険です。そこで、これらがそのまま出力されないようにする必要があります。
※なお、これは HTML 文書中の属性値が全て二重引用符で括られている場合です。そうでない場合は、単引用符やスペースなども危険な文字となることがあります。また、注釈宣言やマーク区間、さらには script要素や style要素の中に出力している場合などは、さらにいくつかの文字が危険となります。
問題がある文字をそのまま出力しない方法は、いくつかあります。
- 問題のある文字を正しくエスケープする (たとえば、文字参照に変換)
- 問題のある文字を何らかの文字に変換する (たとえば、半角の「<」を全角の「<」に変換)
- 問題のある文字を削除する
HTML の場合は、文字参照に変換することによってエスケープできます。「<」「>」「&」「"」を、それぞれ < > & " に変換すれば良いのです。
エスケープができない場合もあります。たとえば、Perl の open() に渡すファイル名に . や / が含まれているとディレクトリトラバーサルの危険がありますが、これらはエスケープすることができません。このような場合は、危険な文字を削除する、危険な文字が含まれている場合はエラーにする、といった対処になるでしょう。
危険な入力は他にもいろいろあります。データベースに渡す SQL 文の処理を怠れば SQLインジェクションが可能になりますし、スクリプトの中に出力する文字列、コマンドラインに出力する文字列などにも注意が必要となります。それぞれに異なる処理方法があり、方法を誤ると問題が起きる場合があるので注意が必要です。
「サニタイズ」の多義性
この語は文脈によって、また人によって、様々な意味に使われることがあります。
狭義のサニタイズ
狭義の「サニタイズ」は、外部から与えられたデータに対し、データを受け取る際にエスケープ等の処理を行うことを意味します。最初に処理を行っておき、プログラム中では変換された後のデータを使い続けます。必然的に、出力時には変換後のデータが出力されることになります。
ただし、この方法にはいくつかの問題点があります。根本的な問題は、どのような文字が「危険」であるのかはシーンによって異なるということです。
たとえば、ユーザがフォームから「名前」を入力したとき、「<」「>」「&」「"」をそれぞれ文字参照に変換したとしましょう。これは HTML として出力されるシーンでは問題ありません。しかし、「名前」というデータは、メールヘッダの From: の値として出力されるかもしれませんし、SQLのクエリの中に使われるかもしれません。そのようなシーンが出現した場合、先ほど施した処理は不適切となります。入力時に処理をするという発想では、使用シーンごとに最適な処理ができないのです。
「この文字は HTML に出力するだけで、他には絶対に使用しない」という保証があれば問題はないでしょう。しかし、後に別の作業者がメール送信機能を追加するようなことがあれば、そこに危険が生じる可能性は否定できません。
この方法が有効なのは、機能追加や別の作業者の介在が全くないような小規模プログラミングの場合です。そのため、個人がフリーで配布しているような CGIプログラムでは、この手法が採用されていることがあります。
広義のサニタイズ
広義の「サニタイズ」は、処理のどこかでエスケープ等の処理を行うことを指します。データを受け取る際に処理する場合だけでなく、データを使用する際に処理する場合もサニタイズと呼びます。
プログラマにとっては、どの処理をどこで行うかは重要な問題です。しかし、脆弱性の検査や指摘を行う立場からすると、処理のタイミングはさほど重要ではありません。特に、ソースコードを見ないでブラックボックステストを行う場合は、処理のタイミングを知る術がありません。
※不適切な出力がなされている場合、タイミングが推測できることもあります。
この立場では、入力時に処理を行っているか、出力時に処理を行っているかということを区別することが難しい場合がありますし、区別する必要があまりありません。ですから、処理のタイミングにかかわらず「サニタイズ」と呼んでしまいます。
さらに広義のサニタイズ
さらに広義には、インジェクション系の脆弱性を防ぐ方法を総称してサニタイズと呼ぶことがあります。
純粋に脆弱性の有無だけの話をする場合、「サニタイズ」の目的が達成されていさえすれば、対応の具体的な手段は何であっても構わないためです。
たとえば、検索フォームに入力された文字がそのまま結果画面に出力されてしまい、任意の HTML が出力されてしまう問題があったとします。これは、広義のサニタイズを行っていないことが原因と考えられます。
この場合、具体的な対応としては以下のようなものが考えられます。
- 問題のある文字を文字参照に変換して出力する
- 問題のある文字を、他の文字に変換する (たとえば、半角の「<」を全角の「<」に変換)
- 問題のある文字を削除する
普通に考えれば、文字参照に変換する以外の方法には問題があるでしょう。「<」などを含む文字列が検索できなくなってしまったり、実際に検索している文字と表示されている文字が異なるという結果になってしまったりするためです。
しかし、純粋に脆弱性の有無だけの話をすると、どの方法でも対策はできているということになります。脆弱性を指摘して修正させる立場からは、「この方法では検索の機能が低下するので適切ではない」という指摘はしづらく、まあ直ったから良しとせざるを得ません。どの方法であっても「サニタイズされた」ことになります。
ところで、実はこんな対処法もあります。
- 問題のある文字が入力された場合に、「文字列が不正です」などのエラーにする
この場合どうでしょうか。これがサニタイズと呼べるのかどうかは、意見が分かれるところでしょう。プログラマの立場では絶対にサニタイズとは呼べないと思いますが、これも「サニタイズされていない」という指摘に対する対処のひとつであることに変わりはないのです。
そのようなわけで、このような処理をもサニタイズと呼ぶことがあります。ただ、ここまで来ると、もはや「セキュリティ対策する」という程度の意味しか残されておらず、用語として成立しないのではないかとする意見もあります。
※参考 : 「サニタイズ」という言葉はもう死んでいる (takagi-hiromitsu.jp)
- 「サニタイズ」へのコメント (2件)