httpd-modules-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From "Nebergall, Christopher" <cneb...@sandia.gov>
Subject RE: secure use of ap_get_server_name/port
Date Thu, 06 Mar 2008 23:26:08 GMT
Sorry let me clarify.   I'm looking at doing external policy evaluation of the URI like is
done is most SSO products.   I have to create a policy for every URL the user may hit (with
support for wildcards).  I would like to minimize the number of policies created.  So while
there may be 5 different ways a user may type the hostname and port portions of the URI for
the same content, I would want it to evaluate to just 1 definitive answer that I can create
policy for (or at least as few as possible).   Plus I need to beware of malicious users. 
If they set an invalid host header, I don't want a case where apache ignores the host header
and host header port because it doesn't know about the server mentioned in the host header,
but the policy code still uses it to do policy evaluation. That creates a case where the code
would be granting or denying access based on the wrong policy.

Example

ServerName foo.com
ServerAlias bob.smith.bar.com *.jones.com

Assume these requests:

GET http://bob.smith.bar.com/cgi-bin/printenv
GET http://mark.jones.com/cgi-bin/printenv

I want all of these evaluated to only http://foo.com/cgi-bin/printenv

Which API's would do this for the server name and host portions?

-Christopher
-----Original Message-----
From: Ray Morris [mailto:support@bettercgi.com]
Sent: Thursday, March 06, 2008 3:32 PM
To: modules-dev@httpd.apache.org
Subject: Re: secure use of ap_get_server_name/port

On 03/06/2008 01:09:37 PM, Nebergall, Christopher wrote:
> I'm looking for secure versions of ap_get_server_name and
> ap_get_server_port which can be trusted to always evaluate to the
> correct host and port for re-constructing the original URL the user
> requested.

  The text part of your question seems to contradict itself regarding what you're actually
wanting, then the code gives a third result.  Let's be sure exactly what you want.  If you
really do want to reconstruct the orginal URL requested, the hostname will be found in headers_in:


host = apr_pstrdup( r->pool, apr_table_get(r->main->headers_in, "Host") ); if (host
== NULL) {
    # The client didn't specify a hostname, so punt:
    host = apr_pstrdup( r->pool, ap_get_server_name(r) );
    if (host == NULL) return 0;
}


> I've removed all of the code below which seemed to rely on DNS, or
> info sent from the client.

  I thought you wanted to reconstruct what the client sent, but now you say you want to remove
any reference to what the client sent?  You're asking for two opposite things.



> It seems that if the ServerName directive is there it should return a
> value and that would be it.

   The ServerName may have no relationship at all to the original URL requested by the client,
which is what you said you wanted.

ServerName foo.com
ServerAlias bob.smith.bar.com

GET http://bob.smith.bar.com/


> I'm confused why there are so many different ways to get the hostname
> or port.

  Assume this configuration and no other hosts on the server for the four following requests:

ServerName foo.com
ServerAlias bob.smith.bar.com *.jones.com

CASE 1
Assume this request:
GET http://bob.smith.bar.com/

  There are at least two "correct" answers for the hostname - one can get the value of ServerName,
as you mentioned, or one cause use the ServerAlias which matched the request.
So we need to functions to do the two different things.
Given the possibility of UseCanonicalName, we may want three functions - one for the first
answer, one for the second answer, and one that respects that silly UseCanonicalName directive.

CASE 2
Assume this request:
GET http://joe.jones.com/

  Now we have three hostnames you be interested in - the specified ServerName, foo.com, the
alias that matched, *.jones.com, and the actual hostname requested, joe.jones.com.  Throw
in the fact that UseCanonicalName may be on or off and you need four functions in order to
be able to get whichever answer you seek.

CASE 3
Assume noname.com resolves to 123.123.123.123, an IP on this server.

Assume this request:
GET http://noname.com/

  Now we have four possible answers - the value of ServerName, the the requested host name,
or the match, which is just the IP - or is it an empty name?

  I could go on and on, but I think the point is clear - there are a lot of ways to get different
hostnames, depending on what you're looking for.  You say you are confused about why there
are so many ways to get the host name, but then again you're also confused about which hostname
you want - the one from the original request or the one from the ServerName directive.
One could also throw in the possibility that this request isn't the orginal request, but is
a sub-request.
In that case there could up to twelve different answers you may be interested in - the four
answers from case 4, each regarding THIS request, it's parent, or the main original request.

   In most cases, the best one to use is probably the hostname that was actually requested
for this request:
apr_table_get(r->headers_in, "Host")
There may be a better way to get that information. I'm somewhat new to Apache module programming.
--
Ray B. Morris
support@bettercgi.com

Strongbox - The next generation in site security:
http://www.bettercgi.com/strongbox/




On 03/06/2008 01:09:37 PM, Nebergall, Christopher wrote:
> I'm looking for secure versions of ap_get_server_name and
> ap_get_server_port which can be trusted to always evaluate to the
> correct host and port for re-constructing the original URL the user
> requested.   I've removed all of the code below which seemed to rely
> on DNS, or info sent from the client.  Is the code below a sufficient
> minimal set to get working secure versions of those functions?  I'm
> confused why there are so many different ways to get the hostname or
> port.  It seems that if the ServerName directive is there it should
> return a value and that would be it.   Also why would code like cport
> below ever be zero?
>
> API_EXPORT(const char *) ap_get_server_name2(request_rec *r) {
>         return r->hostname?r->hostname:r->server->server_hostname;
> }
>
> API_EXPORT(unsigned) ap_get_server_port2(const request_rec *r) {
>     unsigned port;
>     unsigned cport = ntohs(r->connection->local_addr.sin_port);
>     port = cport ? cport : r->server->port ? r->server->port :
> ap_default_port(r);
>     return port;
> }
>
> -Christopher
>
> Original apache 1.3 code
>
> ----------------------------------------------------------------------
> -------------------------------------------
> API_EXPORT(const char *) ap_get_server_name(request_rec *r) {
>     conn_rec *conn = r->connection;
>     core_dir_config *d;
>
>     d = (core_dir_config *)ap_get_module_config(r->per_dir_config,
>                                                 &core_module);
>
>     if (d->use_canonical_name == USE_CANONICAL_NAME_OFF) {
>         return r->hostname ? r->hostname :
> r->server->server_hostname;
>     }
>     if (d->use_canonical_name == USE_CANONICAL_NAME_DNS) {
>         if (conn->local_host == NULL) {
>             struct in_addr *iaddr;
>             struct hostent *hptr;
>             int old_stat;
>             old_stat = ap_update_child_status(conn->child_num,
>                                               SERVER_BUSY_DNS, r);
>             iaddr = &(conn->local_addr.sin_addr);
>             hptr = gethostbyaddr((char *)iaddr, sizeof(struct
> in_addr),
>                                  AF_INET);
>             if (hptr != NULL) {
>                 conn->local_host = ap_pstrdup(conn->pool,
>                                               (void *)hptr->h_name);
>                 ap_str_tolower(conn->local_host);
>             }
>             else {
>                 conn->local_host = ap_pstrdup(conn->pool,
>
> r->server->server_hostname);
>             }
>             (void) ap_update_child_status(conn->child_num, old_stat,
> r);
>         }
>         return conn->local_host;
>     }
>     /* default */
>     return r->server->server_hostname; }
>
> API_EXPORT(unsigned) ap_get_server_port(const request_rec *r) {
>     unsigned port;
>     unsigned cport = ntohs(r->connection->local_addr.sin_port);
>     core_dir_config *d =
>       (core_dir_config *)ap_get_module_config(r->per_dir_config,
> &core_module);
>
>     if (d->use_canonical_name == USE_CANONICAL_NAME_OFF
>         || d->use_canonical_name == USE_CANONICAL_NAME_DNS) {
>
>         /* With UseCanonicalName Off Apache will form self-referential
>          * URLs using the hostname and port supplied by the client if
>          * any are supplied (otherwise it will use the canonical
> name).
>          */
>         port = r->parsed_uri.port_str ? r->parsed_uri.port :
>           cport ? cport :
>             r->server->port ? r->server->port :
>               ap_default_port(r);
>     } else { /* d->use_canonical_name == USE_CANONICAL_NAME_ON */
>         port = r->server->port ? r->server->port :
>           cport ? cport :
>             ap_default_port(r);
>     }
>
>     /* default */
>     return port;
> }
>
>




Mime
View raw message