フォームメールcgi の加工(スパム排除)について教えて下さい。


http://www.pet-thailand.com/formmail.txt
(txtファイルとしてアップしています。)

上記フォームメールを長年使用していますが、
最近は英語圏の自動ソフトによる、スパムメールが多く
とても困っています。

送られてくる、スパムメールは、ほとんどが
フォームに設置しているtextarea に、URLを書き込む形で
フォームを送信してきます。

私の場合、textareaにurlが書き込まれたフォームは
全く必要としないのですが、これらtextareaに、URLを含むメールを
排除できないものでしょうか?
(フォームの他の箇所でも、URLを必要とする箇所はありません。)

"http://"を含むフォーム送信を禁止する等、
何か加工方法、アイディアがあれば、教えていただけると助かります。

どうぞよろしくお願いします。

回答の条件
  • 1人2回まで
  • 登録:
  • 終了:2009/06/20 10:15:02
※ 有料アンケート・ポイント付き質問機能は2023年2月28日に終了しました。

回答1件)

id:kn1967 No.1

回答回数2915ベストアンサー獲得回数301

ポイント60pt

(1)GETによるパラメータ送信は拒絶し POSTのみ受け取るようにするだけでも、かなり減ると思われます。

フォームHTMLのほうでGETを利用しているのであれば、そちらもPOSTに変更する必要があります。

    if ($ENV{'REQUEST_METHOD'} eq 'GET') {
        # Split the name-value pairs
        @pairs = split(/&/, $ENV{'QUERY_STRING'});
    }
    elsif ($ENV{'REQUEST_METHOD'} eq 'POST') {
        # Get the input
        read(STDIN, $buffer, $ENV{'CONTENT_LENGTH'});
 
        # Split the name-value pairs
        @pairs = split(/&/, $buffer);
    }
    else {
        &error('request_method');
    }

   ↓↓↓↓↓

    if ($ENV{'REQUEST_METHOD'} eq 'POST') {
        # Get the input
        read(STDIN, $buffer, $ENV{'CONTENT_LENGTH'});
 
        # Split the name-value pairs
        @pairs = split(/&/, $buffer);
    }
    else {
        &error('request_method');
    }

(2)件名が空白だったり半角英文だけで構成されているような場合は拒絶するようにすれば、さらに減ると思われます。

        if (defined($Config{$name})) {
            $Config{$name} = $value;
        }

   ↓↓↓↓↓

        if (defined($Config{$name})) {
            if (($name eq 'subject') && ($varue =~ /[^\x80-\xff]/) {
                &error('request_method');
            }
            $Config{$name} = $value;
        }

(3)本文にURLを含んでいれば拒否して良いというのであればさらに減るとは思いますが、

上記2点があれば、もしかしたら不要かもしれません。

        else {
            if ($Form{$name} ne '') {
                $Form{$name} = "$Form{$name}, $value";
            }
            else {
                push(@Field_Order,$name);
                $Form{$name} = $value;
            }
        }

   ↓↓↓↓↓

        else {
            if ($varue =~ /http:\/\//) {
                &error('request_method');
            }
            if ($Form{$name} ne '') {
                $Form{$name} = "$Form{$name}, $value";
            }
            else {
                push(@Field_Order,$name);
                $Form{$name} = $value;
            }
        }

※以上、動作確認はしておりません。

※(2)は文字コードEUC-JPの場合です。他の場合は変更が必要です。

※エラー表示のほうは追加してませんので、どこで引っかかっても同じエラー処理が動きます。

※プロバイダの迷惑メールフィルタもあわせて使う事をお勧め。

id:nobu55

ご回答ありがとうございます。

大変恐れ入りますが、たとえば

全ての入力箇所(textarea, radio bottun 等々)で、入力された値が

半角英数の場合に、拒否するような、加工方法を合わせて教えていただけると、とても助かります。

どうぞよろしくお願いします。

2009/06/13 12:48:10
  • id:nobu55
    質問の中に書き忘れてしまいましたが、
    自動ソフトは
    フォームの他の箇所では、意味のない文字列(英語)を
    書き込んできます。
  • id:kn1967
    >全ての入力箇所

    そのうちの「1つでも半角英数だけの場合」という事ならば
    (3)で追加した部分をやめて、代わりに(2)で追加した式を入れる。

    「すべてのテキストエリアが半角英数だけの場合」の改造は
    解読に少々時間がかかるし、説明もさらに長くなるので割愛させて欲しい。

    他の方の回答を待ってみてください。
  • id:hijk04
    (はてなにより削除しました)
  • id:hijk04
    (はてなにより削除しました)
  • id:nobu55
    kn1967さん

    どうも。ありがとうございました。
    試してみます。
  • id:hijk04
    (はてなにより削除しました)
  • id:rouge_2008
    ※すみません。一度削除して再投稿しています。

    リファラーの指定を正しく行っていてもスパムメールが届くのですか?(※フォームを設置したページのドメイン部分)
    @referers = ('www.pet-thailand.com');

    リファラーを偽装して送信されるという場合は、クッキーをセットして回避する方法もあります。

    http://gac.kir.jp/12/16126
    http://www.rfs.jp/sb/perl/03/04.html

    正規のフォームにアクセスしてクッキーを取得された場合は、回避できなくなるので完全ではありませんが、自動ソフトが対応していない場合は十分に有効な手段だと思います。

    他には、プライバシーポリシーの規約に同意する確認のラジオボタンなどを設けて、チェックしていない場合や「いいえ」にチェックした場合は弾くという方法も良いのではないかと思います。
    こちらの方法も完全ではなくて、フォームのソースを解析されて上記の項目と正しい値を指定された場合は回避できなくなってしまいますが・・・
    自動ソフトの機能が分かりませんが、とりあえず使用できる方法ではないかと思います。


    既にkn1967さんが回答されている方法で大丈夫かもしれませんが、もし必要な場合は教えてください。
    よろしければ回答させていただきます。
  • id:hijk04
    (はてなにより削除しました)
  • id:rouge_2008
    本当にすみません。
    一部間違えたので訂正・削除して再々度コメントしました。

    おせっかいをしてちょっと試してみました。
    以下の2箇所の「$varue」は正しくは「$value」で、ケアレスミスですね。
    (2)
    if (($name eq 'subject') && ($varue =~ /[^\x80-\xff]/) {

    (3)
    if ($varue =~ /http:\/\//) {


    (2)の方法についてですが、「1つ(の項目だけ)でも半角英数だけの場合にエラー」ではなく、「日本語以外の文字を1文字でも含んだ場合にエラー」になっているように思います。
    それとも、最初から「英数字など日本語以外の文字を1文字だけでも含んだ場合にエラー」でいいのでしょうか?
    if (($name eq 'subject') && ($value =~ /[^\x80-\xff]/) {
    &error('request_method');
    }

    以下のように「=~」ではなく「!~」にすると、「日本語の文字を含まない場合にエラー」となるはずです。
    if (($name eq 'subject') && ($value !~ /[\xA1-\xff]/) {
    &error('request_method');
    }

    http://www.din.or.jp/~ohzaki/perl.htm#JP_Exist


    上記はEUCの場合ということですので、Shift_JISの場合は、次のようにすれば大丈夫だと思います。(かなり大ざっぱですが・・・)
    ※「半角英数字と一部の記号および改行以外の文字を含まない場合にエラー」となるようにしてあります。(他の文字コードでも大丈夫なはず?)
    if (($name eq 'subject') && ($value !~ /[^\x0a-\x7e]/) {
    &error('request_method');
    }


    他の項目についても制限したい場合は、187行目付近からの記述を次のように変更してみてください。

    if (defined($Config{$name})) {
    #次の3行は、kn1967さんの回答の(2)の方法を追加した部分です。(※おそらくSJISだと思い、SJIS用にしてあります。)
    if (($name eq 'subject') && ($value !~ /[^\x0a-\x7e]/)) {
    &error('request_method');
    }
    $Config{$name} = $value;
    else {
    if ($Form{$name} ne '') {
    $Form{$name} = "$Form{$name}, $value";
    }
    #次の3行を新しく追加します。ただし、電話番号のように日本語以外の文字だけの値の項目がない場合は、次の1行を「if ($value !~ /[^\x0a-\x7e]/) {」にします。
    if (($name ne '電話番号') && ($value !~ /[^\x0a-\x7e]/)) {
    &error('request_method');
    }
    #日本語が含まれない項目が複数ある場合は、上記3行を#で無効にして、代わりに下の3行の#を削して有効にします。3個記述できるようにしてありますが、足りない場合は「||」で区切って同じように追加するといいです。
    # if (($name eq '電話番号' || $name eq '項目名2' || $name eq '項目名3') && ($value !~ /[^\x0a-\x7e]/)) {
    # &error('request_method');
    # }
    else {
    push(@Field_Order,$name);
    $Form{$name} = $value;
    }
    }
    }


    ※まだ解決できていない場合は、上記の記述に変更して確認してみてください。
  • id:rouge_2008
    kn1967さん、ポイントの送信ありがとうございます!
    先ほど確認しました。
    終了待ちの質問がない時に、いきなりポイントの表示が増えていたので、少しびっくりしてしまいました。(^-^;A
  • id:rouge_2008
    大変申し訳ありません。m(__;)m
    「$Config{$name} = $value;」の次の行の「}」を忘れていました。
    ※「else {」の前の行です。
    ※下が訂正済みのものです。(デフォルト状態で177行目から189行目)



    if (defined($Config{$name})) {
    #次の3行は、kn1967さんの回答の(2)の方法を追加した部分です。(※おそらくSJISだと思い、SJIS用にしてあります。)
    if (($name eq 'subject') && ($value !~ /[^\x0a-\x7e]/)) {
    &error('request_method');
    }
    $Config{$name} = $value;
    }
    else {
    if ($Form{$name} ne '') {
    $Form{$name} = "$Form{$name}, $value";
    }
    #次の3行を新しく追加します。ただし、電話番号のように日本語以外の文字だけの値の項目がない場合は、次の1行を「if ($value !~ /[^\x0a-\x7e]/) {」にします。
    if (($name ne '電話番号') && ($value !~ /[^\x0a-\x7e]/)) {
    &error('request_method');
    }
    #日本語が含まれない項目が複数ある場合は、上記3行を#で無効にして、代わりに下の3行の#を消して有効にします。※こちらで指定するのは日本語が含まれていなければならない項目名です。3個記述できるようにしてありますが、足りない場合は「||」で区切って同じように追加するといいです。
    # if (($name eq 'ご住所' || $name eq 'メッセージ' || $name eq '項目名3') && ($value !~ /[^\x0a-\x7e]/)) {
    # &error('request_method');
    # }
    else {
    push(@Field_Order,$name);
    $Form{$name} = $value;
    }
    }
    }


    ※説明で分かりにくいと思われる部分も訂正してあります。
  • id:nobu55
    id:rouge_2008様 いつもありがとうございます。
    id:kn1967様 情報ありがとうございます。

    失礼なコメントが削除されて良かったです。

    出張にでておりまして、回答が遅れてしまいまして、大変失礼いたしました。
    これから、頂いた情報を参照に、作業してみます。

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

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

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

回答リクエストを送信したユーザーはいません