You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@httpd.apache.org by Rob Hartill <ro...@imdb.com> on 1997/03/12 03:42:01 UTC

Re: NCSA-style 'referer allow' in Apache?

On Tue, 11 Mar 1997, David Richards wrote:

> NCSA had a handy access-control feature in the latested (1.5.2.x) server
> releases where the LIMIT directive could be used to restrict access based
> on the referer variable, then the 'On-Deny' option could be used to send
> them to an appropriate page.
> 
> This is very useful to provide an efficient, automated mechanism for keeping
> people from inlining your graphics their pages. I know I can do this with
> a CGI script, but that adds significant server overhead.
> 
> 
> Is there any good way to implement the following in Apache?
> 
> <LIMIT GET>
> order deny,allow
> deny from all
> 
> referer allow from http://www.mydomain.com/
> 
> OnDeny http://www.mydomain.com/EVIL.gif
> </LIMIT>
 
there's nothing to do this automatically, but it should be possible to
create a module to do this from Apache 1.2b7's mod_browser.c. That module
sets environment variables based on the User-Agent field. Change it to
look at "Referer" and it'll then let you do something like:

ReferrerMatch http://www.parasite.com/ block_referrers

: : : 

ErrorDocument 403 http://www.mydomain.com/EVIL.gif
order allow,deny
allow from all
deny from env=block_referrers

This is all theory, but I think it'll work. No hang on, the theory
just got turned into practice. A new module is attached.. Enjoy.

regards,
rob
--
Rob Hartill   Internet Movie Database (Ltd)
http://us.imdb.com/Oscars/oscars_1996 -  hype free Oscars (R) info.
http://us.imdb.com/usr/sweepstake     -  Win a 56k X2 modem. Free draw.


-=-=-=-=

Look at the docs for mod_browser.c and use "ReferrerMatch" and
"ReferrerMatchNoCase" in place of the "BrowserMatch" equivalents.


/* ====================================================================
 * Copyright (c) 1997 The Apache Group.  All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer. 
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * 3. All advertising materials mentioning features or use of this
 *    software must display the following acknowledgment:
 *    "This product includes software developed by the Apache Group
 *    for use in the Apache HTTP server project (http://www.apache.org/)."
 *
 * 4. The names "Apache Server" and "Apache Group" must not be used to
 *    endorse or promote products derived from this software without
 *    prior written permission.
 *
 * 5. Redistributions of any form whatsoever must retain the following
 *    acknowledgment:
 *    "This product includes software developed by the Apache Group
 *    for use in the Apache HTTP server project (http://www.apache.org/)."
 *
 * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY
 * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE APACHE GROUP OR
 * IT'S CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
 * OF THE POSSIBILITY OF SUCH DAMAGE.
 * ====================================================================
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the Apache Group and was originally based
 * on public domain software written at the National Center for
 * Supercomputing Applications, University of Illinois, Urbana-Champaign.
 * For more information on the Apache Group and the Apache HTTP server
 * project, please see <http://www.apache.org/>.
 *
 */

/*
 * mod_check_referer.c
 * Set environment variables based on the 'Referer' header.
 * 
 * Rob Hartill <ro...@imdb.com>
 *  this is basicaly a rip-off of Alexei Kosut's mod_browser.c
 */

#include "httpd.h"
#include "http_config.h"

typedef struct {
    char *name;
    regex_t *preg;
    table *referrer_type;
} referrer_entry;

typedef struct {
    array_header *referrers;
} referrer_server_config_rec;

module referrer_module;

void *create_referrer_config (pool *p, server_rec *dummy)
{
    referrer_server_config_rec *new =
   (referrer_server_config_rec *) palloc (p, sizeof(referrer_server_config_rec));

    new->referrers = make_array (p, 20, sizeof(referrer_entry));
    return (void *)new;
}

void *merge_referrer_config (pool *p, void *basev, void *overridesv)
{
    referrer_server_config_rec *a =
	pcalloc(p, sizeof(referrer_server_config_rec));
    referrer_server_config_rec *base = basev, *overrides = overridesv;

    a->referrers = append_arrays(p, base->referrers, overrides->referrers);
    return a;
}

const char *add_referrer(cmd_parms *cmd, void *dummy, char *name,
			const char *feature)
{
    referrer_server_config_rec *sconf =
      get_module_config (cmd->server->module_config, &referrer_module);
    referrer_entry *new, *entries = (referrer_entry *)sconf->referrers->elts;
    char *var;
    int i, cflags = (int)cmd->info;

    /* First, try to merge into an existing entry */

    for (i = 0; i < sconf->referrers->nelts; ++i) {
	referrer_entry *b = &entries[i];
	if (!strcmp(b->name, name)) {
	    var = getword(cmd->pool, &feature, '=');
	    if (*feature) table_set(b->referrer_type, var, feature);
	    else if (*var == '!') table_set(b->referrer_type, var + 1, "!");
	    else table_set(b->referrer_type, var, "1");
	    return NULL;
	}
    }

    /* If none was found, create a new entry */

    new = push_array(sconf->referrers);
    new->name = name;
    new->preg = pcalloc(cmd->pool, sizeof(regex_t));
    if (regcomp(new->preg, name, REG_EXTENDED|REG_NOSUB|cflags))
	return "Referrer regex could not be compiled.";
    new->referrer_type = make_table(cmd->pool, 5);

    var = getword(cmd->pool, &feature, '=');
    if (*feature) table_set(new->referrer_type, var, feature);
    else if (*var == '!') table_set(new->referrer_type, var + 1, "!");
    else table_set(new->referrer_type, var, "1");

    return NULL;
}

command_rec referrer_module_cmds[] = {
{ "ReferrerMatch", add_referrer, (void*)0,
    RSRC_CONF, ITERATE2, "A referrer regex and a list of variables." },
{ "ReferrerMatchNoCase", add_referrer, (void*)REG_ICASE,
    RSRC_CONF, ITERATE2, "a referrer regex and a list of variables." },
{ NULL },
};

int parse_headers_referrer_module(request_rec *r)
{
    server_rec *s = r->server;
    referrer_server_config_rec *sconf = get_module_config (s->module_config,
							  &referrer_module);
    referrer_entry *entries = (referrer_entry *)sconf->referrers->elts;
    table_entry *elts;
    char *ref = table_get(r->headers_in, "Referer");
    int i, j;

    if (!ref) return DECLINED;

    for (i = 0; i < sconf->referrers->nelts; ++i) {
	referrer_entry *b = &entries[i];

	if (!regexec(b->preg, ref, 0, NULL, 0)) {
	    elts = (table_entry *)b->referrer_type->elts;

	    for (j = 0; j < b->referrer_type->nelts; ++j) {
		if (!strcmp(elts[j].val, "!"))
		    table_unset(r->subprocess_env, elts[j].key);
		else
		    table_set(r->subprocess_env, elts[j].key, elts[j].val);
	    }
	}
    }

    return OK;  
}

module referrer_module = {
   STANDARD_MODULE_STUFF,
   NULL,			/* initializer */
   NULL,			/* dir config creater */
   NULL,			/* dir merger --- default is to override */
   create_referrer_config,	/* server config */
   merge_referrer_config,     	/* merge server configs */
   referrer_module_cmds,	/* command table */
   NULL,			/* handlers */
   NULL,			/* filename translation */
   NULL,			/* check_user_id */
   NULL,			/* check auth */
   NULL,			/* check access */
   NULL,			/* type_checker */
   NULL,			/* fixups */
   NULL,			/* logger */
   parse_headers_referrer_module	/* header parser */
};


Re: NCSA-style 'referer allow' in Apache?

Posted by Dean Gaudet <dg...@arctic.org>.
Didn't Alexei write mod_block for this?  (see
/apache/dist/contrib/modules/mod_block.c at any mirror).

I've also seen some cool javascript that fudges with the framesets if
someone, say, tries to embed your page in their frames. 

For 2.0 I want to play with a more general syntax for a lot of this config
stuff, there's a few primitives that should give a lot of this for free.

Dean

On Wed, 12 Mar 1997, Rob Hartill wrote:

> On Tue, 11 Mar 1997, David Richards wrote:
> 
> > NCSA had a handy access-control feature in the latested (1.5.2.x) server
> > releases where the LIMIT directive could be used to restrict access based
> > on the referer variable, then the 'On-Deny' option could be used to send
> > them to an appropriate page.
> > 
> > This is very useful to provide an efficient, automated mechanism for keeping
> > people from inlining your graphics their pages. I know I can do this with
> > a CGI script, but that adds significant server overhead.
> > 
> > 
> > Is there any good way to implement the following in Apache?
> > 
> > <LIMIT GET>
> > order deny,allow
> > deny from all
> > 
> > referer allow from http://www.mydomain.com/
> > 
> > OnDeny http://www.mydomain.com/EVIL.gif
> > </LIMIT>
>  
> there's nothing to do this automatically, but it should be possible to
> create a module to do this from Apache 1.2b7's mod_browser.c. That module
> sets environment variables based on the User-Agent field. Change it to
> look at "Referer" and it'll then let you do something like:
> 
> ReferrerMatch http://www.parasite.com/ block_referrers
> 
> : : : 
> 
> ErrorDocument 403 http://www.mydomain.com/EVIL.gif
> order allow,deny
> allow from all
> deny from env=block_referrers
> 
> This is all theory, but I think it'll work. No hang on, the theory
> just got turned into practice. A new module is attached.. Enjoy.
> 
> regards,
> rob
> --
> Rob Hartill   Internet Movie Database (Ltd)
> http://us.imdb.com/Oscars/oscars_1996 -  hype free Oscars (R) info.
> http://us.imdb.com/usr/sweepstake     -  Win a 56k X2 modem. Free draw.
> 
> 
> -=-=-=-=
> 
> Look at the docs for mod_browser.c and use "ReferrerMatch" and
> "ReferrerMatchNoCase" in place of the "BrowserMatch" equivalents.
> 
> 
> /* ====================================================================
>  * Copyright (c) 1997 The Apache Group.  All rights reserved.
>  *
>  * Redistribution and use in source and binary forms, with or without
>  * modification, are permitted provided that the following conditions
>  * are met:
>  *
>  * 1. Redistributions of source code must retain the above copyright
>  *    notice, this list of conditions and the following disclaimer. 
>  *
>  * 2. Redistributions in binary form must reproduce the above copyright
>  *    notice, this list of conditions and the following disclaimer in
>  *    the documentation and/or other materials provided with the
>  *    distribution.
>  *
>  * 3. All advertising materials mentioning features or use of this
>  *    software must display the following acknowledgment:
>  *    "This product includes software developed by the Apache Group
>  *    for use in the Apache HTTP server project (http://www.apache.org/)."
>  *
>  * 4. The names "Apache Server" and "Apache Group" must not be used to
>  *    endorse or promote products derived from this software without
>  *    prior written permission.
>  *
>  * 5. Redistributions of any form whatsoever must retain the following
>  *    acknowledgment:
>  *    "This product includes software developed by the Apache Group
>  *    for use in the Apache HTTP server project (http://www.apache.org/)."
>  *
>  * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY
>  * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
>  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
>  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE APACHE GROUP OR
>  * IT'S CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
>  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
>  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
>  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
>  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
>  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
>  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
>  * OF THE POSSIBILITY OF SUCH DAMAGE.
>  * ====================================================================
>  *
>  * This software consists of voluntary contributions made by many
>  * individuals on behalf of the Apache Group and was originally based
>  * on public domain software written at the National Center for
>  * Supercomputing Applications, University of Illinois, Urbana-Champaign.
>  * For more information on the Apache Group and the Apache HTTP server
>  * project, please see <http://www.apache.org/>.
>  *
>  */
> 
> /*
>  * mod_check_referer.c
>  * Set environment variables based on the 'Referer' header.
>  * 
>  * Rob Hartill <ro...@imdb.com>
>  *  this is basicaly a rip-off of Alexei Kosut's mod_browser.c
>  */
> 
> #include "httpd.h"
> #include "http_config.h"
> 
> typedef struct {
>     char *name;
>     regex_t *preg;
>     table *referrer_type;
> } referrer_entry;
> 
> typedef struct {
>     array_header *referrers;
> } referrer_server_config_rec;
> 
> module referrer_module;
> 
> void *create_referrer_config (pool *p, server_rec *dummy)
> {
>     referrer_server_config_rec *new =
>    (referrer_server_config_rec *) palloc (p, sizeof(referrer_server_config_rec));
> 
>     new->referrers = make_array (p, 20, sizeof(referrer_entry));
>     return (void *)new;
> }
> 
> void *merge_referrer_config (pool *p, void *basev, void *overridesv)
> {
>     referrer_server_config_rec *a =
> 	pcalloc(p, sizeof(referrer_server_config_rec));
>     referrer_server_config_rec *base = basev, *overrides = overridesv;
> 
>     a->referrers = append_arrays(p, base->referrers, overrides->referrers);
>     return a;
> }
> 
> const char *add_referrer(cmd_parms *cmd, void *dummy, char *name,
> 			const char *feature)
> {
>     referrer_server_config_rec *sconf =
>       get_module_config (cmd->server->module_config, &referrer_module);
>     referrer_entry *new, *entries = (referrer_entry *)sconf->referrers->elts;
>     char *var;
>     int i, cflags = (int)cmd->info;
> 
>     /* First, try to merge into an existing entry */
> 
>     for (i = 0; i < sconf->referrers->nelts; ++i) {
> 	referrer_entry *b = &entries[i];
> 	if (!strcmp(b->name, name)) {
> 	    var = getword(cmd->pool, &feature, '=');
> 	    if (*feature) table_set(b->referrer_type, var, feature);
> 	    else if (*var == '!') table_set(b->referrer_type, var + 1, "!");
> 	    else table_set(b->referrer_type, var, "1");
> 	    return NULL;
> 	}
>     }
> 
>     /* If none was found, create a new entry */
> 
>     new = push_array(sconf->referrers);
>     new->name = name;
>     new->preg = pcalloc(cmd->pool, sizeof(regex_t));
>     if (regcomp(new->preg, name, REG_EXTENDED|REG_NOSUB|cflags))
> 	return "Referrer regex could not be compiled.";
>     new->referrer_type = make_table(cmd->pool, 5);
> 
>     var = getword(cmd->pool, &feature, '=');
>     if (*feature) table_set(new->referrer_type, var, feature);
>     else if (*var == '!') table_set(new->referrer_type, var + 1, "!");
>     else table_set(new->referrer_type, var, "1");
> 
>     return NULL;
> }
> 
> command_rec referrer_module_cmds[] = {
> { "ReferrerMatch", add_referrer, (void*)0,
>     RSRC_CONF, ITERATE2, "A referrer regex and a list of variables." },
> { "ReferrerMatchNoCase", add_referrer, (void*)REG_ICASE,
>     RSRC_CONF, ITERATE2, "a referrer regex and a list of variables." },
> { NULL },
> };
> 
> int parse_headers_referrer_module(request_rec *r)
> {
>     server_rec *s = r->server;
>     referrer_server_config_rec *sconf = get_module_config (s->module_config,
> 							  &referrer_module);
>     referrer_entry *entries = (referrer_entry *)sconf->referrers->elts;
>     table_entry *elts;
>     char *ref = table_get(r->headers_in, "Referer");
>     int i, j;
> 
>     if (!ref) return DECLINED;
> 
>     for (i = 0; i < sconf->referrers->nelts; ++i) {
> 	referrer_entry *b = &entries[i];
> 
> 	if (!regexec(b->preg, ref, 0, NULL, 0)) {
> 	    elts = (table_entry *)b->referrer_type->elts;
> 
> 	    for (j = 0; j < b->referrer_type->nelts; ++j) {
> 		if (!strcmp(elts[j].val, "!"))
> 		    table_unset(r->subprocess_env, elts[j].key);
> 		else
> 		    table_set(r->subprocess_env, elts[j].key, elts[j].val);
> 	    }
> 	}
>     }
> 
>     return OK;  
> }
> 
> module referrer_module = {
>    STANDARD_MODULE_STUFF,
>    NULL,			/* initializer */
>    NULL,			/* dir config creater */
>    NULL,			/* dir merger --- default is to override */
>    create_referrer_config,	/* server config */
>    merge_referrer_config,     	/* merge server configs */
>    referrer_module_cmds,	/* command table */
>    NULL,			/* handlers */
>    NULL,			/* filename translation */
>    NULL,			/* check_user_id */
>    NULL,			/* check auth */
>    NULL,			/* check access */
>    NULL,			/* type_checker */
>    NULL,			/* fixups */
>    NULL,			/* logger */
>    parse_headers_referrer_module	/* header parser */
> };
> 
>