perl は安全な setuid・setgid スクリプトを 安全に書くことができるように設計されている。 シェルは、スクリプトの各行を複数の置換のパスを通して実行するが、 perlはより伝統的な評価法を用いて、 隠れた"わけのわからないもの"を少なくしている。
さらに、perl にはより多くのビルトイン関数があるので、 目的を達するために外部の(そして多分信用できない)プログラムに頼る必要が少ない。
パッチを当てていない 4.2 や 4.3bsd カーネルでは、 setuid スクリプトは危険であると見なされるが、 このカーネルの機能は使用不可にすることができる。
そうしてある場合、perl は setuid・setgid 機構をエミュレートし、同時に、 そうでない場合にはスクリプトについている setuid/gid ビットは 意味のないものであることを知らせる。
カーネルの機能が使用不可になっていない場合、 perl は setuid スクリプトが危険であることを声高に注意する。 カーネルの setuid スクリプト機能を使用不可にするか、 スクリプトに C のラップをかけなくてはならない。
perl が setuid スクリプトを実行する時は、 明らかなトラップにはまらないような予防策を取る。 (幾つかの点で、perl スクリプトは同じ内容の C プログラムよりも安全である。)
コマンドライン引数、環境変数、入力はすべて"汚れている"と見なされ、 サブシェルを起動するコマンドや、 ファイル・ディレクトリ・プロセスを変更するコマンドには、 直接的であれ間接的であれ、使用が許されない。
過去に"汚れた"値を参照した expression でセットされた変数もまた "汚れる"("汚れた"値が変数に影響を及ぼすことが論理的に不可能であっても)。
例えば:
$foo = shift; # $foo は汚れている $bar = $foo,'bar'; # $bar もまた汚れる $xxx = <>; # 汚れている $path = $ENV{'PATH'}; # 汚れているが、下を見よ $abc = 'abc'; # 汚れていない system "echo $foo"; # 危険 system "/bin/echo", $foo;# 安全(sh は使わない) system "echo $bar"; # 危険 system "echo $abc"; # PATH がセットされないかぎり危険 $ENV{'PATH'} = '/bin:/usr/bin'; $ENV{'IFS'} = " if $ENV{'IFS'} ne "; $path = $ENV{'PATH'}; # 汚れていない system "echo $abc"; # 今度は安全! open(FOO,"$foo"); # OK open(FOO,">$foo"); # OK ではない open(FOO,"echo $foo|"); # OK ではないが... open(FOO,"-|") || exec 'echo', $foo; # OK $zzz = `echo $foo`; # 危険、zzz は汚れる unlink $abc,$foo; # 危険 umask $foo; # 危険 exec "echo $foo"; # 危険 exec "echo", $foo; # 安全(sh は使わない) exec "sh", '-c', $foo; # 安全とみなされる、ああ
"汚れ"は全スカラー値と結合しており、 配列の幾つかの要素は"汚れて"いても他の要素は大丈夫、ということも可能である。
何か危険なことをしようとすると、
`Insecure dependency' または `Insecure PATH' というメッセージと共に
致命的なエラーとなる。
それでも危険なシステムコールや exec
を書くことはできるが、
それは上の最後の例のような明らかな場合のみであることに注意。
また、"汚れ"機構をサブパターンを参照することで回避することもできる。
perl は $1
、$2
などを使ってサブストリングを参照する場合には
パターンを書いた人が何をやっているのかを知っているものだと仮定している。
$ARGV[0] =~ /^-P(\w+)$/; $printer = $1; # 汚れていない
\w+
はシェルのメタキャラクタにマッチしないので、
これはかなり安全である。
.+
を使っていたら危険であっただろうが、perl はそれをチェックしないので、
パターンには注意するべきである。
これは、ファイル操作を行う場合にユーザが与えるファイル名を"汚さない"ための
唯一の機構である。
($>
を $<
と同じにしないかぎり。)
"汚れた"値を気にかけない他の操作においてもトラブルを起こし得る。
ユーザが与えるファイル名を使ってファイルテストをする場合には、
よく考えるように。
可能ならば、 $> = $<
とした後で open
などを行った方がいい。
perl は"汚れた"名前のファイルを読み込みのために open
することを許す。
したがって、出力する内容には注意すること。
See section $> : プロセスの実効 uid for $>
, and See section $< : プロセスの実 uid for $<
.
"汚れ"機構は馬鹿げた間違いを防ぐために作ったもので、 何も考えなくてもよいようにするためのものではない。