9.4. シェルスクリプト言語(sh と csh 系)

setuid もしくは setgid した安全が求められるコードには、標準的なコマンドシェル のスクリプト言語(csh や sh、bash のような)を採用しないよう、強く推奨します。 システムには(Linux のような)、setuid や setgid したシェルスクリプトを完全に 無効にしているものもあり、setuid や setgid したシェルスクリプトを作成すると、 移植性の問題がさらに発生します。 古いシステムでは、そもそもシェルスクリプト言語は安全ではありません。それは 競合状態を起こすからです(Section 3.1.3 で論じたように)。 その他のシステムにとっても、あまり良いとはいえません。

実際のケースでは、シェルスクリプト言語を安全が要求されるプログラムに使うべき ではない場合がよくあります。 標準的なコマンドシェルは、あいまいな入力に左右されてしまうのは周知の事実です。 普通コマンドシェルは、対話的に利用してるユーザに対して、「自動的に」 動作するように設計してあります。したがって、クラックする決意を持った人間には 対抗できません。 シェルプログラムは、安全にする必要が求められないプログラムにとっては、 素晴らしいプログラムです(たとえば、特権を持たないユーザと同じ権限で実行でき ますし、「信頼できない」データも受けつけません)。 また、入力すべて(たとえば、ファイルやディレクトリ、コマンドライン、環境 変数他)が、信頼できるユーザからのものである限り、特権を持って動作するのには 好都合です。起動時や終了時のスクリプトに非常に良く採用されているのはこのため です。

悪意ある入力が存在する状況で、安全なシェルプログラムを作成するのは、 他の言語に比べて困難です。理由は、シェルはすべてから影響を受けるからです。 たとえば、「見えない」環境変数(たとえば、ENV や BASH_ENV、IFS の値)は、 操作方法に影響しますし、スクリプトが実行される前に、ユーザが定義した任意の コードを実行することさえ可能です。 実行ファイル名やディレクトリの中身のようなものでさえ、実行に影響します。 攻撃者が制御文字(たとえば改行)や空白、シェルのメタキャラクタ、ダッシュ (オプションを示すフラグ)ではじまるファイル名を作れると、それがつけ込む隙を 与えることになります。 たとえば、Bourne シェルの実装の多くは、下記のコードを実行すると、root で のアクセスを認めてしまいます(この脆弱性を提示してくれた NCSA に感謝します)。
 % ln -s /usr/bin/setuid-shell /tmp/-x
 % cd /tmp
 % -x
システムによってはこの穴を塞いでいるものもありますが、問題が解決した訳では ありません。コマンドシェルの大部分が、安全に setuid や setgid したプログラム を書くようにはできていないからです。 プログラムの目的として、setuid したシェルスクリプトの作成は避けてください。 システムが setuid したシェルスクリプトを許していてもです。 そのかわりに、別の言語で小さなプログラムを作成して、環境をクリアにしてから、 他の実行形式(シェルスクリプトであるかもしれません)を呼ぶようにしましょう。

それでもシェルスクリプト言語の利用にこだわるなら、少なくとも移動もしくは 変更できないディレクトリにスクリプトを置いてください。 PATH と IFS には、スクリプトの最初の方で既知の値を設定してください。実際、 環境はスクリプトが呼ばれる以前に整えておくべきです。 また最初の方で「cd」して、安全なディレクトリに移動しておいてください。 データを使うなら /etc のような、信頼できるユーザが制御しているディレクトリ からのデータにしてください。攻撃者は、そのようなディレクトリに、悪意を持って 名付けたファイルは入れられませんので。 ファイル名はすべて必ず引用符で囲んで コマンドラインに渡してください。たとえば、$1 ではなく "$1" のように。理由は、 空白が入ったファイル名が分割されてしまうからです。 「--」を使ってコマンドを呼び出し、オプションがさらに追加できない ようにしてください。攻撃者がダッシュではじまるファイル名を作成したり、渡して きたりして、プログラムをひっかけてオプションであるかのごとく処理させようと するかもしれないからです。 入力ファイル名を注意深く調べ、許可するファイル名には制限をきつくかけて ください。

同じ意味合いで、安全なポリシを実装している「制限付きのシェル(restricted shell)」を信頼するのは、お薦めできません。 制限付きのシェルは、あえてユーザにさまざまな処理を実行できないようにする シェルです。目的は、ユーザにごく限られたプログラムだけを動作させることです。 制限付きシェルは、念には念を入れる手段としては有効ですが、正確に設定できない のは有名で、設定してもよく破られてしまいます。 たとえば制限付きシェルには、ファイル(たとえば、「.profile」)に制限をかけない 状態で実行してから、動作するものがあります。 ユーザがこのファイルを変更できれば、そのコードを実行させてしまいます。 制限付きシェルは、限られた少数のプログラムだけを実行するように設定するべき です。しかし、それらのプログラムのどれかが「シェルエスケープ」を使って、 ユーザがさらにプログラムを動かせるようになっていれば、攻撃者はそのシェル エスケープを利用して制限付きシェルを回避してしまいます。 もちろん、制限付きシェルの PATH を設定していなければ(どんなプログラムの動作 も許可)、攻撃者はプログラムの多くでシェルエスケープを利用できます(テキスト エディタや メールリーダー等)。 問題は、シェルの目的がそもそも他のプログラムの実行にある点です。他のプログラム が、望んでいない操作を認めているかもしれません。シェルは、これらの操作の防止 には介入しません。