| Developer's Daily
|
Perl Education |
Limiting access to your
Perl/CGI scripts by host
| This article introduces a simple Perl subroutine that you can use
to limit user's access to your Perl/CGI programs. The subroutine limits
access by checking the value of the REMOTE_HOST environment variable.
If you're not logged in from the right host, you're not allowed to run
the CGI program. |
Introduction
If you've ever run your own web site using Apache, you know that you can
limit access to certain files and directories using the .htaccess
file. But suppose you forget to put a .htaccess file in a directory,
or you configure it wrong? That leaves open the possibility that somebody
outside your Internet domain can run your CGI programs. Not always a pretty
thought, eh?
As an extra layer of security, I've created a very simple Perl subroutine
that I use in my important Perl/CGI programs. This routine checks the REMOTE_HOST
environment variable. If the user accessing the script isn't logged in
from the proper remote host, the script won't run.
Easy to use
I wanted to make the subroutine easy to use in my Perl/CGI programs. Using
the subroutine involves just two steps:
-
Use the require statement to include the myutils.lib
library in your program.
-
Call the limitHostAccess subroutine.
Here's a simple "Hello, world" CGI program that shows how to include the
library and call the subroutine:
| #!/usr/bin/perl
#----------------------#
require "myutils.lib";
# include the library #
#----------------------#
print "Content-type: text/html";
#---------------------------------------------#
&limitHostAccess;
# program exits here if REMOTE_HOST is wrong #
#---------------------------------------------#
print "<H3>Hello, world that I trust</H3>\n";
exit;
|
| Listing 1: |
Here's a modified HelloWorld.cgi program
that shows how the limitHostAccess subroutine should be called. |
|
|
If a user invokes the CGI program while they're logged into the proper
REMOTE_HOST, they'll see the "Hello,
world that I trust" output. Otherwise, they won't see anything
except a blank browser screen.
What's in the subroutine
Listing 1 showed how to include the library in your Perl/CGI program,
and how to call the subroutine. But how does the subroutine work?
Listing 2 shows the Perl source code for the limitHostAccess
subroutine.
|
# myutils.lib
#
#---------------------------<<
limitHostAccess >>--------------------------#
#
#
# PURPOSE: Only let users from
certain domains access Perl/CGI programs. #
#
#
#----------------------------------------------------------------------------#
sub limitHostAccess {
$trustedHosts = "devdaily.com|mydomain.com";
# define your domain here
$remoteHost = $ENV{'REMOTE_HOST'};
if ( $remoteHost =~ /$trustedHosts$/i
) {
return;
} else {
print "\n";
exit 1;
}
}
1;
|
| Listing 2: |
The limitHostAccess subroutine exits
if the REMOTE_HOST does not match the patterns defined in the
list of "trusted hosts". |
|
|
How it works
The limitHostAccess routine works by comparing the value of the
REMOTE_HOST environment variable to the list of trusted hosts
that you define. If REMOTE_HOST is in the list, the subroutine
returns and the rest of your program continues. If REMOTE_HOST
is not in the list, the subroutine calls "exit", which terminates
your entire CGI program.
The meat of the program is in this comparison statement:
if ( $remoteHost =~ /$trustedHosts$/i
)
Here, we're comparing the value of $remoteHost to the list of
trusted hosts. $remoteHost is given to your CGI program through
your web server (in the environment variable named REMOTE_HOST),
while you specify the value for the variable named $trustedHosts.
The $ symbol (the end-of-line
pattern-matching symbol) at the end of the $trustedHosts variable
specifies that the domain name must be at the end of the name. This means
that names like joe.devdaily.com will pass the test, but a name
like devdaily.com.baddomain.com will fail the test.
Also, the "i" after the final
forward-slash makes the comparison case-insensitive. In every test I ran
this was not needed, but I left it in just in case this condition was unique
to my particular configuration.
As a final note, if you only log onto the Internet through one domain,
such as fred.com, instead of multiple domains, just make your
$trustedHosts definition look like this:
$trustedHosts = "fred.com";
# define your domain here
Where this routine is bad
This routine won't help much if you approve a domain like AOL.COM, which
has 20 million or more users. (On the other hand, if only approve a domain
like FRED.COM, you'll know that there are 20M+ AOL users that can't see
the output of your CGI scripts.)
This routine will also fail if a hacker spoofs your domain name. But
my guess is that if somebody is willing to go through that effort, they'll
probably be able to bypass your other security measures as well.
How this technique can be improved/expanded
This is a very simple technique that can be used to add a little more security
to your Perl/CGI programs. I wouldn't count on it as your only line of
defense, but it can be a helpful layer of protection. Used as shown in
Listing 1, it gives the appearance that the CGI program ran, but
returned no results. This basic technique limits user access to your Perl/CGI
scripts by looking at the domain name of the user.
If you're interested in expanding this technique, look at the environment
variables available to your Perl/CGI programs, and decide how else
you want to limit access. As an example you can also limit access by these
variables:
-
REMOTE_ADDRESS
-
QUERY_STRING
-
REMOTE_PORT
-
HTTP_USER_AGENT
In each case, the programming technique is the same. Define the acceptable
values, and exit the program if the environment variable doesn't match
what you expected.
Limiting access by REMOTE_PORT might be a little tricky (requiring
configuration on the client-side of the equation), but can be worth the
effort if you really want to tie down your scripts. Most people might think
is a little overboard, but if I'm running Yahoo, E-Trade, or Amazon, I'd
certainly think about it.
Conclusion
If you know how to use the .htaccess file with your Apache web
server, by all means use it as your first line of defense. (If you want
to learn more about Apache, check out the Apache
home page.) But if you don't know how to use .htaccess, or
you use another web server, or you want another line of defense for your
CGI programs, consider this subroutine as a possible security option.
[an error occurred while processing this directive]