Update: 29/06/2008
I've corrected all of the issues posted here. please feel free to make comments on the coding.

i've put the corrected code below. thanks


Update: 26/06/2008
i have realised email validation is another issue on its own. hence, it is taking me slightly longer to correct the mistakes i have made here. so bare with me a little longer.

okay, there are easy ways of validating email address like using Email::Address or Data::Validate::Email module. however on this occasion i've decided not to take the easy road so that i may learn something new.



#!/usr/bin/perl -Tw # ## Thanks to Perl Monk members for their suggestions: # Corion, moritz, runrig and pc88mxer # # This program is free software: you can redistribute it and/or # modify it under the terms of the GNU General Public License as # published by the Free Software Foundation, either version 3 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public # License along with this program. If not, see # &lt;http://www.gnu.org/licenses/&gt;. # use strict; ## Path set to minimal default $ENV{PATH} = "/usr/bin:/bin:/usr/sbin"; use warnings; use subs qw(isHostValid); use CGI qw( :standard ); use CGI::Carp qw(fatalsToBrowser); ## Capture error message BEGIN{ CGI::Carp::set_message(\&carp_error); } ## Path of nslooku. Change this to the path of your nslookup my $NSLOOKUP = '/usr/bin/nslookup'; ## Path of sendmail. change this to the path of your sendmail my $SENDMAIL = '/usr/sbin/sendmail'; ## Set your email address here my $RECIP = 'youremail@here.com'; ############################################################ # ACTION HANDLER # ############################################################ # # if($ENV{REQUEST_METHOD} eq 'POST'){ ## Fetch form data input my $name_in = param('name'); my $name = q{}; my $email_in = param('email'); my $email = q{}; my $comments_in = param('comments'); my $comments = q{}; ## Check for html tags in name field if($name_in !~ /<.*>/){ $name_in =~ /(.*)/; $name = $1; }else{ die ("oops! you have html tags. naughty, naughty!"); } ## Check to see if email is valid. ## Does not match email addresses using an IP address instead ## of a domain name. if ($email_in =~ m/\b[a-z0-9._%-]+@[a-z0-9.-]+\.[a-z]{2,4}\b/) +{ $email_in =~ /(.*)/; $email = $1; }else{ die ("oops! your email address is not valid one"); } ## Check for html tags in name field; if($comments_in !~ /<.*>/ ){ $comments_in =~ /(.*)/; $comments = $1; }else{ die ("oops! you have html tags. naughty, naughty!"); } ## Okay! you have passed the tests. now the ultimate test. my @result = split(m/@/, $email); if(!isHostValid($result[1])) { die ("Oops! invalid host name"); } ## Send form data to your email address open (MAIL, "|$SENDMAIL -t"); print MAIL "To: $RECIP\n"; print MAIL "Reply: $email\n"; print MAIL "Subject:email from web form\n"; print MAIL "\n\n"; print MAIL "name: ". $name."\n" ; print MAIL "emial: ".$email."\n" ; print MAIL "comments: ".$comments."\n" ; print MAIL "\n\n"; close (MAIL); ## Display confirmation message print header; print start_html; print "Thanks you for using the comment form. We are going to get back to you as soon as we can say thank you again."; print end_html; }else{ ## Display form print header; print start_html; print start_form(-method => "post", -action => ""); print h4("Contact Form"); print "Name: ", textfield(-name => "name"), br; print "E-mail: ", textfield(-name => "email"), br; print "Enter your comments:", br; print textarea(-name => "comments", -rows => "5", -column => " +50"), br; print submit(-value => "Submit"); print end_form; print end_html; } ## # Subroutine checks if the host is valid # # @param host # sub isHostValid{ my $host = shift; $/=''; open(my $fh, "-|", $NSLOOKUP, "-type=any", $host) or die "unable to exec $NSLOOKUP: $!"; my @response = <$fh>; close $fh; $/='\n'; return 1 if (grep /Name:\s+$host/, @response); return 0; } ## # Subroutine displays error message # # @param error_message # sub carp_error{ my $error_message = shift(); print start_html("Error") . h1("Error") . p("Sorry, the following error has occurred: ") . p(i($error_message)) . end_html; }

Replies are listed 'Best First'.
Re: Perl script to send form data via email
by Corion (Patriarch) on Jun 24, 2008 at 10:03 UTC

    Sorry, but your script has hideous security holes and will be easily subverted to send spam.

    Please use a form mailer script like the NMS Formmail Script, which has been vetted.

    Why are you using CGI and still doing manual parameter decoding in your parse_form_data subroutine? Simply use CGI::param() instead.

    Your handling of form parameters opens up lots of backdoors to send spam, because it is very easy to embed newline characters (or other characters relevant to the protocol how sendmail expects it) into for example the $from variable. This is a large security hole that will likely put your machine onto a mail blacklist within a few days. To fix that, you need to verify that all your input data is as you expect it to be, especially that your $from email address does only contain the characters you expect. Possibly, only allowing /[-+\@.\w]+/ would be a crude yet effective filter.

    Your copy-and-paste of the source code used weird "matching" quotes that Perl 5 does not understand.

      Thanks Corion, for your feedback. i understand where i am going wrong so i am going to be making the necessary changes to make this secure. thanks again! ps: i will try to remove this post so that other do not use it

        I don't think it should be removed, and have approved it, because I think that learning what *not* to do is highly important. I suggest adding an informative description above your code, and when you have a fixed solution, add it to this post as well (Although, in hindsight, this should've been in Seekers rather than in CUFP...)

        Stop saying 'script'. Stop saying 'line-noise'.
        We have nothing to lose but our metaphors.

Re: Perl script to send form data via email
by moritz (Cardinal) on Jun 24, 2008 at 10:12 UTC
    Corion is absolutely right, this a very bad and insecure way of doing this. Consider only this line:
    print MAIL "From: $email\n";

    If somebody passes faked@example.com\nTo: mail_you_want_to_spam@victim.com as the value of $email - your script can easily be abused for sending spam.

    Please do all interent users a favour and don't use this script anywhere.

      Thanks moritz, i've listened to your suggestions and am trying to correct the issues raised here about the script. i agree with you on what you say, however i have not used this script on an actually website. i've created this more as an rough example/tutorial for others. however, i realise now that my good intention to help others is a bad example. :-( thanks again. ps: i will try to remove this post from "cool use of perl" to "not so cool use of perl" :-)
        If you want to, we can consider the node for reaping (ie deleting).

        Another option is that you restore your original text, and put a warning at the top that it's actually a counter-example, and that the reader should also read the replies to it.