Saturday November 01, 2008
05:41 PM
CGI for sending emails
Today I've created a CGI (below) to send feedback emails from submitted form.
I would like to use (that's why I've created it of course) but also to give it as an example.
Now I'm wondering 1. is it a good example and 2. if it's "secure" enough.
Any suggestions?
---cut---
#!/usr/bin/perl -T
=head1 NAME
send-feedback.cgi - CGI that sends email from posted feedback form
=head1 SYNOPSIS
in html:
<form action="/cgi-bin/send-feedback.cgi" id="feedback_form" method="post">
<fieldset>
<span class="text label">
<label for="name">Your name</label>
<input name="name" type="text" id="name" size="25" />
</span>
<span class="text label">
<label for="email">Tour email</label>
<input name="email" type="text" id="email" size="25" />
</span>
<span class="text label">
<label for="subject">Subject</label>
<input name="subject" type="text" id="subject" size="25" />
</span>
<span class="textarea label">
<label for="message">Message</label>
<textarea name="message" cols="40" id="message" rows="5"></textarea>
</span>
<span class="submit">
<input name="submit" type="submit" value="Submit" />
</span>
</fieldset>
</form>
in Apache virtualhost:
AddHandler cgi-script .cgi
<Location "/cgi-bin/send-feedback.cgi">
Options +ExecCGI
</Location>
test from commandline:
send-feedback.cgi message=test name=jozef subject=subj email=devnull@ba.pm.org
=head1 DESCRIPTION
=cut
use strict;
use warnings;
use CGI;
use MIME::Lite;
use Email::Address;
my $EMAIL_TO = 'feedback@bratislava.pm.org';
my $REDIRECT_OK = '/cgi/email-ok.html';
my $REDIRECT_FAILED = '/cgi/email-fail.html';
my $EMAIL_ADDRESS_RE = $Email::Address::mailbox;
exit main();
sub main {
my $q = CGI->new();
# default redirection is to _FAILED
my $REDIRECT = $REDIRECT_FAILED;
# get parameters
my $name = $q->param('name') || '';
my $from = $q->param('email') || 'devnull@ba.pm.org';
my $subject = $q->param('subject') || '';
my $message = $q->param('message');
$from = "$name <$from>"
if ($name);
# input check
my $input_ok = 1;
$input_ok = 0
if ($from =~ m/\r|\n/m);
$input_ok = 0
if ($subject =~ m/\r|\n/m);
$input_ok = 0
if ($from !~ m/^$EMAIL_ADDRESS_RE$/xms);
# only message paramter is mandatory
if ($message and $input_ok) {
# create message
my $msg = MIME::Lite->new(
From => $from,
To => $EMAIL_TO,
Subject => $subject,
Type => 'text/plain; charset=UTF-8',
Encoding => '8bit',
Data => $message,
);
# send email and redirect to _OK if sucessfull
$REDIRECT = $REDIRECT_OK
if eval { $msg->send('smtp', 'localhost'); };
}
# redirect
print $q->redirect(
-uri => 'http://'.$q->virtual_host.$REDIRECT,
-status => 302
);
return 0;
}
Seems secure (Score:2)
At first glance, it seems secure. The biggest issue with a script that sends mail from web input is if you allow the "To" address to be controlled by the form submission. Obviously, allowing that is a recipe for spam.
You're generating the email using a module, rather than by hand, so that should help rule out other vulnerabilities that could come if you built the email by hand.
There might be an issue with the message body, because you're not restricting it to 7-bit ASCII. I'm not sure if MIME::Lite will do
Re: (Score:1)
the encoding was a good point. The page is in utf-8, so I changed:
my $msg = MIME::Lite->new(
From => $from,
To => $EMAIL_TO,
Subject => $subject,
The HTML (Score:1)
Other people have already commented on the Perl, so I'll mention the HTML.
If it is trying to be HTML, then its invalid. If it is trying to be XHTML, then it is probably flawed in ways you don't want. I'm going to assume the latter.
It's "post" not "POST"
You have no block level container between the form element and its inline content. This means you can't be using valid XHTML 1.0 Strict (or anything based on it). Strict is the modern approach, it is generally wise to avoid Transitional.
You don't have elemen
Re: (Score:1)
<form action="/cgi-bin/send-feedback.cgi" method="POST">
Your Name: <input type="text" name="name" size="20"
Your Email: <input type="text" name="from" size="20"
Subject: <input type="text" name="subject" size="20"
Message: <textarea name="message" cols="80" rows="20"
Re: (Score:2)
It's still weird: placing textarea inside span element is not an option you should use :-)