homepage Welcome to WebmasterWorld Guest from 54.211.201.65
register, free tools, login, search, subscribe, help, library, announcements, recent posts, open posts,
Subscribe to WebmasterWorld
Home / Forums Index / Code, Content, and Presentation / Perl Server Side CGI Scripting
Forum Library, Charter, Moderators: coopster & jatar k & phranque

Perl Server Side CGI Scripting Forum

    
Modifying NMS FormMail to deny submissions with URL links
FormMail spam
patb




msg:4447904
 11:25 am on May 1, 2012 (gmt 0)

Hi. I am using NMS FormMail Version 3.14c1 to receive input from visitors to a web site. I want to adopt a fairly tight restriction on spammers. I want to modify the FormMail perl script to deny submissions if there are any links to web pages in the comments part of the form.

There is a good discussion here [webmasterworld.com] of the type of thing I want to do, well articulated by Wizcrafts in the first and last posts, but the thread ends without conclusion.

I am an absolute beginner in Perl but I may have made a little progress in editing the formmail script to block spammers. At about (my) line 2876, I have added the lines shown here (marked "phb anti-spam hack"):


sub send_main_email_fields {
my ($self) = @_;

foreach my $f (@{ $self->{Field_Order} }) {
my $val = (defined $self->{Form}{$f} ? $self->{Form}{$f} : '');

# phb anti-spam hack
if ($val =~ /http/) {
# This looks like spam. Clear the field.
$val = 'SUSPECTED SPAM - MESSAGE DELETED';
print "content-type: text/html\n\n";
print 'Program error. Please contact us by email or phone. <br><br>Press your browser&apos;s &quot;Back&quot; button to continue.<br><br>';
# Note: exit or die here does not stop the form being submitted.
}

# end phb anti-spam hack

$self->send_main_email_field($f, $val);
}
}

This edit causes the contents of the comments field of the form to be deleted if it contains the string "http", and replaced with a marker warning. However, the form is still submitted and for me, that is a small problem. I tried 'exit' or 'die' at the same point but the form was still submitted. It seems that at this point in the script, it is too late to stop the process of sending the form.

What I now want to do is simply to kill off any form submission if the form contains the string "http" ie stop it being submitted. Can anyone suggest how?

Thanks in advance, Pat.

 

rocknbil




msg:4448017
 3:50 pm on May 1, 2012 (gmt 0)

Welcome aboard patb, good job for a beginner! The short answer: wrap the send line in an else and last out of the loop IF spam is found.

A longer answer: there's more to form spam than just http. Added lines below, it may need debugging but as you see it allows you to filter for a number of patterns. Also the "bad" part about this approach is you won't know what they are sending - I usually choose to log the input and exit the program from the logging routine. But anyway . . . .


sub send_main_email_fields {
my ($self) = @_;
my $spam = 0;
my @bad_patterns (
'b*cc\s*:', ## multipart or mail header injection attempts
'to\s*:',
'content\-type',
'\[\s*URL.*\]*', ## BB code style attempts
'\[\s*LINK.*\]*',
'\%5B\s*URL.*(\%5D)*',
'\%5B\s*LINK.*(\%5D)*',
'\[\s*a\s*href.*\]*',
'\%5B\s*a\s*href.*(\%5B)*',
'\<\s*a\s*href.*\>*',
'\%3C\s*a\s*href.*(\%3E)*',
#'example.com',
'viagra',
'pharm',
'male\s+enhance'
);
#
foreach my $f (@{ $self->{Field_Order} }) {
my $val = (defined $self->{Form}{$f} ? $self->{Form}{$f} : '');
foreach my $pattern (@bad_patterns) {
if ($val =~ /$pattern/i) {
$val = 'SUSPECTED SPAM - MESSAGE DELETED';
$spam=1;
last;

} # end if
} # end @bad_patterns
if ($spam==1) {
print "content-type: text/html\n\n";
print '<p>Program error. Please contact us by email or
phone. <br><br>Press your browser&apos;s
&quot;Back&quot; button to continue.</p>';
exit 0;
last;
} # end if $spam == 1
$self->send_main_email_field($f, $val);
} # end Field_Order
} # end sub


As you can see, this allows you to add and remove patterns as needed and picks up a couple others. You can add http(s)? if you need to. The "example.com" one you'd use for your domain (you'll never send email to yourself except in testing, which is why it's commented out) and is a common attack, "anything@yourdomain.com".

The $spam=1 is because we want to last out of the outer foreach and it would only last out of the inner loop if we just "last'ed" from there.

Wizcrafts




msg:4448255
 5:04 am on May 2, 2012 (gmt 0)

Bill; You're still IncrediBill as far as I'm concerned, to be able to write this stuff off the top of your head.

Pat; Thanks for resuming the topic I abandoned in 2008. I may try applying these new changes, just to see if they work for my setup.

My required JavaScript include is still extremely effective at stopping spam submissions from happening at all, but I can't log the contents that way.

patb




msg:4448280
 7:30 am on May 2, 2012 (gmt 0)

Rocknbil and Wiz, thanks for the interest and responses.

Rocknbil: there's more to form spam than just http

Yes, I thought I was going to have to dream up a long and complex regex but your method saved me that.

The code provided by Rocknbil worked well with a change to one line:
my @bad_patterns (
I had to change to:
my @bad_patterns = (

What I experience though is that the headers to the form (email) are still sent whether I use the code I posted earlier or Rocknbil's variation. The offending comments section is deleted but the sender's name and email address as filled in by the sender are still included and sent as an email. It seems the sendmail operation has already started by this point in the script and cannot be stopped.

Rocknbil: I usually choose to log the input and exit the program from the logging routine

Yes. It would be best just to log the offending content somewhere. In such a case, I would prefer that no form were submitted at all. Non-offending forms would be submitted to the relevant person and I would look through the log occasionally to pick up anything falsely identified as spam. That would be my preferred method but right now, a form with spam is truncated but still submitted. I would like to prevent that happening.

Thanks again. Cheers, Pat.

rocknbil




msg:4448500
 3:31 pm on May 2, 2012 (gmt 0)

Hmm OK then . . . do you have

for (some condition) {

&send_main_email_fields;

}

Maybe it's being called inside a loop from elsewhere? If so you'd need to return a value, like

for (some condition) {

$s = &send_main_email_fields;

if ($s==1) {
## output and exit here
}

}

sub send_main_email_fields {
## Same code, remove printout and exit, add
return $spam;
}

I don't use off the shelf scripts so am never familiar with them.

patb




msg:4448890
 1:29 pm on May 3, 2012 (gmt 0)

I think we are getting there. Thanks so much for your guidance Rocknbill. Your technique to print out the contents of variables as explained on that other thread [webmasterworld.com] was a great way to analyse what was going on.

At about (my) line 2287, there is a 'sub parse_form' which leads to either 'sub parse_config_form_input' or 'sub parse_nonconfig_form_input'. It is at the latter point where the code (either my simple version or Rocknbill's works for me). So the complete edited code at about (my) line 2404 (with the added lines marked "phb anti-spam hack V2") is as follows:

sub parse_nonconfig_form_input {
my ($self, $name) = @_;

my @vals = map {$self->strip_nonprint($_)} $self->cgi_object->param($name);
my $key = $self->strip_nonprint($name);
$self->{Form}{$key} = join $self->{CFG}{join_string}, @vals;
push @{ $self->{Field_Order} }, $key;

# phb anti-spam hack V2
my @bad_patterns = (
'bcc\s:', ## multipart or mail header injection attempts
'to\s:',
'\[\sURL.\]', ## BB code style attempts
'\[\sLINK.\]',
'\%5B\sURL.(\%5D)',
'\%5B\sLINK.(\%5D)',
'\[\sa\shref.\]',
'\%5B\sa\shref.(\%5B)',
'\<\sa\shref.\>',
'\%3C\sa\shref.(\%3E)',
# 'example.com',
'viagra',
'http',
'male\s+enhance'
);
my $spam = 0;
foreach my $pattern (@bad_patterns) {
if ($self->{Form}{$key} =~ /$pattern/i) {
$spam=1;
# to do: we now need to log the suspected spam
print "content-type: text/html\n\n";
print 'Program error. Your message was not sent. Please contact us by email or phone. <br><br>Press your browser&apos;s &quot;Back&quot; button to continue.<br><br>';
exit 0;
} # end if
} # end @bad_patterns
# end phb anti-spam hack V2

}


This is still probably a bit rough but it does identify spam, send the printed message to the sender, and decline to submit the form if suspect spam is detected.

It might be necessary to apply the same technique under the 'sub parse_config_form_input' or refine the code but in my local testing that sub seems to be by-passed in all cases. I'm not knowledgeable enough to see what the distinction is between the two subs.

Any further comments would of course be welcome but I am happy with this. Thanks again.

Cheers, Pat.

Global Options:
 top home search open messages active posts  
 

Home / Forums Index / Code, Content, and Presentation / Perl Server Side CGI Scripting
rss feed

All trademarks and copyrights held by respective owners. Member comments are owned by the poster.
Home ¦ Free Tools ¦ Terms of Service ¦ Privacy Policy ¦ Report Problem ¦ About ¦ Library ¦ Newsletter
WebmasterWorld is a Developer Shed Community owned by Jim Boykin.
© Webmaster World 1996-2014 all rights reserved