?
Solved

Preventing script from being called by other domain

Posted on 2003-03-13
25
Medium Priority
?
323 Views
Last Modified: 2008-03-10
Hi,

I don't write perl. I just configure prebuilt scripts.  I need to add a line of code that will prevent the script from being called by any other domain other than the domain that the script is installed on.

Here is a copy and paste of  the current script.  Can you insert the necessary line(s) of code?

For example, this script is installed at www.foobar.com (domain example has been changed from the actual domain for privacy purposes.)


Thanks!
============

$|++;
use Net::SMTP;
use CGI;
$q = new CGI;

$foobarfolks='<jjones@foobar.com>, <jsmith@foobar.com>';
$toddemail='<jones@foobar.com>';
$message="Thank you for contacting US.;
$user_subject='Thank You from US';

foreach ($q->param){
    $$_=$q->param($_);

    next if /^to$/;
    $$_=~ s/^\s+//g;
    $$_=~ s/\s+$//g;
}

if (!($to)){
    print "Content-type: text/html\n\n";
    print "Please go back to the form and enter your email address.<BR>\n";
    exit;
}

if (!($firstname)){
    print "Content-type: text/html\n\n";
    print "Please go back to the form and enter your First Name.<BR>\n";
    exit;
}

if (!($lastname)){
    print "Content-type: text/html\n\n";
    print "Please go back to the form and enter your Last Name.<BR>\n";
    exit;
}

@new_from=split(/,\s/,join(', ',$from,$foobarfolks)); ## NOTE the , inside the single quotes

if (!($to)){
    print "Content-type: text/html\n\n";
    print "Please go back and enter your email address<BR>\n";
    exit;
}

#     Email the user who posted the form, a TY note!!
$smtp = Net::SMTP->new('localhost'); # connect to an SMTP server
$smtp->mail($toddemail);     ##     use the sender's address here
$smtp->to($to);     ##     recipient's address
$smtp->data();
$smtp->datasend("Subject: ".$user_subject."\n");
$smtp->datasend("\n");
$smtp->datasend($message);


$smtp->dataend();                   # Finish sending the mail

##  Close the connection
$smtp->quit;

foreach $new_from (@new_from){
    $smtp = Net::SMTP->new('localhost'); # connect to an SMTP server
    $smtp->mail($to);     ##     use sender's address here
    $smtp->to($new_from);     ##     recipient's address. Use new_from, not from
    $smtp->data();
    $smtp->datasend("To: ".$new_from."\n");
    $smtp->datasend("Subject: ".$your_subject."\n");
    $smtp->datasend("Copies of this email sent to: $foobarfolks \n\n");
    $smtp->datasend("\n");
    $smtp->datasend("Name : $name\n");
    $smtp->datasend("Email : $to\n");
    $smtp->datasend("Home Phone : $homephone\n");
    $smtp->datasend("Work PHone : $workphone\n");
    $smtp->datasend("Referer     : " . $q->referer . "\n");
    $smtp->datasend("Remote Host : " . $q->remote_host . "\n");
    $smtp->datasend("User Agent  : " . $q->user_agent . "\n");
     
    $smtp->dataend();                   # Finish sending the mail
   
    ##  Close the connection
    $smtp->quit;
}


##     Redirect to the Thank you page.
print "Location: https://www.foobar.com/html/content/response1.shtml\n\n";
0
Comment
Question by:Rowby Goren
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 4
  • 4
  • 4
  • +8
25 Comments
 
LVL 14

Expert Comment

by:avner
ID: 8128167
Why not protecting the directory using the web-server tools ?

0
 

Accepted Solution

by:
trevorw earned 1000 total points
ID: 8128236
Hi,

You can use the HTTP_REFERER environment variable to do this, as follows:

if ($ENV{'HTTP_REFERER'} !~ /foobar\.com/i) {
   print "Content-type: text/html\n\n";
   print "Incorrect referrer.<BR>\n";
   exit;
}

Obviously change /foobar\.com/ to /yourdomain\.com/ :)

Hope this helps.

Best regards,
Trevor
0
 
LVL 84

Expert Comment

by:ozo
ID: 8128447
You probably wanted to check $ENV{REMOTE_ADDR} not HTTP_REFERER
0
VIDEO: THE CONCERTO CLOUD FOR HEALTHCARE

Modern healthcare requires a modern cloud. View this brief video to understand how the Concerto Cloud for Healthcare can help your organization.

 

Expert Comment

by:trevorw
ID: 8128479
No... REMOTE_ADDR will give you the visitor's IP or host, not the domain which called the script.
0
 
LVL 20

Expert Comment

by:jmcg
ID: 8130331
Ozo's right. HTTP_REFERER can easily be forged. REMOTE_ADDR may not give you the visitor's true IP address (thanks to proxies, firewalls, etc) but it will not show you an address _inside_ your network if the originator is outside.
0
 
LVL 1

Expert Comment

by:OKSD
ID: 8131330
What if you check for the domain at the begining of the HTTP_REFERER?

e.g.,

if($ENV{'HTTP_REFERER'} !~ /^http://www.foobar\.com/) {
print "Error! Invalid referer!";
exit;
}

Would that work better?

OKSD
0
 
LVL 1

Expert Comment

by:OKSD
ID: 8131347
What if you check for the domain at the begining of the HTTP_REFERER?

e.g.,

if($ENV{'HTTP_REFERER'} !~ /^http://www.foobar\.com/) {
print "Error! Invalid referer!";
exit;
}

Would that work better?

OKSD
0
 
LVL 9

Author Comment

by:Rowby Goren
ID: 8131378
(Hi all -- I'm lurking while you Experts work this out :)  )

Thanks

Rowby
0
 
LVL 1

Expert Comment

by:OKSD
ID: 8131416
Actually, I'm not really an expert, I know a few things, I code in a practically illegible free-hand manner and do things inefficiantly, but I manage to get my task done :D

OKSD
0
 
LVL 22

Expert Comment

by:pjedmond
ID: 8131693
Hey OKSD - Join the club :)
0
 
LVL 1

Expert Comment

by:biglug
ID: 8132193
As people say, HTTP_REFERER (and all other headers) can be forged.

If this script is an internal script (its called by another script) then the REMOTE_ADDR would be more interesting than the HTTP_REFERER, but I'm guessing from the look of the script that its run by the general public filling out a form?

There are very few ways to be 'certain enough' that the user comes from the correct place.

This method has been discussed above:
if($ENV{'HTTP_REFERER'} !~ /^http://www.foobar\.com/) {
   print "Content-Type: text/plain\n\n";
   print "Error! Invalid referer!";
   exit;
}
Now as people say, putting this into your code will check where the user is *coming from*, that is, which page the form was on. However, it can be forged. Who would forge it? The only people who would forge it would be people who seriously wanted to mess with something. Like if they could use this to send some third party an email that looked like it came from you. However your script seems to just send a canned response. Any hacking would be for fun more than anything.

To be more certain, send the form from a CGI. This CGI would associate a REMOTE_ADDR and HTTP_USER_AGENT with a time-limited obscure key.

This key becomes a hidden field in your form. When the form is submitted, you check that the key matches the new REMOTE_ADDR and new HTTP_USER_AGENT and that the match hasn't expired.

Of course, this is still forgable, its just a hell of a lot more trouble for hackers to go to (and the question remains why they would).
0
 
LVL 9

Author Comment

by:Rowby Goren
ID: 8132337
H Biglug

It is interteresting that you suggest using a key.  Someone else somewhere else suggested using this key system.

Can you tell me how to create this key.  Again, I don't write perl. :)

I have increased the points to 250

0
 
LVL 48

Expert Comment

by:Tintin
ID: 8132473
Forging HTTP_REFERER is certainly possible, but not as common as it being empty.

Many browsers/proxies simply strip it out, so relying on HTTP_REFERER is potentially going to prevent legitimate users from using the script.
0
 

Expert Comment

by:webadmin
ID: 8134173
Absolutely DO NOT USE HTTP_REFERRER as it can be easily spoofed!

Use REMOTE_ADDR instead...

Just add the following lines to the beginning of your code:
Put in your "allowed" networks and domains in the @ALLOWED_NETWORKS variable.  If ALL your client ip's are reverse resolvable, then you can omit putting in networks, just put in your domain(s).

-----------------------------------------------------------

use Net::DNS;

my @ALLOWED_NETWORKS = qw/161.151.  .yourdomain.com/;


if (! &ValidClient(\@ALLOWED_NETWORKS)){
   print "Content-type: text/html\n\n";
   print "Your are an illegal user. ".
          The authorities are being notified...<BR>\n";
   exit;
}


sub ValidClient {
my $networks = shift;
my $DNSObj;
my $DNSQuery;
my $client     = $ENV{'REMOTE_ADDR'};
my $rr;
my $client_hostname = $client;
my $network;
my $rc = 0;


if ($client =~ /^[\d\.]+$/) {
  $DNSObj     = Net::DNS::Resolver->new();
  $DNSQuery = $DNSObj->search($client);

  if ($DNSQuery) {
    foreach my $rr ($DNSQuery->answer) {
      next unless $rr->type eq "PTR";
      $client_hostname = $rr->rdatastr;
      last;
    }
  }
  $client_hostname =~ s/\.$//;
}

foreach $network (@{$networks}) {
  if ($network =~ /^[\d\.]+$/) {
    $rc = 1 if ($client_hostname =~ /^${network}.*$/i);
  }
  else {
    $rc = 1 if ($client_hostname =~ /^.*${network}$/i);
  }
}

return $rc;
}

----------------------------------------------------------
0
 
LVL 1

Expert Comment

by:strAtEdgE
ID: 8137793
rowby: all these guys are wrong.

You want to check that $ENV{HTTP_HOST} is the current domain.

$ENV{HTTP_HOST} : the current domain for this page, even on a name based server (server with multiple domains).

$ENV{HTTP_REFFERER} : the URL of the page that sent the user to this page by a link (not what you want).

$ENV{REMOTE_ADDR} : the address of the client accessing your page (not what you want).
0
 
LVL 1

Expert Comment

by:strAtEdgE
ID: 8137891
Oh and as for code, stick this in right at the beginning:

exit(1) unless ($ENV{HTTP_HOST} eq "www.foobar.com");
0
 

Expert Comment

by:webadmin
ID: 8139015
Rowby,

It appears you will have to clarify your original question.

Do you want your script to only "run on the web server whose virtual host domain is foobar.com" ?

Or...

Do you want the script to only answer to "clients whose workstations are from the domain foobar.com" ?

If the answer to question #1 is "yes" then you only need to use the HTTP_HOST enviornment variable.


However, if the answer to question #2 is "yes", then DO NOT USE HTTP_HOST as that is wrong wrong wrong, instead use REMOTE_ADDR (my code snippet above) or a combination of USER_AGENT and HTTP_HOST as a "key" (also mentioned above by another person.)

0
 
LVL 9

Author Comment

by:Rowby Goren
ID: 8139192
Hi

I hope I can clarify what is needed.  

We want to prevent soemone from accessing the perl script who from another domain.

For example.  Our web server is www.foobar.com.  THe form which accesses the perl script is form.html and is on the foobar.com webserver.  The perl script is in the www.foobar.com/cgi-bin

We want to prevent someone from www.spam.com from recreating our the form.html and putting it on the www.spam.com server and accessing our perl script in the cgi-bin of gthw www.foobar.com server.

I hope that clarifies things.

(I must say, the "key" suggestion by biglug, also sounds "appealing".  But I'm ignorant in these things!)

ROwby
0
 
LVL 48

Expert Comment

by:Tintin
ID: 8139631
Also note that HTTP_HOST is not a standard CGI/1.1 environment variable.

See http://hoohoo.ncsa.uiuc.edu/cgi/env.html for the full list.
0
 
LVL 1

Expert Comment

by:strAtEdgE
ID: 8140009
rowby: based on your clarification, you want to check the HTTP_REFFERER then.
0
 
LVL 48

Expert Comment

by:Tintin
ID: 8140070
For a start, HTTP_REFFERER doesn't exist, it is HTTP_REFERER

Also, please read through the entire post to see why using HTTP_REFERER is not a good idea.
0
 
LVL 1

Expert Comment

by:strAtEdgE
ID: 8141259
Tintin: you get a gold star for good spelling. Unfortunatley not for knowledge, though. :(

rowby: Don't listen to those who tell you that using HTTP_REFERRER is not a good idea, it is. Yes, it can be spoofed, since it's just a variable passed to you from the client in the HTTP header... but if you understand how HTTP and networking in general work, then you'll understand that it is theoretically impossible to determine without a doubt where a client came from. You have to take their word for it.

Further more, it's a part of the HTTP 1.1 specification and it's quite reliable. The reason it is quite often not there is because it is not passed along if the referring source is not a valid URI; for example if a user types in the URI from their keyboard. When you're on the receiving end of your own form, however, it's going to be there quite certainly.
0
 
LVL 20

Expert Comment

by:jmcg
ID: 8141391
It's hard to know how to help you Rowby, since we don't have all the information needed to write a script for you. To implement the KEY idea mentioned by Biglug, your initial page containing the form has to be dynamically generated, too.


If the degree of security you're looking for is not too stringent, then HTTP_REFERER may be good enough. The lines suggested by trevorw will suffice.


As it currently is written, your script can be hacked to send a canned email (your content, with your site as the originator) to an arbitary recipient and will simultaneously generate an internal junk email with non-dangerous content to your foobarfolks. Biglug is correct in saying that this isn't a wide open loophole for hackers. Furthermore, there is no protection possible to prevent a hacker from sending at least one e-mail to an arbitrary address via an auto-responder form like this.

If you're looking to cut down on abuse, you'd want to keep track of recent e-mail addresses and their corresponding REMOTE_ADDR values. If either of these appears as a duplicate, you may want to hold off on sending an email reply (sending back a suitable warning webpage is okay). Having a throttle on the overall rate at which your site will display this form or accept accesses to the script might also help you avoid being an unwitting party to more sophisticated abuse.


Since you're not in a position to implement something complicated, I suggest you go with trevorw's suggestion.

If you really do have more stringent requirements, you may need to hire someone with some expertise. As you can see, we volunteer question answerers vary a lot in what we know and how we read an ambiguous situation. A lot of the problems we have on the Internet are caused by poorly thought out responses to particular problems that either do not respond to the real problem or that have side effects at least as bad (and harder to solve) as the original problem.
0
 
LVL 48

Expert Comment

by:Tintin
ID: 8141635
strAtEdgE,

Where is my knowledge lacking?

HTTP_REFERER (note the spelling again) is OK in most instances, but you are still going to isolate a certain percentage of your audience that use software/browser to prevent it being sent.

See http://www.w3.org/Protocols/HTTP/1.1/spec.html
0
 
LVL 9

Author Comment

by:Rowby Goren
ID: 8230830
Thanks. Sorry for the delay in awarding this one
0

Featured Post

Technology Partners: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

I've just discovered very important differences between Windows an Unix formats in Perl,at least 5.xx.. MOST IMPORTANT: Use Unix file format while saving Your script. otherwise it will have ^M s or smth likely weird in the EOL, Then DO NOT use m…
On Microsoft Windows, if  when you click or type the name of a .pl file, you get an error "is not recognized as an internal or external command, operable program or batch file", then this means you do not have the .pl file extension associated with …
Explain concepts important to validation of email addresses with regular expressions. Applies to most languages/tools that uses regular expressions. Consider email address RFCs: Look at HTML5 form input element (with type=email) regex pattern: T…
Six Sigma Control Plans
Suggested Courses

777 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question