CGIのエラーの原因を知りたい

[上に] [前に] [次に]
M [E-Mail] 1999/09/28(火) 20:12:48
はじめまして。いつもこちらにお世話になっています。
私は今日初めてperlに挑戦してみたのですが、
どうにもうまくいかないので、教えていただきたいと思い投稿しました。
CGIを使って、
ダウンロードするファイルを選んでもらう
→新しいディレクトリにそのファイルをコピーする
→それをLHAで圧縮する
→ダウンロードさせる
ということをしたいのですが、
自分の書いたCGIでテストすると、
http://xxxxx/xxx.cgiを開けません。
  Windowsインターネットエクステンションで
  内部エラーが発生しました」
(↑IEの場合の表示)となってしまいます。
しかしこの時ダウンロードさせたいLZHファイルは意図した通りにできています。
このエラーの原因は何なのでしょうか。
このエラーメッセージを初めて見たので
どういうものなのか全然分かりません。
何かとんでもない間違いをしているのでしょうか…。

また、テスト時にサーバ上にできたディレクトリが
削除できなくなって困っています。
コピーしたpacファイルが、削除できないようなのです。
FTPソフトでは削除した後も消えないし、
telnetで消そうとすると
rm: public_html/cgi-bin/download/oyatsu4/choco.pac: Permission denied
のようになって消せません。
パーミッションを変更しようとすると、
chmod: public_html/cgi-bin/download/oyatsu4/choco.pac: Operation not permitted
となってやはり変更できません。
こちらの原因・解決法もわかれば知りたいと思っています。

問題のCGIは、
http://mizu.lovely.to/test_cgi.txt
に置いてあります。
ちなみに都合上ここに置きましたが実際に設置するのはAISNETです。

長文になって申し訳ありません。
よろしくお願いいたします。

ふじ 1999/09/28(火) 20:30:23
ダウンロードさせたいファイルを cgi-bin/download 以下に作って
そこに Location で飛ばしているようですが、そのディレクトリのファイルは
読み取り可になってますか?
#具体的にはブラウザでそのURLを直打ちして、ダウンロードできるかどうかということ。

>コピーしたpacファイルが、削除できないようなのです。
ファイルを作った後に(スクリプトの中で)

chmod 0666, $filename;

としてパーミッションを変えましょう。
telnet で消せないファイルの所有者とパーミッションを見てみて下さい。

M 1999/09/28(火) 21:49:28
回答ありがとうございます。
ファイルの削除が出来なかった問題については、
パーミッションを変更しても消せなかったのですが、
lha a ...としていたところを lha ad ...と直して
スクリプトの中で削除するようにしました。

CGIのエラーはまだ直せません。
ダウンロードさせたいファイルは、
直にURLを打ち込んだ場合はダウンロードできます。
この場合どこを直せばいいのでしょうか。

B-Cus 1999/09/29(水) 01:24:05
 print "Location: $url\n\n";
の前に
 system($command2);
で lha コマンドが標準出力に書き出してるんじゃないの?
うちの lha はアーカイブ作るときに標準出力に
 foo.c  - Frozen(36%) oo
 bar.c  - Frozen(29%) oooooo
 baz.c  - Frozen(44%) o
ってのを出力するけど。

もしそうなら
 system("$command2 >/dev/null");
とか。

# まずは先頭に print "Content-type: text/plain\n\n"; を書いて
# デバッグするのが吉。

> 実際に設置するのはAISNETです。
可能なら、そのURLを公開するのが一番話が早いです。

B-Cus 1999/09/29(水) 01:33:31
あ、セキュリティホールがあるので、公開しちゃまずいか…。

引数に hoge;ls; とか fuga;rm -rf /; とか入力されるとまずいので、
引数が適正かどうかをチェックしましょう。systemに文字列でなく
配列で渡すってのも可。

サンプルなのでチェック部分を省略してるだけなら失礼。

moci [E-Mail] 1999/09/29(水) 01:47:33
> 実際に設置するのはAISNETです。

げっ…(笑)
最初からlzhファイルを置いておくのはダメなんですか?^^;

AISNETではCGIはnobodyで動きます。スクリプトで生成する
ディレクトリもファイルもnobodyの所有です。
当然、telnetで入っても消せはしないし、パーミションも
変えられません。ふじさんの言われるように、CGIの中で
パーミションを変えておけば、消せることは間違いありません。
実績あり。ディレクトリのパーミションを変え忘れてませんか?

M 1999/09/29(水) 02:37:53
B-Cusさん>
> system("$command2 >/dev/null");
この方法で上手くいきました。
ありがとうございます!
>あ、セキュリティホールがあるので、公開しちゃまずいか…。
それには自分で気がついていませんでした。
引数をどういう基準でチェックすればいいのかわからないのですが、
どういう引数だと危険なんでしょうか?
$ENV{'HTTP_REFERER'}を使って自分の設置したフォームからしか
アクセスできないようにするのでは不十分ですか?
(フォームはcheckbox・radio・submitだけで作ります)

mociさん>
>最初からlzhファイルを置いておくのはダメなんですか?^^;
今はそうしているのですが、ファイルが多くなってくると、
欲しいファイルだけをまとめてダウンロードできたら
便利かな、と思いまして…。
>パーミションを変えておけば、消せることは間違いありません。
>実績あり。ディレクトリのパーミションを変え忘れてませんか?
ディレクトリのパーミッションは755のままにしていました。
これが原因だったんですね。すみません。

Selly 1999/09/29(水) 02:52:17
> $ENV{'HTTP_REFERER'}を使って自分の設置したフォームからしか
> アクセスできないようにするのでは不十分ですか?

不十分です。
HTTP_REFERERはUA側の自己申告なのでいくらでも改竄できます。
実際にそういうことを行うツールも存在しています。

B-Cus 1999/09/29(水) 03:39:44
> どういう引数だと危険なんでしょうか?
例えば、cp の部分を短く書くと
 system("cp ../../oyatsu/$QUERY{gen}/$QUERY{os}/$pac.pac ./oyatsu.$cnt")
となるわけ。ここで $QUERY{os} に「mac;/bin/rm -rf /;」を
入力されたとする。つまり
 system("cp ../../oyatsu/hoge/mac;/bin/rm -rf /;$pac.pac ./oyatsu.$cnt");
が実行されるんね。「;」はマルチステートメントを意味するので、
 system("cp ../../oyatsu/hoge/mac");
 system("/bin/rm -rf /");
 system("$pac.pac ./oyatsu.$cnt");
が実行されるのと同じであると。そしたら、rm -rf / で、nobody権限で消せる
ファイルが全部消えてしまう。つまり、同じサーバの他の人のファイルも消えて
しまうことに…ってこと。

なので、
 if ( $QUERY{os} ne "mac" && $QUERY{os} ne "Win" ){ &error }
 if ( $QUERY{gen} =~ m/[^\-a-zA-Z0-9_\.]/ ){ &error }
などとチェックしましょう。大事なのは「危ないものを弾く」のではなく、
「安全なもの以外を弾く」ようにすること。例えば「;」と同様に
「<」「>」「|」なども危険です。

あと、
 @command = ("lha","a",$file,$dir);
 system(@command);
などと配列で渡すと、$file や $dir に「;<>|」などが入っていても
無視されます(というか、「;<>|」などを解釈する役目の sh が起動されなくなる)。


どーでもいいですが、僕ならこう書きます。
 chdir "$oyatsudir$QUERY{gen}/$QUERY{os}/";
 @pacs = split(/&/,$QUERY{oyatsu});
 print "Content-type: application/x-lzh\n";
 print "Content-Disposition: attachment; filename=$dirname.lzh\n\n";
 open(LHA,"lha a - @pacs|");
 print <LHA>;

M [E-Mail] 1999/09/29(水) 04:24:54
[[解決]]
回答ありがとうございます。
HTTP_REFERERは常に信用できるものではないんですね。
B-Cusさんに教えていただいた通り、
引数のチェックをして、systemも配列にしようと思います。
>大事なのは「危ないものを弾く」のではなく、「安全なもの以外を弾く」ようにすること。
これは勉強になりました。
スクリプトの書き方は、まだわからない部分が多いので
もっと勉強したいと思います。

お答えくださった皆さん、本当に有り難うございました。

[上に] [前に] [次に]