perlについての質問です。フォームに外部からダイレクトにアクセスされないように、フォームが開いていれば(displayがblockなら)送信許可、そうでなければ(displayがnone(初期設定)なら)拒否というものを考えています。JavaScriptでは以下の感じだと思うのですが、これでは外部対策にはなっていないので、”regist.cgi”に書き込むperlの書き方を教えてください。よろしくお願いします。


function check() {
if(document.getElementById("form").style.display == "block"){
return true;
}else{
return false;
}
}

<form action="./regist.cgi>
<input type="submit" value="送信" onclick="return check();">
</form>

回答の条件
  • 1人5回まで
  • 登録:2009/12/25 13:12:05
  • 終了:2009/12/29 14:02:30

ベストアンサー

id:kn1967 No.2

kn1967回答回数2915ベストアンサー獲得回数3012009/12/26 02:35:35

ポイント100pt

非常に簡素な例

(1)form.cgi

#!/usr/bin/perl --
#
# クッキーの準備
my $limit = 5; # クッキーの有効期限を5秒とする
my ($sec,$min,$hour,$mday,$mon,$year,$wno) = gmtime(time + $limit);
my @wdays = ('Sun','Mon','Tue','Wed','Thu','Fri','Sat');
my @mons = ('Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec');
my $expires = sprintf("%s, %d-%s-%d %02d:%02d:%02d GMT",$wdays[$wno],$mday,$mons[$mon],$year+1900,$hour,$min,$sec);
#
# クッキー出力
# 変数の値はURLエンコードが必要になる場合があります。
# 今回は$limitの値が数字なので手抜きして行ってません。
print "Set-Cookie: TimeLimit=$limit; expires=$expires;\n";
#
# ヘッダー出力
print "Content-Type:text/html\n\n";
#
# コンテンツ出力
print<<"END";
<html>
<body>
<form action="./regist.cgi">
<input type="submit" value="送信">
</form>
</body>
</html>
END

(2)regist.cgi

#!/usr/bin/perl --
#
# ヘッダー出力
print "Content-Type:text/html\n\n";
#
# クッキー読み取り(事前作業はありません。いきなり環境変数を参照すればOKです。)
print "クッキーの中身は[" . $ENV{'HTTP_COOKIE'} . "]です。";
#
# クッキーは通常URLデコードと変数毎の分離作業が必要ですが、今回は省いてます。
if ($ENV{'HTTP_COOKIE'} !~ /TimeLimit/) {
    print "有効期限切れです。";
    exit;
}
# 以下、登録処理や確認出力を行う。

※ページ遷移を伴わずに実行しようとすれば

 ajaxの非同期通信が必要になってくるのですが、

 直接飛んでくるような輩を弾く仕組みとしては、

 上記の通りjavascriptは無関係。

※タイムリミットは5秒にしてありますので、フォームから呼んだ場合と

 時間を空けて直接regist.cgiを呼んだ場合の動作の違いを見てください。

※上記は非常に手抜きで簡素なサンプルです。セキュリティに関する事なので、

 実装の際には、クッキーについてご自身なりに調べてからにしてください。

id:tontonpokopoko

kn1967 さん、わざわざプログラムを書いていただきありがとうございます。

現状で使っているのはフリーで配布されたフォーム(クッキーも取得)で、

何とか上記と組み合わせてみようと思いましたが、私の知識では無理でした。

コメント欄に現在のクッキーを書き込んでおきますので、

もし宜しければ修正していただければ幸いです。

*情報提供不足や作業が複雑なようなら無視してください。現在の知識で出来ることを考えて見ます。

上記のものは今後にまた悩んだときに参考にさせていただきます。

2009/12/27 01:39:02

その他の回答(2件)

id:mattn No.1

mattn回答回数104ベストアンサー獲得回数232009/12/25 13:28:56

ポイント80pt

javascriptはクライアントサイド、cgi(perl)はサーバサイドなので対策方法も異なります(display:blockはperl側には関係ありません)。

実際display:noneとした所でアドレスバーから

javascript:document.getElementById('form').style.display = 'block';void 0

としてしまえば回避できます。

外部からのダイレクトにアクセスされるのを弾くのであれば、リファラを確認するのが良いかと思います。

if ($ENV{"HTTP_REFERER"} !~ /^http:\/\/example.com\/.*/) {
  # 不正アクセス
}

ただし実際にはこれでもすり抜けられるのは、おそらくご存知かと思います。難解にするという意味で以下の様にする方法もあります。

ページA:登録前ページ
ページB:登録処理ページ

Aの表示時に特殊なクッキー値を渡し、B(CGI)で確認します。

Perlからcookieは「$ENV{"HTTP_COOKIE"}」で参照出来ます。

これも完璧な防御方法ではないので、実際には直接アクセスされても大丈夫な風に作っておくべきかと思います。

もちろんCGIはPOSTクエリでないと処理が実行されないように作っておくべきです。

id:tontonpokopoko

mattnさん、参考になります、ありがとうございます。

弾きたいのは外部からの直アクセス(無差別)なので、

アドレスバーで操作するくらいの「人?」はとりあえず歓迎です。

リファラは偽造(内部からアクセス)されているのを当然と考えています。

(すでに取り入れています)

3番目に書いてくれた方法に興味を持っています。

もちろんクッキーを読み取ってしまえば簡単に突破できるでしょうが、

こちらも即変更が可能なので最初の1歩としては、かなり効果があると思えます。

perlの登録処理ページで正しいクッキーかを確認する方法を教えていただけないでしょうか?

クッキーをjavascriptで取得(この場合、displayの変更時)したら、perlに値を渡す必要があるのでしょうか?

知りたいのはjavascriptで取得したクッキーを、

perlの登録処理ページで正しいかを確認する書き方です。

よろしくお願いします。

2009/12/26 00:29:03
id:kn1967 No.2

kn1967回答回数2915ベストアンサー獲得回数3012009/12/26 02:35:35ここでベストアンサー

ポイント100pt

非常に簡素な例

(1)form.cgi

#!/usr/bin/perl --
#
# クッキーの準備
my $limit = 5; # クッキーの有効期限を5秒とする
my ($sec,$min,$hour,$mday,$mon,$year,$wno) = gmtime(time + $limit);
my @wdays = ('Sun','Mon','Tue','Wed','Thu','Fri','Sat');
my @mons = ('Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec');
my $expires = sprintf("%s, %d-%s-%d %02d:%02d:%02d GMT",$wdays[$wno],$mday,$mons[$mon],$year+1900,$hour,$min,$sec);
#
# クッキー出力
# 変数の値はURLエンコードが必要になる場合があります。
# 今回は$limitの値が数字なので手抜きして行ってません。
print "Set-Cookie: TimeLimit=$limit; expires=$expires;\n";
#
# ヘッダー出力
print "Content-Type:text/html\n\n";
#
# コンテンツ出力
print<<"END";
<html>
<body>
<form action="./regist.cgi">
<input type="submit" value="送信">
</form>
</body>
</html>
END

(2)regist.cgi

#!/usr/bin/perl --
#
# ヘッダー出力
print "Content-Type:text/html\n\n";
#
# クッキー読み取り(事前作業はありません。いきなり環境変数を参照すればOKです。)
print "クッキーの中身は[" . $ENV{'HTTP_COOKIE'} . "]です。";
#
# クッキーは通常URLデコードと変数毎の分離作業が必要ですが、今回は省いてます。
if ($ENV{'HTTP_COOKIE'} !~ /TimeLimit/) {
    print "有効期限切れです。";
    exit;
}
# 以下、登録処理や確認出力を行う。

※ページ遷移を伴わずに実行しようとすれば

 ajaxの非同期通信が必要になってくるのですが、

 直接飛んでくるような輩を弾く仕組みとしては、

 上記の通りjavascriptは無関係。

※タイムリミットは5秒にしてありますので、フォームから呼んだ場合と

 時間を空けて直接regist.cgiを呼んだ場合の動作の違いを見てください。

※上記は非常に手抜きで簡素なサンプルです。セキュリティに関する事なので、

 実装の際には、クッキーについてご自身なりに調べてからにしてください。

id:tontonpokopoko

kn1967 さん、わざわざプログラムを書いていただきありがとうございます。

現状で使っているのはフリーで配布されたフォーム(クッキーも取得)で、

何とか上記と組み合わせてみようと思いましたが、私の知識では無理でした。

コメント欄に現在のクッキーを書き込んでおきますので、

もし宜しければ修正していただければ幸いです。

*情報提供不足や作業が複雑なようなら無視してください。現在の知識で出来ることを考えて見ます。

上記のものは今後にまた悩んだときに参考にさせていただきます。

2009/12/27 01:39:02
id:azuco1975 No.3

azuco1975回答回数613ベストアンサー獲得回数162009/12/27 19:57:23

http://www.kanzaki.com/docs/html/htminfo32.html

とりあえずPOSTメソッドに変更するだけでかなりマシです。

次にhiddenタグをつかってタイプスタンプ等を代入してその都度

CGIでチャックすればかなり安全

  • id:kn1967
    えーーーっと。
    perl はサーバ上で動いてる事はご存知ですよね?

    クライアントのブラウザが今どのような状況なのかという事は、
    サーバ上のプログラムから直接見ることは出来ないって事は、ご存知でない?

    外部対策と言っても、リファラだって騙せるし、そもそも、
    IEやFirefoxなどのブラウザじゃなくて、プログラムからアクセスされてたら・・・
    何をやっても対した意味はないですよね。

    Flashでフォーム作るなどの手を使うサイトもあるけど、
    通信を解析されたら一発だし・・・。

    インターネットというオープンな環境でのやりとりなので、
    基本的には完全な方法ってのはなかったりする訳だけど、
    クライアントとの関係(オープンか、会員制かなど)や、
    どの程度の信頼性(単純にいたずら防止か?)を確保したいのかによっては、
    ある程度までは対処のしようもあったりはしますので、
    そのあたり書き込んで相談してみては?
  • id:tontonpokopoko
    kn1967 さん、いつもありがとうございます。
    >サーバ上のプログラムから直接見ることは出来ないって事は、ご存知でない?

    お恥ずかしいことにその通りでした。(言われてみればもっともで)
    今回の外部対策は、自分のサイト特定ではなく無差別で考えています。
    そのため最低限のことだけはやっておきたいと考えている状況でした。

    perlには、できるなら時間をかけたくないというのが本音で、
    ここで登録処理ページの書き方を聞いている次第です。
  • id:KeyKey
    特にperlの書き方というわけではないのでコメントで

    ある程度でいいのであればセッションを使うのが早いかな
    Aページでセッション発行してそのセッションに認証OKとわかる値を格納
    Bページでセッションを確認して認証OKであれば処理を実行

    そのあと保存されてる認証を削除すれば
    Bにアクセスするためには必ずAを通させるといったこともできるかと
  • id:kn1967
    perl の場合、どのモジュールが使いやすいのかとか、そもそも、
    「セッションを行うためのモジュールが導入されているかどうか?」
    って話になりますよね。
  • id:tontonpokopoko
    KeyKey さん、コメントをありがとうございます。
    セッション発行を簡単に調べましたが、にわか仕込みではとても厳しそうでした。
    今後にデータベースなど勉強する機会がありましたら参考にさせていただきます。
  • id:kn1967
    一部だけを提示されても具体的な場所は示せないのですが、
    全体を示せというのもまた無理な話なので、以下、概略のみ。

    (1)クッキーには複数のキーと値の組を含む事が出来ます。

    私の書いた form.cgi のクッキー出力を下記3行に増やして動かしてみてください。
    そうすれば、regist.cgi のほうが中身を出力してくれますので、確認ができます。
    print "Set-Cookie: TimeLimit=$limit; expires=$expires;\n";
    print "Set-Cookie: test1=aaaa; expires=$expires;\n";
    print "Set-Cookie: test2=bbbb; expires=$expires;\n";

    幸いにもキーが異なる(myDataとTimeLimit)ので、
    双方を同時に利用する事に問題はありません。

    (2)form.cgiへの組み込み

    クッキーへの書き込み作業はコンテンツ本体出力の前に行う必要があります。
    あなたが使っておられる form.cgi にも
    print "Content-Type:text/html\n\n";
    という部分があるはずですから、その直前にでも、
    クッキーを生成して出力する部分を加えてください。

    (3)regist.cgiへの組み込み

    あなたが使っておられる regist.cgi の先頭のほうにでも、
    TimeLimit がクッキーに存在しているかどうかを確認するコードを加えてください。
  • id:tontonpokopoko
    kn1967 さん、わかりやすい解説をありがとうございます。
    以下、TimeLimitとしてクッキーを取得、正常に動作したのですが・・

    ただ何度か書き込みを試していると、
    TimeLimitとしての情報が消えてしまう(クッキーが削除されてる?)ことがあるんです・・

    エラーに”$ENV{'HTTP_COOKIE'}”とすると、
    myDataのクッキーだけが表示される状態です・・

    いったい何故なのでしょう・・?

    これが↓
    myData=何たらかんたら; TimeLimit=5; test1=aaaa; test2=bbbb

    これだけになってしまう↓
    myData=何たらかんたら
  • id:kn1967
    >TimeLimit=5
    5秒で消える設定のままだからですよ。

    テスト段階で、あまり長くするとやりにくいでしょうから、
    クッキーの有効期限を30秒から180秒くらいに設定しておくと良いでしょう。

    本番として使えそうになったら、
    600秒(10分)から1800秒(30分)くらいに設定しなおす事をお忘れなく。
  • id:tontonpokopoko
    なるほど、意味を理解しました。
    これは使えそうです、ありがとうございます。

    テストで正常に動作しているみたいなので、取り入れてみようと思います。
    またこれを利用して、もう少し複雑にも出来そうですね。

    もう少し確認したら、問題を締め切ろうと思います。
    いつもありがとうございます。助かりました。
  • id:kn1967
    id:azuco1975さんへ

    > POSTメソッドに変更するだけでかなりマシ

    いつの時代の話? いまどきGETもPOSTも変わらないよ。

    > hiddenタグをつかってタイプスタンプ等を代入してその都度
    > CGIでチャックすればかなり安全

    クッキーですら、インターネット初心者避け程度にしか期待できないのに、
    hiddenなんか使って安全性下げてどうしたいの?

    連日くだらない投稿を大量投下する人が増えちゃって、
    質問者や回答者のはてな離れに拍車がかかり、投稿先が減ったんでしょ?
    今度はシステムやプログラム分野も減らしたいの?
    真剣に回答しているというなら、返事してみてくださいよ。
    安全だっていうなら、安全性を証明してみてくださいよ。
    チャックするCGI作ってみてくださいよ。


    tontonpokopoko さんへ。

    このような輩に惑わされて餌を与えないように気をつけてくださいね。
    過去の回答で同分野の実績が無いようなら、回答を開けないほうが無難ですし、
    開けてしまったら即座にゼロポイントに設定しておきましょう。
    (回答拒否設定にしてしまうのも有効です。)

    人力検索の質向上のためにも、ご協力ください。

この質問への反応(ブックマークコメント)

「あの人に答えてほしい」「この質問はあの人が答えられそう」というときに、回答リクエストを送ってみてましょう。

これ以上回答リクエストを送信することはできません。制限について

絞り込み :
はてなココの「ともだち」を表示します。
回答リクエストを送信したユーザーはいません