- ベストアンサー
perl パラメータ
このようなソースがあります。 require "test.cgi"; これはperlを読み込めますが、 require "test.cgi/path"; としますと、500Errorです。 .cgiの後ろのPATH_INFOをrequireで読み込むperlのパラメータとして渡す方法はありますか。
- みんなの回答 (6)
- 専門家の回答
質問者が選んだベストアンサー
#1です。#2の補足からすると >require "/Users/$FORM{'directory'}/Sites$ENV{'REDIRECT_URL'}"; /Users/$FORM{'directory'}/Sites$ENV{'REDIRECT_URL'}" のパスのファイルがOS上の何かのコマンドで、それが危険なものかどうかを察知しようとしていますか? もし、そういう事であれば、apacheの設定でurlのパスとOSのパスで、そういうものをマッピングしなければいいだけに思えるのですけど。
その他の回答 (5)
- superside0
- ベストアンサー率64% (461/711)
もともとの問題とは別件なのかな・・ 単に、test.cgi/pathからpath部分を取り出したいということでなく Webサーバー(Apache)がtest.cgiとpathに切り分けされる前に リダイレクトされてるからPATH_INFOにセットされてない ってことですね。 $ENV{'REDIRECT_URL'} =~ s/\.cgi\/([\w|\!\#\&\=\-\%\@\~\;\+\:\.\?\/]+)$/\.cgi/g; としているのは、環境変数REDIRECT_URLに Webサーバー側でリダイレクト等されたときに設定されて これはブラウザからのもともとのURLがtest.cgi/pathのように PATH_INFO設定されたURLでも、そのままtest.cgi/path のままで になりますね。 そこで、この正規表現では、 *.cgiのあとの文字を取り消して cgiファイル名部のみにしてるということですね。 この場合、サーバー上にtest.cgiはあるけどtest.cgi/pathは存在をしないでので PATH_INFOに/pathをセットするということを apacheはしてくれないので その正規表現の切り取った部分のほうをPATH_INFOの変わりに使うしかないでしょう。
補足
PATH_INFOは解決できましたが、こんどはQUERY_STRINGで詰んでます。 *.cgi/path?*は表示できますが、*.cgi?*はエラーを吐きます。
- superside0
- ベストアンサー率64% (461/711)
私の説明がわるかったのか、 根本的に勘違いされているようです。 perlには、require "test.cgi/path"; のよう書いてINFO_PATH値を引き渡す機能はありません。 この書き方をすると test.cgiというディレクトリのしたのpathというファイルを 呼び出ししにいくだけです。 (ファイルが存在しない場合は、500エラーとかになりますね) ではなぜ、ブラウザでURLとして function.cgi/pathと指定することで CGIとして、function.cgi を呼び出て それにINFO_PATHとして"path"を渡せているかというと それはWebサーバーがそのように内部処理してくれているからです。 Webサーバーから CGI呼び出しで function.cgi に渡されたあとは Webサーバーを経由しないでperlのみの環境で動いている訳ですから、 perlでrequre('test.cgi/path'); と書いても、 perlはtest.cgiを呼び出してくれないわけです。 親CGIのfunction.cgiから 子側のtest.cgiをrequireで呼びたいのなら function.cgiでは、require('test.cgi');(pathなし) で呼び出すしかなく pathの実際の値を引き渡したいなら、 test.cgi側でfunction.cgiで作った変数なり Webサーバーがセットしてくれた 環境変数を使うしかありません。 ようするに、test.cgiは function.cgiから呼ばれる 単なるサブルーチンとしてつくる形ですね。
補足
そこでエラーを出ないようにやってみたのが。 $ENV{'REDIRECT_URL'} =~ s/\.cgi\/([\w|\!\#\&\=\-\%\@\~\;\+\:\.\?\/]+)$/\.cgi/g; ところが、これをやってしまうと、呼び出し先のCGIで$ENV{'PATH_INFO'}とやっても表示できないのです。 REDIRECT_URLはapacheのmod_rewriteを使ってリダイレクトしてるので、リダイレクト元のパスを取得するためですね。 下の方の回答でスクリプトを書いてますので、ご確認いただけると幸いです。 そもそも、 リダイレクトせずにapache側で文法をチェックできればいいのですが……。
- superside0
- ベストアンサー率64% (461/711)
あ、ごめんなさい。日本語おかしかったですね。 > URL中のGETパラメータは、そのままでCGIがコールされるのではなくて >Webサーバーから環境変数QUERY_STRINGにされて >で渡されるので、CGI側ではそれを使います。 ↓ URL中のGETパラメータがそのままCGIに渡されているのではなく Webサーバーで環境変数QUERY_STRINGにセットされてから 渡されるので、CGI側ではその環境変数を使って動作させます。 でした。 しかも、今回の問題はGETパラメータでなくPATH_INFOですね。 ただ、PATH_INFOも、環境変数名がPATH_INFOになるだけで 考え方は同じです。 つまり、ブラウザからURLとしてtest.cgi/path で渡されると Webサーバーは、環境変数PATH_INFOに /pathをセットしてから test.cgiをCGIコールしています。 (test.cgi/pathというファイル名で実行している訳ではないことに注意) よって、CGIからCGIをシステムコールで呼で出す場合は、 これを模擬する必要があります。 しかし、requireで呼び出すのであれば、 CGIとしてコールしていのではなくサブルーチン実行のようなものなので 渡したい値は、サブルーチンの引数にするとかグローバル変数にしておけばそのまま渡せます。 つまり (1) 出来合いのCGIを呼び出したいが、それを改造することが難しいのなら 親側のCGIで環境変数代入と子側のCGIのコールをセットにして システムコールする方式 (2) 自作のCGIをrequire で呼ぶなら、test.cgi側では GET/POST/PATH_INFOの値は使わずに 親側から変数をもらって動作するように改造する方式 のどちらかになるでしょう。
補足
すみません、言葉足らずでした。 test.cgiを呼び出すCGIをfunction.cgiとし、function.cgiではtest.cgi(.cgi拡張子のperlなら別のファル名でもいい)の文法で特定の文字列、例えばsystem関数とかがあったらfunction.cgi側でエラーメッセージを出し、問題がなければ通過して、読み込みたいtest.cgiをブラウザ上で実行したいです。この時に、URL上でtest.cgi/pathとしても、test.cgi内で$ENV{'PATH_INFO'}で表示したくても、何も代入されず、逆にfunction.cgi側でtest.cgi/pathとしてしまうと、500エラーが返されるわけです。
- superside0
- ベストアンサー率64% (461/711)
URL中のGETパラメータは、そのままでCGIがコールされるのではなくて Webサーバーから環境変数QUERY_STRINGにされて で渡されるので、CGI側ではそれを使います。 つまり、cgiから別のcgiをシステムコール (system()とかpopenとか)するなら 親側とは、別プロセスになるのでGETパラメータにしたいものは 環境変数QUERY_STRINGにセットしてからシステムコールするという工夫が必要です。 しかし、今回のはrequire()で呼ぶ形で実行できるCGIのようなので それならサブルーチンで実行するようなものなので 同じプロセス内なので、親側のグローバル変数なりを test.cgi内でそのままつかえばよいのでは?
補足
下記、スクリプト。 引っかかってるのは、たぶん「$ENV{'REDIRECT_URL'} =~ s/\.cgi\/([\w|\!\#\&\=\-\%\@\~\;\+\:\.\?\/]+)$/\.cgi/g;」だけど、これないとrequireでエラー出るし、ここの部分を直すにしてもどういう文法にすれば見当がつかずでして。 #!/usr/bin/perl require "./jcode.pl"; &decode; sub decode { if ($ENV{'REQUEST_METHOD'} eq "POST") { read(STDIN, $buffer, $ENV{'CONTENT_LENGTH'}); } else { $buffer = $ENV{'QUERY_STRING'}; } @pairs = split(/&/,$buffer); foreach $pair (@pairs) { ($name, $value) = split(/=/, $pair); $value =~ tr/+/ /; $value =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg; $buffer =~ tr/+/ /; $buffer =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg; &jcode'convert( *value, 'utf8' ); $FORM{$name} .= $value; } } $ENV{'REDIRECT_URL'} =~ s/\.cgi\/([\w|\!\#\&\=\-\%\@\~\;\+\:\.\?\/]+)$/\.cgi/g; open(ERROR, "/Users/$FORM{'directory'}/Sites$ENV{'REDIRECT_URL'}"); @error = <ERROR>; foreach (@error) { if($_ =~ /system\(/){ print "Content-type: text/html\n\n"; print <<"EOM"; <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>強制停止</title> </head> <body> <center>システムが危険な関数を検知したので、プログラムを強制停止しました。</center> </body> </html> EOM exit; } } require "/Users/$FORM{'directory'}/Sites$ENV{'REDIRECT_URL'}"; exit;
- wormhole
- ベストアンサー率28% (1626/5665)
ないです。 require は指定のパスにあるファイルをperlのプログラムが書かれたファイルとして読み込み機能ですから require "test.cgi/path"; test.cgiディレクトリにあるpathというファイルを読込むだけです。
補足
では、test.cgi/pathをtest.cgiとして読み込んでくれ、かつ/pathの部分をPATH_INFOとして出力できる関数はありますか?
補足
URL上でリクエストのあったファイルをopenして、ソースコード中にsystem関数があったら、エラーを文を表示し、なければ通過してリクエストされたファイルを読み込んで表示させる、といったことですね。 いろいろいじくって、リクエストされたファイルのソースコードでPATH_INFOの記述でURL上のPATH_INFOは取得できるようになったのですが、今度はQUERY_STRINGがエラーを吐きます。 *.cgi?aaaというのはエラーが出ますが、*.cgi/path?aaaの場合はなぜか表示できます。