WEB相談室

Webページ作成に関しての何でも掲示板です。

タイトル:掲示板等についているヘルプを

0:[投稿] makoto [2002/05/29 17:11 ][環境:WIN+IE WIN系+Perl]

初めまして、質問させてください。

WIN+IE6 AnHTTPd+ActivePerlで、最近Perlの勉強を始めました。
よく、掲示板でヘルプ等の表示がありますが、真似してみてもうまく表示されないのです。
具体的には以下のような書き方なのですが、

#!/usr/local/bin/perl

$script = 'test.cgi';

if ($mode eq 'how') { &how; }
&html;

sub html {
print <<"EOM";
Content-type: text/html

<HTML>
<HEAD><TITLE></TITLE></HEAD>
<BODY>
<A HREF="$script?mode=how">ヘルプ</A>
</BODY>
</HTML>
EOM
}

sub how {
print <<"EOM";
Content-type: text/html

<HTML>
<HEAD><TITLE></TITLE></HEAD>
<BODY>
これはヘルプです
</BODY>
</HTML>
EOM
}

メイン表示はsub htmlで、このルーチンにある<A HREF="$script?mode=how">ヘルプ</A>をクリックするとsub howルーチンが呼び出され、結果内容が表示されるようにしたいのです。

KENT WEBさんで公開されているファイルを見比べて書いてみたのですが、なかなかうまく行かないので質問させていただきました。
どこが間違っているのでしょうか?あるいは何か足りないのでしょうか。
ご教授をお願いします。


1:[回答] andi [2002/05/29 17:30 ]

3行目(空行除く)に if ($mode eq 'how') { &how; } とありますよね?
この $mode は恐らく <A HREF="$script?mode=how"> から渡される値のことを意識していらっしゃるのだと思いました。

しかし、スクリプトがブラウザから渡される値は $ENV{'QUERY_STRING'} という特殊な変数の中に格納されるので、
これを取り出して $mode に設定しておく必要があります。

しかも $ENV{'QUERY_STRING'} の中には mode=how という形で値が入っているので、
これを分解する処理が必要になります。

KENT WEBさんのスクリプトの中にも恐らくその処理が含まれていると思いますので、調べてみて下さい。


この処理を考えるのが面倒な場合はモジュールを使う方法もあります。

例)
> #!/usr/local/bin/perl
> if ($mode eq 'how') { &how; }

#!/usr/local/bin/perl
use CGI qw(:cgi);
if(param('mode') eq 'how') { &how; }


2:[回答] やじうま1号 [2002/05/29 17:35 ]

$script?mode=howとしてもPerlは$modeがhowだななんて理解してくれません(PHPなら出来るそうですが)。 なので、自分で処理をする必要があります。

@buf = split(/[&;]/, $ENV{'QUERY_STRING'};

foreach (@buf){
 local($key,$value) = split(/=/);
 $mode{$key} = $value;
}

とした上で、$mode{'mode'} eq 'how'と条件にかければ成功するはずです。(KENTでそういくのは、$mode = $mode{'mode'}のようなことをしているからです。)


3:[回答] ジングー [2002/05/29 17:50 ]

use strict;
でなくていいなら

foreach (split /&/,$ENV{QUERY_STRING}) {
my($key,$value) = split /=/;
$$key = $value;
}

で$modeに値が入りますが、ちょっと変かな。  


4:[回答] B-Cus [2002/05/29 18:44 ]

>>3
なにかとセキュリティにうるさい昨今、それはナシでしょう。

test.cgi?,=hoge という QUERY を送ることで
 $a='a';
 $b='b';
 print $a,$b,"\n";
の結果は ahogebhoge\n となります。

これでは危なくて仕方がない。


5:[完了] makoto [2002/05/29 19:42 ]

おお、短時間でこれほどレスをつけて下さるとは。

andiさん
なるほど・・・これも$ENVを使わなくては成らないのですね。
分解はやった事があるので、これは難なくクリア出来そうです。
いやはや、的確な回答ありがとうございます。
早速いじってみますね。

やじうま1号さん
Perlのクセと言いましょうか、また一つ分かりました。
これで一歩前進出来ます。ありがとう。

ジングーさん
B-Cusさん
それは危ない使い方なのでしょうか。
覚えておきますね。


6:[回答] ジングー [2002/05/29 19:54 ]

いやもちろん$keyの汚染はチェックしますが
やじうま1号さんのと並べて書いたほうがいいかと思ったので、
誤解を招く表現だったら申し訳ない。

$key =~ tr/a-zA-Z0-9_//cd;
$key =~ s/^\d+//;


7:[回答] andi [2002/05/29 20:23 ]

>> 6

変数を上書きされる可能性も・・・。


8:[回答] ふじ [URL] [2002/05/29 20:44 ]

>>6
use English;
してると、そのチェックもすり抜けて特殊変数を書き換えられてしまうおそれが。
そうでなくても、その処理以前に定義した変数が書き換えられてしまうのは
よろしくないでしょう。

$datafile = "< data.txt";
>>3 の処理
open OUT, $datafile;

みたいになってると悲惨です。

というか、自前でパラメータをばらすことをしないで、すなおに CGI.pm を使うのが
いいと思いますが。


9:[回答] B-Cus [2002/05/29 21:12 ]

> すなおに CGI.pm を使うのがいいと思いますが。

ときに、この辺 (サーバへの攻撃・XSS) のセキュリティ対策について、
最も優れた方法などういうのなんでしょうね。言語は perl として。


最近考えてみたことを書いてみると…

入力については、
 %allow_args = (
   'mode'=>qw[mode1 mode2 mode3], # mode は mode1 か mode2 か mode3 のいずれか
   'num'=>'m/^\d+$/', # num は数字のみ
   'name'=>'m/^.*$/', # 名前は何でもアリ
   'url'=> &check_url, # URL は複雑なので、チェック用関数に渡す
 );
などと、事前に許される形を定義しておく。それに反したら即エラー。

で、テンプレートを使った MVC モデルにして、
 1. 引数解析
 2. ログ記録や DB アクセス、データチェック
 3. テンプレートで HTML 表示 (JSP 的な感じで)
という順番で処理を行う。

入力された値へのアクセスは関数 &get('mode') のような
感じで、常に関数経由で行う。環境変数は標準入力は
1 の部分で全てクリアし、その後アクセスしても無効にさせる。

3 の最初の部分で内部フラグを「表示モード」に変える。すると
関数 &get は必ず < > & ' " を実体参照に変換して返すようになる。

これにより、3 の部分で &get('name') として、そこに < や > が
入っていても XSS 脆弱性は発生しない。どうしても生データを取得したい
場合は &get_raw('name') などとする。

ってのはどうでしょうか。perl のお手軽感は全くなくなって
しまいますが。


他には、HTML 出力時に

 HTML::HeadOpen();
 HTML::Title($title);
 HTML::HeadClose();
 HTML::BodyOpen();
 ...
 HTML::BodyClose();

といった関数を噛ませる方法 (関数内部で < > などをエスケープする)
もありますが、何かと繁雑になるので却下かなと。


10:[回答] ふじ [URL] [2002/05/29 21:51 ]

>>9
CGI::Application と HTML::Template というモジュールを
フレームワークとしてよく使ってます。

http://member.nifty.ne.jp/hippo2000/perltips/CGI/Application.htm
http://member.nifty.ne.jp/hippo2000/perltips/html/template.htm

どちらも Pure Perl なモジュールなので、ファイルを設置するだけで使えます。

HTML::Template ではテンプレートファイルで値を出力したいところに
<TMPL_VAR name="hoge"> のように記述するのですが、
<TMPL_VAR name="hoge" escape="html"> とすると、
自動的に < > & ' " がエスケープされて出力されます。
# 便利ですが、指定を忘れると生で出てしまうので、
# 完全な XSS 対策というわけではないですが。


11:[回答] andi [2002/05/29 22:16 ]

そう言えばご存知かもしれませんが「エスケープ処理では塞げないCSS脆弱性」という話題もありました。
http://www.asahi-net.or.jp/~ki4s-nkmr/mswatch42.html の25日の記事です。

当たり前と言えば当たり前の話ですが、意外に盲点かも。


12:[回答] B-Cus [2002/05/29 22:36 ]

>>10
> CGI::Application と HTML::Template というモジュールを
> フレームワークとしてよく使ってます。

うーむ、初心者が陥りがちなミスを防ぐ仕組みとしてちょっと弱いかなと
いう感じです。入力データのチェックはないようですし。

# 使っていないので間違ってたら失礼。お手軽なテンプレートフレームワーク
# としてはいいと思います。

>>11
> 「エスケープ処理では塞げないCSS脆弱性」という話題もありました。

これについては、入力データのチェックで防ぐことができるのでは
ないかと思っています。もし防ぎきれないとしたら、

 - データ処理は perl で。
 - 見栄えは HTML で。
 - ブラウザ操作は Javascript で。

というふうに3つを明確に分離する…というのはどうかなぁと (ただの妄想ですが)。


ちなみに、

> $output .= $q->start_html(-title => 'Widget Detail');

このタイプの弱点として
 - 結局 print "<html>\n" という書き方が可能。タグを知っている人は
   めんどくさいので全部 print で済ませてしまう。
 - プログラムとしてのインデントと、HTML のタグのインデントが
   混ざってしまう (あるいはプログラムのインデントしか付けられない)。
というのがあると考えています。


最近はもう面倒になって、穴が空きまくりの perl スクリプトを書く
日々です。部内サーバだからまぁいいんですが、他の人がそれを参考に
して商用のプログラムを書いてしまうので困っているところ。


13:[回答] ふじ [URL] [2002/05/29 22:59 ]

> うーむ、初心者が陥りがちなミスを防ぐ仕組みとしてちょっと弱いかなと
> いう感じです。入力データのチェックはないようですし。
そういう用途ですか。確かにそういうのには弱いですね。

入力データのチェックについては、自作のモジュールで
(仕事で作ったのでちと公開できないのですが、大したものではないです)

check($value)->is_num; # 数値だったら1を返す
check($value)->is_http_url; # URLだったら1を返す
check($value)->is_addr_spec; # 正しい形式のメールアドレスなら1を返す

みたいなのを作って、それでチェックさせています。
各自勝手にメールアドレスの形式チェックなんてのを実装するとロクなことがないので。
# が、怠慢が原因のチェック漏れはなかなか防げませんね。


14:[回答] ふじ [URL] [2002/05/29 23:06 ]

http://search.cpan.org/search?dist=CGI-Untaint
CGI::Untaint というモジュールがありました。


15:[回答] やじうま1号 [2002/05/30 16:56 ]

遅まきながら。

>>8
とりあえず基本として書いたまでです。

>>13
大崎さんのスクリプトを流用してます(汗)


16:[回答] ジングー [2002/05/31 01:34 ]

さらに遅まき。

>>7-8
そういえばそうですね。失礼。
$keyの内容チェックして…なんてやってる暇あったら
CGI.pm使うべきか。


17:[回答] ジングー [2002/05/31 01:34 ]

さらに遅まき。

>>7-8
そういえばそうですね。失礼。
$keyの内容チェックして…なんてやってる暇あったら
CGI.pm使うべきか。


18:[回答] ジングー [2002/05/31 01:35 ]

>>16-17
同一投稿すいません。

回答(必須): 状態:

お名前(必須):

e-mail:

URL:




[戻る]

ChaichanPAPA's World