📄 ch03.htm
字号:
AllowOverride : None
Limit: GET POST
require = valid-user
Options for Directory: /usr/local/etc/httpd/htdocs
PerlHandler : main::handler
AddType : text/html .shtml
Options : Indexes SymLinksIfOwnerMatch IncludesNOEXEC
AllowOverride : AuthConfig FileInfo Indexes Limit
Limit:
</FONT></PRE>
<P>The <TT><Limit></TT> options for the test1 directory are now specified.
<CENTER>
<H4><A NAME="Heading11"></A><FONT COLOR="#000077">Whos There? Configuring Client
IP/Domain Restrictions</FONT></H4>
</CENTER>
<P>After you've configured the access rights on a per-directory basis, using either
the global access.conf or directory-specific access control files, you may decide
that you want to allow or deny access on a per-site basis, as well. You may, for
instance, only wish to allow connections from a particular domain, possibly for specific
directories. You can do this additionally within the global access.conf file using
additional entries within the <TT><Limit></TT> directive for a particular directory.</P>
<P>It's important to understand how the allow/deny directives are parsed within any
given <TT><Limit></TT> statement. You have three options to specify parse order
that give you the ability to override previous deny statements with allow statements,
using the order statement</P>
<PRE><FONT COLOR="#0066FF">order deny, allow
</FONT></PRE>
<P>Using this form lets you, for instance, deny from everywhere, then allow only
from a specific domain(s) or host(s), perhaps like this:</P>
<PRE><FONT COLOR="#0066FF"><Limit GET>
order deny,allow
deny from all
allow from .corp.adobe.com
</Limit>
</FONT></PRE>
<P>Likewise, you can override allow statements with deny statements to allow everyone
and then deny a few specific domains or hosts like so:</P>
<PRE><FONT COLOR="#0066FF"><Limit GET>
order allow,deny
allow from all
deny from .bozo.com
</Limit>
</FONT></PRE>
<P>You can also treat all connections as denied, unless the host appears in either
an allow or deny statement, using the following order option:</P>
<PRE><FONT COLOR="#0066FF">
<Limit GET>
order mutual-failure
allow from .metronet.com
allow from 130.248
deny from .bozo.com
</Limit>
</FONT></PRE>
<P>This option is probably the safest, because it won't allow any connections from
anywhere, unless they're specifically allowed.</P>
<P>Running our script again now gives the following:</P>
<PRE><FONT COLOR="#0066FF">Userid: nobody
Group: nogroup
Administrator is: wmiddlet@adobe.com
Running at port: 80
Access filename: .privaccess
User Directory: public_html
Global Types: text/html .shtml
Options for Directory: /usr/local/etc/httpd/cgi-bin
Options : None
AllowOverride : None
Limit:
Options for Directory: /usr/local/etc/httpd/htdocs/test1
Options : None
AllowOverride : None
Limit: GET POST
require = valid-user
Options for Directory: /usr/local/etc/httpd/htdocs
PerlHandler : main::handler
AddType : text/html .shtml
Options : Indexes SymLinksIfOwnerMatch IncludesNOEXEC
AllowOverride : AuthConfig FileInfo Indexes Limit
Limit: GET
deny = from .bozo.com
order = mutual-failure
allow = from .metronet.com
</FONT></PRE>
<P>But note our <TT><Limit></TT> directive for <TT>DocumentRoot</TT> has not
limited retrievals in /cgi-bin. Because the cgi-bin directory isn't beneath <TT>DocumentRoot</TT>,
it's not affected by the <TT><Limit></TT> statement. You'll need to explicitly
limit anything outside, or above, the directory where you place <TT><Limit></TT>
statements if that is the intent.
<CENTER>
<H4><A NAME="Heading12"></A><FONT COLOR="#000077">Another IP Restriction Mechanism:
tcpwrapper</FONT></H4>
</CENTER>
<P>Another alternative, when you wish to restrict/verify connections from particular
hosts, is to run a site-wide tool like tcpwrapper. (This will work only if you're
starting httpd out of inetd.) You can get tcpwrapper from the COAST archive at</P>
<PRE><FONT COLOR="#0066FF">ftp://ftp.cs.purdue.edu/pub/tools/tcp_wrappers
</FONT></PRE>
<P>along with plenty of other security tools, papers, and packages. Using tcpwrapper,
you can configure certain actions based on the connecting site's domain, or hostname,
which are vastly more powerful than the options you have with httpd alone. Many sites
out on the open Internet use this tool, and it even ships with a couple of operating
systems. If your site has an open pipe to the Internet, it may well be worth investigating
this tool.
<CENTER>
<H4><A NAME="Heading13"></A><FONT COLOR="#000077">Whos There? User/Group Verification</FONT></H4>
</CENTER>
<P>Finally, you can use the http access.conf file, along with a couple of other files
and tools, to configure security for a specific directory or file on a per-user or
per-group basis. You'll need to create the .htpasswd file on a per-directory basis
and/or a global .htpasswd file. The <TT>HTTPD::UserAdmin</TT> module is the tool
of choice for manipulating passwd/group files. It knows about the various types of
user and group databases that the Apache, NCSA, and even CERN servers implement,
and provides you with a generic interface that hides the inconsistencies, simplifying
the maintenance of the databases.</P>
<P>The user/group databases may take various forms and use different internal formats,
depending on your preference and what tools are available on your system. The <TT>HTTPD::UserAdmin</TT>
module allows you to access databases implemented as DBM files or straight text files.
It also gives you the capability to talk to an SQL database and to get/put user information
to an SQL database. Its companion, <TT>HTTPD::Authen</TT>, knows about the various
formats of the entries in these files, including MD5 (Message Digest), as well as
standard (default) DES encryption and, of course, plaintext.</P>
<P>The <TT>HTTPD::UserAdmin</TT> module provides you with several useful methods
after you've created a new <TT>HTTPD::UserAdmin</TT> object. These include the following:
<TABLE BORDER="0">
<TR ALIGN="LEFT" rowspan="1">
<TD ALIGN="LEFT"><TT>add(</TT>name<TT>,</TT>passwd<TT>)</TT></TD>
<TD ALIGN="LEFT">Add a new user to the database</TD>
</TR>
<TR ALIGN="LEFT" rowspan="1">
<TD ALIGN="LEFT"><TT>delete(</TT>name<TT>)</TT></TD>
<TD ALIGN="LEFT">Delete a user from the database</TD>
</TR>
<TR ALIGN="LEFT" rowspan="1">
<TD ALIGN="LEFT"><TT>exists(</TT>name<TT>)</TT></TD>
<TD ALIGN="LEFT">Check if the user exists in the database</TD>
</TR>
<TR ALIGN="LEFT" rowspan="1">
<TD ALIGN="LEFT"><TT>password(</TT>name<TT>)</TT></TD>
<TD ALIGN="LEFT">Return the encrypted password for the user</TD>
</TR>
<TR ALIGN="LEFT" rowspan="1">
<TD ALIGN="LEFT"><TT>list</TT></TD>
<TD ALIGN="LEFT">Return a list of all the usernames in the database</TD>
</TR>
<TR ALIGN="LEFT" rowspan="1">
<TD ALIGN="LEFT"><TT>update(</TT>name<TT>,</TT>password<TT>)</TT></TD>
<TD ALIGN="LEFT">Update the user with a new password</TD>
</TR>
<TR ALIGN="LEFT" rowspan="1">
<TD ALIGN="LEFT"><TT>group</TT></TD>
<TD ALIGN="LEFT">Create a new <TT>GroupAdmin</TT> object</TD>
</TR>
<TR ALIGN="LEFT" rowspan="1">
<TD ALIGN="LEFT"><TT>lock([</TT>timeout<TT>])</TT></TD>
<TD ALIGN="LEFT">Create a file lock for the database in anticipation of updating it</TD>
</TR>
<TR ALIGN="LEFT" rowspan="1">
<TD ALIGN="LEFT"><TT>unlock</TT></TD>
<TD ALIGN="LEFT">Unlock the database</TD>
</TR>
<TR ALIGN="LEFT" rowspan="1">
<TD ALIGN="LEFT"><FONT COLOR="#000000">db(dbname)</FONT></TD>
<TD ALIGN="LEFT"><FONT COLOR="#000000">Select a different database</FONT></TD>
</TR>
</TABLE>
</P>
<PRE></PRE>
<P>There are several examples, provided as tests in the t/ directory, that accompany
the <TT>HTTPD::</TT> module suite. You can adapt these to suit your particular needs.
The simplest case might be one in which you wish to add a new user to an existing
database. The following simple script lets you do this, first by checking if the
specified user already exists in the database. If so, it updates the record with
the new password. If not, it creates the new entry for the user.</P>
<PRE><FONT COLOR="#0066FF">#!/usr/local/bin/perl
require HTTPD::UserAdmin;
$path = "/usr/local/etc/httpd/conf";
$username = shift || "josie";
$password = "pussycats";
$user = new HTTPD::UserAdmin(DBType => "Text", Path => $path, Server => "apache");
if($user->exists($username)){
print "$username already exists in the database\n";
print "Updating with new password\n";
$user->update($username, $password);
}
else{
print "Adding $username to database\n";
$user->add($username, $password);
if($user->exists($username)){
print "Successful\n";
}
}
</FONT></PRE>
<CENTER>
<H4><A NAME="Heading14"></A><FONT COLOR="#000077">Changing Passwords from the Web</FONT></H4>
</CENTER>
<P>One of the most common requests I've seen for a CGI program is the one for a program
that allows the Web client to change his/her password. Certainly, it's reasonable
to want to be able to do this; unfortunately, it's more complicated and risky than
it seems.</P>
<P>Because the httpd is running as the user <TT>nobody</TT>, and because the passwd
file doesn't (or shouldn't) belong to that user, it's a bit of a quandary to have
an <TT>exec</TT>'d CGI program change that file. There are alternatives, however.
You can run a secondary server on a different port, under the <TT>www</TT> userid,
whose only purpose would be to execute the CGI program that changes the user's password,
for instance. Another alternative might be to implement something with <TT>SafeCGIPerl</TT>,
discussed later, and the <TT>HTTPD::UserAdmin</TT> module just introduced. Coding
it up is left as an exercise for the wary administrator. Be very, very careful.
<CENTER>
<H4><A NAME="Heading15"></A><FONT COLOR="#000077">Monitoring Userids</FONT></H4>
</CENTER>
<P>As a final note in this section, we'll add a bit more code to our ongoing example
to keep track of userids in the .htpasswd file for each <TT><Directory></TT>
entry in access.conf.</P>
<PRE><FONT COLOR="#0066FF">use HTTPD::Config;
require HTTPD::UserAdmin;
require "stat.pl";
$conf = `/usr/local/etc/httpd/conf';
@files = qw(httpd.conf srm.conf access.conf);
$V= new HTTPD::Config (SERVER => Apache,
SERVER_ROOT => $conf,
FILES => [@files]);
print "Userid: ", $V->user,"\n";
print "Group: ", $V->group,"\n";
print "Administrator is: ", $V->server_admin,"\n";
print "Running at port: ", $V->port,"\n";
print "Access filename: ",$V->access_file_name,"\n";
print "User Directory: ", $V->user_dir,"\n";
print "Global Types:\t", join("\n\t\t",$V->add_type),"\n";
print "\n\n";
foreach $dir (keys %{$V->{`Directory'}}){
print "Options for Directory: $dir\n";
while(($opt,$val) = each %{$V->{`Directory'}{$dir}{`OPTIONS'}}){
print "\t",$opt, " : ", @{$val},"\n";
if($opt eq "AuthUserFile"){
($path = join(`',@{$val})) =~ s/^(.*)\/.*/$1/;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -