Perl Perl_2
Perl 「 モジュール 」 CGI 実用的なファイルアップロード 14 続・汚染チェック (0x11b)

目次 - Perl Index
Theme
Perl について、復習を兼ねて断片的な情報を掲載して行く連載その 0x11b 回。
CGI.pm で、実用的なファイルアップロードの処理を確認する。その 14 回。実際のアップロードの処理を請け負うサブルーチンの中から、もうひとつの汚染チェックの内容を確認する。
続・汚染チェック
前回 (0x11a) では Cgi upload - perlmeme.org の例示に従って、ファイル名の文字列チェック ( 汚染チェック ) を行いましたが、今回はもうひとつの汚染チェックを確認します。「 one more thing 」です。
「 許可する 」汚染チェック
前回の汚染チェックを再確認します。それは、次のものでした。
if ($filename =~ /^([-\@:\/\\\w.]+)$/) {
$untainted_filename = $1;
} else {
die <<"EOT";
Unsupported characters in the filename "$filename".
Your filename may only contain alphabetic characters and numbers,
and the characters '_', '-', '\@', '/', '\\' and '.'
EOT
}
これは、正規表現パターン「 /^([-\@:\/\\\w.]+)$/ 」によるマッチングを行い、「 許可する 」文字の組み合わせのみを通過させるチェック方式でしたが、これに続いて、もうひとつの汚染チェックが行われます。
「 許可しない 」汚染チェック
今回確認する汚染チェックは、前回の「 許可する 」チェックと反対の「 許可しない 」チェックを行います。
前回のチェックは、条件式に「 適合した 」( 真 ) の場合に「 処理を継続 」していましたが、今回のチェックは条件式に「 適合した 」( 真 ) 場合に「 処理を中断 」( die ) する方式を採用しています。
Memo: 前回は「 ホワイトリスト 」。今回は「 ブラックリスト 」。
「 許可しない 」チェックのコード
「 もうひとつ 」の汚染チェックは、次のコードで行います。
if ($untainted_filename =~ m/\.\./) {
die <<"EOT";
Your upload filename may not contain the sequence '..'
Rename your file so that it does not include the sequence '..', and try again.
EOT
}
my $file = "/tmp/$untainted_filename";
print "Uploading $filename to $file
";
if 文の条件式には、「 /\.\./ 」の正規表現パターンが指定されています。これは、2 つの「 . 」( period ) が連続している場合に 真 になるパターンです。
前回確認した文字クラス「 [ ] 」の内部では単なる「 ピリオド 」でしかなかった「 . 」ですが、通常は、任意の 1 文字にマッチングするメタキャラクタとして扱われます。
そのため、ここでは、「 . 」を単なる文字として認識させるために、「 \ 」( backslash ) を利用してその効果を打ち消して ( エスケープして ) います。
「 .. 」を除外する意味
今回の汚染チェックは、ファイル名に「 .. 」( 2 つの連続した period ) を含む場合にプログラムを強制終了 ( die ) する様に書かれています。
このチェックの意味は、あくまで推測になりますが、Unix ライクなオペレーティングシステム ( Windows ではコマンドプロンプト上) で用意されている、ひとつ上の階層を意味する特別なディレクトリ「 .. 」が関係する様に思われます。
この特別なディレクトリを上手に悪用されると、システム内を任意に移動出来てしまう可能性があるので、予めこれを排除しているのではないかということです。
実際に FreeBSD の ports 等でプログラムをインストールする過程を眺めていると、「 .. 」を利用して、ディレクトリを縦横に移動していることが確認出来ます。
条件式が 真 の場合の処理
汚染チェックの条件式が 真 になった場合、つまり、ファイル名に連続する「 . 」( period ) が含まれる場合は、次の様に関数「 die 」を使ってプログラムを終了します。
die <<"EOT";
Your upload filename may not contain the sequence '..'
Rename your file so that it does not include the sequence '..', and try again.
EOT
}
プログラムを終了する際には、やはりその理由を記述したヒアドキュメントのメッセージを提示します。
Your upload filename may not contain the sequence '..'
Rename your file so that it does not include the sequence '..', and try again.
( あなたのアップロードするファイル名には 含めることは出来ません 連続する '..' を. リネームして下さい それが含まない様に連続する '..' を, それから 再度試行してください. )
( ? ): (0x116) で HTML で表示する際のヒアドキュメントの改行について確認したが、HTML 要素なしで改行が反映することを確認。おかしいな。要検証。
条件式が 偽 の場合の処理
ブラックリスト方式の条件式をクリアした場合は、次の処理に移ります。ここでは、システムの /tmp ディレクトリ直下に汚染チェックを経たファイル名でファイルを保存するための文字列を設定し、その旨をユーザに提示しています。
my $file = "/tmp/$untainted_filename";
print "Uploading $filename to $file<BR>";
0x11b -> 0x11c へ
前回確認した「 許可する 」チェックと、今回確認した「 許可しない 」チェックは、併せて 1 度の処理で済ませることも可能だと思われます。
しかしながら、相反するチェックを行う場合は、今回の様に別の構文に分けた方が、読み手に親切で、かつ、エラー発生時の切り分け等で優位である様に思います。
僕は、効率と冗長のはざまで揺れ動く場合は、どちらかといえば冗長気味に対応しておいた方が無難だと思う派閥です。つまり、迷った時はローコンテキストで会話しようとします。ですから、僕は、結果としてウザいやつです (テレ。
次回は、サーバ上への書き込み処理を確認します。
参考情報は書籍「 初めての Perl 第 6 版 」を中心に perldoc, Wikipedia および各 Web サイト。それと詳しい先輩。
目次 - Perl Index
Perl mp2 翻訳 Web コンテンツ圧縮の FAQ (d228)
Perl mp2 翻訳 既知のブラウザのバグの回避策をいくつか (d227)
Perl mp2 翻訳 Perl と Apache でのキュートなトリック (d226)
Perl mp2 翻訳 テンプレートシステムの選択 (d225)
Perl mp2 翻訳 大規模 E コマースサイトの構築 (d224)
Perl mp2 翻訳 チュートリアル (d223)
Perl mp2 翻訳 既知のブラウザのバグの回避策をいくつか (d227)
Perl mp2 翻訳 Perl と Apache でのキュートなトリック (d226)
Perl mp2 翻訳 テンプレートシステムの選択 (d225)
Perl mp2 翻訳 大規模 E コマースサイトの構築 (d224)
Perl mp2 翻訳 チュートリアル (d223)