You are viewing a plain text version of this content. The canonical link for it is here.
Posted to users@httpd.apache.org by Roman Medina-Heigl Hernandez <ro...@rs-labs.com> on 2009/03/02 10:02:11 UTC

Re: [users@httpd] Mixing rewrite with authn_dbd: Rewriting based on path value stored in mysql table

Hello,

I have a *partial*-working solution which I'd like to share with you. It's
tricky (based on my own home structure) and limited, though. Feedback is
appreciated, please!

Some comments:
- Debian 5.0 includes ajp 1.2.12, so I cannot get the url/dir from another
column in users' table (this functionality is for ajp 1.3+). In my case, I
can live without it, having the following convention: username will be a
domainname (which has sense, since I want to offer stats pages for
different domains). For instance, stats for domain "test.com" will use the
username "test.com".
- I've only experimented with per-dir rewrite (the non-recommended way...),
which has the limitation of request reinjection (so you must include
negative rewrite rules which protect you against loops). Perhaps it may be
improved with server rewrite.
- The current method is not secure: an attacker knowing the internal
homedir structure could easily craft a request bypassing the rewrite
ruleset, being able to access other domain/user's stats. It could also be
used to access other directories/files of other users (in my case those
dirs are protected using OS permissions).
- Performance is not very efficient, since I'm reinjecting requests (it
seems unavoidable if using per-dir rewrite).
- Stats home for domain "test.com" will be:
/clientes/test.com/stats/http/
which should be accessed through:
http://isp/stats/


Current config is:
====

        Alias /stats /clientes

        <Location /stats/>
                # Basic Auth
                AuthType Basic
                AuthName "Stats"
                AuthBasicProvider dbd

                Require valid-user
                AuthDBDUserPWQuery "SELECT pass FROM stats WHERE user = %s
and enabled = 1"

                # Rewrite para que cada user entre a su directorio de stats
particular
                RewriteEngine on
                RewriteBase /stats
                RewriteRule !^/clientes/[^/]+/stats/http/ - [C]
                RewriteRule ^/clientes/(.*)
/stats/%{REMOTE_USER}/stats/http/$1 [PT]

====

More comments:
- at the beginning I tried something like:
               RewriteBase /stats
               RewriteCond $1 !^%{REMOTE_USER}/
               RewriteRule ^/clientes/(.*)
/stats/%{REMOTE_USER}/stats/http/$1 [PT]

The problem is that you cannot have %{REMOTE_USER} as 2nd parameters in
RewriteCond, so I have no way for comparing it with $1 (which coudn't be in
2nd parameter, either). Any idea to implement it? (i.e. test if REMOTE_USER
string is included in URI path).

Cheers,
-Roman

---------------------------------------------------------------------
The official User-To-User support forum of the Apache HTTP Server Project.
See <URL:http://httpd.apache.org/userslist.html> for more info.
To unsubscribe, e-mail: users-unsubscribe@httpd.apache.org
   "   from the digest: users-digest-unsubscribe@httpd.apache.org
For additional commands, e-mail: users-help@httpd.apache.org


Re: [users@httpd] Mixing rewrite with authn_dbd: Rewriting based on path value stored in mysql table

Posted by Roman Medina-Heigl Hernandez <ro...@rs-labs.com>.
Bob Ionescu escribió:
> 2009/5/12 Roman Medina-Heigl Hernandez <ro...@rs-labs.com>:
>> My final solution is:
>>
>>                RewriteBase /stats
>>                RewriteCond %{REMOTE_USER}/<>$1 !^([^<]+)<>\1
>>                RewriteRule ^/clientes/(.*) /stats/%{REMOTE_USER}/stats/http/$1
>>
>>                RewriteCond $1 !^[^/]+/stats/http/
>>                RewriteRule ^/clientes/(.*) hacking_attempt [F]
>>
>>
>> The alternative (adding L) is:
>>
>>                RewriteBase /stats
>>                RewriteCond %{REMOTE_USER}/<>$1 !^([^<]+)<>\1
>>                RewriteRule ^/clientes/(.*)
>> /stats/%{REMOTE_USER}/stats/http/$1 [L]
>>
>>                RewriteCond $1 !^[^/]+/stats/http/
>>                RewriteRule ^/clientes/(.*) hacking_attempt [F,L]
>>
>> But I see no real difference between both solutions. Am I right?
> 
> L makes only sense to abort something below, i.e. if there's nothing,
> there's nothing to abort (F implies L btw., the substitution will be
> dropped as well). Your second rule (forbidden) comes never true, if
> the first rule matched. So you could stop further (useless) processing
> with the L flag at your first rule.

Agreed.

For the record, final solution:
                RewriteBase /stats
                RewriteCond %{REMOTE_USER}/<>$1 !^([^<]+)<>\1
                RewriteRule ^/clientes/(.*)
/stats/%{REMOTE_USER}/stats/http/$1 [L]

                RewriteCond $1 !^[^/]+/stats/http/
                RewriteRule ^/clientes/(.*) hacking_attempt [F]

Thanks a lot to all who contributed the thread and specially to Bob!!!!

Cheers,
-Roman


---------------------------------------------------------------------
The official User-To-User support forum of the Apache HTTP Server Project.
See <URL:http://httpd.apache.org/userslist.html> for more info.
To unsubscribe, e-mail: users-unsubscribe@httpd.apache.org
   "   from the digest: users-digest-unsubscribe@httpd.apache.org
For additional commands, e-mail: users-help@httpd.apache.org


Re: [users@httpd] Mixing rewrite with authn_dbd: Rewriting based on path value stored in mysql table

Posted by Bob Ionescu <bo...@googlemail.com>.
2009/5/12 Roman Medina-Heigl Hernandez <ro...@rs-labs.com>:
> My final solution is:
>
>                RewriteBase /stats
>                RewriteCond %{REMOTE_USER}/<>$1 !^([^<]+)<>\1
>                RewriteRule ^/clientes/(.*) /stats/%{REMOTE_USER}/stats/http/$1
>
>                RewriteCond $1 !^[^/]+/stats/http/
>                RewriteRule ^/clientes/(.*) hacking_attempt [F]
>
>
> The alternative (adding L) is:
>
>                RewriteBase /stats
>                RewriteCond %{REMOTE_USER}/<>$1 !^([^<]+)<>\1
>                RewriteRule ^/clientes/(.*)
> /stats/%{REMOTE_USER}/stats/http/$1 [L]
>
>                RewriteCond $1 !^[^/]+/stats/http/
>                RewriteRule ^/clientes/(.*) hacking_attempt [F,L]
>
> But I see no real difference between both solutions. Am I right?

L makes only sense to abort something below, i.e. if there's nothing,
there's nothing to abort (F implies L btw., the substitution will be
dropped as well). Your second rule (forbidden) comes never true, if
the first rule matched. So you could stop further (useless) processing
with the L flag at your first rule.

Bob

---------------------------------------------------------------------
The official User-To-User support forum of the Apache HTTP Server Project.
See <URL:http://httpd.apache.org/userslist.html> for more info.
To unsubscribe, e-mail: users-unsubscribe@httpd.apache.org
   "   from the digest: users-digest-unsubscribe@httpd.apache.org
For additional commands, e-mail: users-help@httpd.apache.org


Re: [users@httpd] Mixing rewrite with authn_dbd: Rewriting based on path value stored in mysql table

Posted by Roman Medina-Heigl Hernandez <ro...@rs-labs.com>.
Bob Ionescu escribió:
> 2009/5/11 Roman Medina-Heigl Hernandez <ro...@rs-labs.com>:
>> Bob Ionescu escribió:
>>> 2009/3/2 Roman Medina-Heigl Hernandez <ro...@rs-labs.com>:
>>>> The problem is that you cannot have %{REMOTE_USER} as 2nd parameters in
>>>> RewriteCond, so I have no way for comparing it with $1
>>> -didn't read all-; but you can compare it with a regEx internal backreference.
>>>
>>> RewriteBase /stats
>>> RewriteCond %{REMOTE_USER}<>$1 !^([^<]+)<>\1
>> Could you explain that, please? I didn't know that syntax...
> 
> You're capturing a value with ^([^<]+), that is according to our test
> string the value of %{REMOTE_USER} followed by the two characters <>
> as a unique separator followed by the (previous) match of ([^<]+)
> which matches against the value of $1.
> 
> E.g. if the remote_user is foo, the regEx will match against a test string of
> foo<>foo
> 
> Just take a look at the manpage of PCRE, http://www.pcre.org/pcre.txt section
> BACK REFERENCES
>        Outside a character class, a backslash followed by a digit greater than

I knew (and have extensively used) about back references in PCRE but
thought the "<>" in RewriteCond's first arg could have a special meaning. I
didn't happen to figure out that you were simply "translating" REMOTE_USER
var to the second arg, using <> as separator. Nice trick!!!!!!

Anyway, I've fixed a bit by adding a slash character after REMOTE USER like
this:
RewriteCond %{REMOTE_USER}/<>$1 !^([^<]+)<>\1
(in order to avoid the bypass of the rewrite when you have authenticated as
"user" and the intruder is hacking/building URLs as "userrrrrrr").

>>> RewriteRule ^/clientes/(.*) /stats/%{REMOTE_USER}/stats/http/$1 [L]
>> Why did you removed PT and used L?
> 
> PT has no special effect in per-directory context (rewrite rules used
> inside <directory>/<location> containers, .htaccess files etc.). In
> fact mod_rewrite will add passthrough: to the result of your
> substitution, stop the processing of following rules in that set and
> remove passthrough: later w/o doing sthg. special. L will only stop
> the rewrite of the current set. I.e. the result is the same.

I removed [L] (is it a good practice to keep it? if not, I don't see the
need to keep it) and added additional protection so the user could only
visit the desired (stats/http) directory (in order to avoid the user
including its own username in the url and reaching other directories in its
home).

My final solution is:

                RewriteBase /stats
                RewriteCond %{REMOTE_USER}/<>$1 !^([^<]+)<>\1
                RewriteRule ^/clientes/(.*) /stats/%{REMOTE_USER}/stats/http/$1

                RewriteCond $1 !^[^/]+/stats/http/
                RewriteRule ^/clientes/(.*) hacking_attempt [F]


The alternative (adding L) is:

                RewriteBase /stats
                RewriteCond %{REMOTE_USER}/<>$1 !^([^<]+)<>\1
                RewriteRule ^/clientes/(.*)
/stats/%{REMOTE_USER}/stats/http/$1 [L]

                RewriteCond $1 !^[^/]+/stats/http/
                RewriteRule ^/clientes/(.*) hacking_attempt [F,L]

But I see no real difference between both solutions. Am I right?

Cheers,
-Roman

---------------------------------------------------------------------
The official User-To-User support forum of the Apache HTTP Server Project.
See <URL:http://httpd.apache.org/userslist.html> for more info.
To unsubscribe, e-mail: users-unsubscribe@httpd.apache.org
   "   from the digest: users-digest-unsubscribe@httpd.apache.org
For additional commands, e-mail: users-help@httpd.apache.org


Re: [users@httpd] Mixing rewrite with authn_dbd: Rewriting based on path value stored in mysql table

Posted by Bob Ionescu <bo...@googlemail.com>.
2009/5/11 Roman Medina-Heigl Hernandez <ro...@rs-labs.com>:
> Bob Ionescu escribió:
>> 2009/3/2 Roman Medina-Heigl Hernandez <ro...@rs-labs.com>:
>>> The problem is that you cannot have %{REMOTE_USER} as 2nd parameters in
>>> RewriteCond, so I have no way for comparing it with $1
>>
>> -didn't read all-; but you can compare it with a regEx internal backreference.
>>
>> RewriteBase /stats
>> RewriteCond %{REMOTE_USER}<>$1 !^([^<]+)<>\1
>
> Could you explain that, please? I didn't know that syntax...

You're capturing a value with ^([^<]+), that is according to our test
string the value of %{REMOTE_USER} followed by the two characters <>
as a unique separator followed by the (previous) match of ([^<]+)
which matches against the value of $1.

E.g. if the remote_user is foo, the regEx will match against a test string of
foo<>foo

Just take a look at the manpage of PCRE, http://www.pcre.org/pcre.txt section
BACK REFERENCES
       Outside a character class, a backslash followed by a digit greater than

>> RewriteRule ^/clientes/(.*) /stats/%{REMOTE_USER}/stats/http/$1 [L]
>
> Why did you removed PT and used L?

PT has no special effect in per-directory context (rewrite rules used
inside <directory>/<location> containers, .htaccess files etc.). In
fact mod_rewrite will add passthrough: to the result of your
substitution, stop the processing of following rules in that set and
remove passthrough: later w/o doing sthg. special. L will only stop
the rewrite of the current set. I.e. the result is the same.

Bob

---------------------------------------------------------------------
The official User-To-User support forum of the Apache HTTP Server Project.
See <URL:http://httpd.apache.org/userslist.html> for more info.
To unsubscribe, e-mail: users-unsubscribe@httpd.apache.org
   "   from the digest: users-digest-unsubscribe@httpd.apache.org
For additional commands, e-mail: users-help@httpd.apache.org


Re: [users@httpd] Mixing rewrite with authn_dbd: Rewriting based on path value stored in mysql table

Posted by Roman Medina-Heigl Hernandez <ro...@rs-labs.com>.
Bob Ionescu escribió:
> 2009/3/2 Roman Medina-Heigl Hernandez <ro...@rs-labs.com>:
>> More comments:
>> - at the beginning I tried something like:
>>               RewriteBase /stats
>>               RewriteCond $1 !^%{REMOTE_USER}/
>>               RewriteRule ^/clientes/(.*)
>> /stats/%{REMOTE_USER}/stats/http/$1 [PT]
>>
>> The problem is that you cannot have %{REMOTE_USER} as 2nd parameters in
>> RewriteCond, so I have no way for comparing it with $1
> 
> -didn't read all-; but you can compare it with a regEx internal backreference.
> 
> RewriteBase /stats
> RewriteCond %{REMOTE_USER}<>$1 !^([^<]+)<>\1

Could you explain that, please? I didn't know that syntax...

> RewriteRule ^/clientes/(.*) /stats/%{REMOTE_USER}/stats/http/$1 [L]

Why did you removed PT and used L?

Wow!!!! I must say I'm frankly amazed, it seems it's working!! :-O  But I'd
like to understand it in depth. Please, Bob, could you explain the trick to
me? :)))))

Thank you!!!

-- 

Saludos,
-Roman

PGP Fingerprint:
09BB EFCD 21ED 4E79 25FB  29E1 E47F 8A7D EAD5 6742
[Key ID: 0xEAD56742. Available at KeyServ]

---------------------------------------------------------------------
The official User-To-User support forum of the Apache HTTP Server Project.
See <URL:http://httpd.apache.org/userslist.html> for more info.
To unsubscribe, e-mail: users-unsubscribe@httpd.apache.org
   "   from the digest: users-digest-unsubscribe@httpd.apache.org
For additional commands, e-mail: users-help@httpd.apache.org


Re: [users@httpd] Mixing rewrite with authn_dbd: Rewriting based on path value stored in mysql table

Posted by Bob Ionescu <bo...@googlemail.com>.
2009/3/2 Roman Medina-Heigl Hernandez <ro...@rs-labs.com>:
> More comments:
> - at the beginning I tried something like:
>               RewriteBase /stats
>               RewriteCond $1 !^%{REMOTE_USER}/
>               RewriteRule ^/clientes/(.*)
> /stats/%{REMOTE_USER}/stats/http/$1 [PT]
>
> The problem is that you cannot have %{REMOTE_USER} as 2nd parameters in
> RewriteCond, so I have no way for comparing it with $1

-didn't read all-; but you can compare it with a regEx internal backreference.

RewriteBase /stats
RewriteCond %{REMOTE_USER}<>$1 !^([^<]+)<>\1
RewriteRule ^/clientes/(.*) /stats/%{REMOTE_USER}/stats/http/$1 [L]


Bob

---------------------------------------------------------------------
The official User-To-User support forum of the Apache HTTP Server Project.
See <URL:http://httpd.apache.org/userslist.html> for more info.
To unsubscribe, e-mail: users-unsubscribe@httpd.apache.org
   "   from the digest: users-digest-unsubscribe@httpd.apache.org
For additional commands, e-mail: users-help@httpd.apache.org


Re: [users@httpd] Mixing rewrite with authn_dbd: Rewriting based on path value stored in mysql table

Posted by Roman Medina-Heigl Hernandez <ro...@rs-labs.com>.
Sorry for re-taking this thread... but I don't get to reach the right
solution... What I'd like to solve is the security problem stated below,
which could be exploited with something like:
https://XXX/stats/USER2/stats/http/YYYY

Since I'm comparing against:
!^/clientes/[^/]+/stats/http/
This would result in request not being rewritten at all, so authentication
would be easily bypassed with any existing user [user1, user2, user3, ...]
(when the desired behaviour should be only letting pass the one where "auth
user" == "user in url"). How could I enforce that?

Perhaps there's another (secure) way to mark the request as "rewritten", so
I could check later without the need to compare against
"!^/clientes/[^/]+/stats/http/".

Please, help! :-(

Cheers,
-r


Roman Medina-Heigl Hernandez escribió:
> Hello,
> 
> I have a *partial*-working solution which I'd like to share with you. It's
> tricky (based on my own home structure) and limited, though. Feedback is
> appreciated, please!
> 
> Some comments:
> - Debian 5.0 includes ajp 1.2.12, so I cannot get the url/dir from another
> column in users' table (this functionality is for ajp 1.3+). In my case, I
> can live without it, having the following convention: username will be a
> domainname (which has sense, since I want to offer stats pages for
> different domains). For instance, stats for domain "test.com" will use the
> username "test.com".
> - I've only experimented with per-dir rewrite (the non-recommended way...),
> which has the limitation of request reinjection (so you must include
> negative rewrite rules which protect you against loops). Perhaps it may be
> improved with server rewrite.
> - The current method is not secure: an attacker knowing the internal
> homedir structure could easily craft a request bypassing the rewrite
> ruleset, being able to access other domain/user's stats. It could also be
> used to access other directories/files of other users (in my case those
> dirs are protected using OS permissions).
> - Performance is not very efficient, since I'm reinjecting requests (it
> seems unavoidable if using per-dir rewrite).
> - Stats home for domain "test.com" will be:
> /clientes/test.com/stats/http/
> which should be accessed through:
> http://isp/stats/
> 
> 
> Current config is:
> ====
> 
>         Alias /stats /clientes
> 
>         <Location /stats/>
>                 # Basic Auth
>                 AuthType Basic
>                 AuthName "Stats"
>                 AuthBasicProvider dbd
> 
>                 Require valid-user
>                 AuthDBDUserPWQuery "SELECT pass FROM stats WHERE user = %s
> and enabled = 1"
> 
>                 # Rewrite para que cada user entre a su directorio de stats
> particular
>                 RewriteEngine on
>                 RewriteBase /stats
>                 RewriteRule !^/clientes/[^/]+/stats/http/ - [C]
>                 RewriteRule ^/clientes/(.*)
> /stats/%{REMOTE_USER}/stats/http/$1 [PT]
> 
> ====
> 
> More comments:
> - at the beginning I tried something like:
>                RewriteBase /stats
>                RewriteCond $1 !^%{REMOTE_USER}/
>                RewriteRule ^/clientes/(.*)
> /stats/%{REMOTE_USER}/stats/http/$1 [PT]
> 
> The problem is that you cannot have %{REMOTE_USER} as 2nd parameters in
> RewriteCond, so I have no way for comparing it with $1 (which coudn't be in
> 2nd parameter, either). Any idea to implement it? (i.e. test if REMOTE_USER
> string is included in URI path).
> 
> Cheers,
> -Roman
> 
> ---------------------------------------------------------------------
> The official User-To-User support forum of the Apache HTTP Server Project.
> See <URL:http://httpd.apache.org/userslist.html> for more info.
> To unsubscribe, e-mail: users-unsubscribe@httpd.apache.org
>    "   from the digest: users-digest-unsubscribe@httpd.apache.org
> For additional commands, e-mail: users-help@httpd.apache.org
> 


---------------------------------------------------------------------
The official User-To-User support forum of the Apache HTTP Server Project.
See <URL:http://httpd.apache.org/userslist.html> for more info.
To unsubscribe, e-mail: users-unsubscribe@httpd.apache.org
   "   from the digest: users-digest-unsubscribe@httpd.apache.org
For additional commands, e-mail: users-help@httpd.apache.org