Apache: Environment Variables Visibility with SetEnv, SetEnvIf and RewriteRule Directives

Scenario

One of those moments again where the search engine did not turn up information which I need. So I hope this article will be helpful to someone out there.

It seems that environment variables in Apache are not being treated equally when SetEnv, SetEnvIf and RewriteRule directives are used. In my case, I want to limit access based on query string but SetEnvIf does not have that attribute to test against. RewriteRule creates an environment variable that is not accessible by Allow/Deny directive (Possibly because Allow/Deny are evaluated before RewriteRule). It makes things complicated when you are going to use environment variables to limit access but it does not work as expected.

Unfortunately, I do not have a solution for you but I hope this information will save you countless hours researching a solution that never exists. But if you do have one, please let me know as I would love to hear from you.

.htaccess Test Configuration

You can skip this part actually. But if you are interested in how the test is done, you can continue reading.

RewriteEngine On

# Putting Header before setting the environment variables do not seem to matter.
Header always add A_1 "%{A_1}e"
Header always add B_1 "%{B_1}e"
Header always add C_1 "%{C_1}e"
Header always add U_1 "%{U_1}e"

Header always add A_2 "%{A_2}e"
Header always add B_2 "%{B_2}e"
Header always add C_2 "%{C_2}e"
Header always add U_2 "%{U_2}e"

Header always add A_3 "%{A_3}e"
Header always add B_3 "%{B_3}e"
Header always add C_3 "%{C_3}e"
Header always add U_3 "%{U_3}e"

Header always add A_4 "%{A_4}e"
Header always add B_4 "%{B_4}e"
Header always add C_4 "%{C_4}e"
Header always add U_4 "%{U_4}e"

Header always add A_5 "%{A_5}e"
Header always add B_5 "%{B_5}e"
Header always add C_5 "%{C_5}e"
Header always add U_5 "%{U_5}e"
Header always add S_5 "%{S_5}e"

# Test to see if (1) Header can access the environment variables.
SetEnv A_1 SetEnv_Works
SetEnvIf always_match ^ B_1=SetEnvIf_Works
RewriteRule .* - [E=C_1:RewriteRule_Works,NE]
# U_1 is not set deliberately.

# Test to see if (2) SetEnvIf can access the environment variables.
SetEnvIf A_1 ^(.*)$ A_2="$1"
SetEnvIf B_1 ^(.*)$ B_2="$1"
SetEnvIf C_1 ^(.*)$ C_2="$1"
SetEnvIf U_1 ^(.*)$ U_2="$1"

# Test to see if (3) RewriteCond can access the environment variables.
RewriteCond %{ENV:A_1} ^(.*)$
RewriteRule .* - [E=A_3:"%1",NE]
RewriteCond %{ENV:B_1} ^(.*)$
RewriteRule .* - [E=B_3:"%1",NE]
RewriteCond %{ENV:C_1} ^(.*)$
RewriteRule .* - [E=C_3:"%1",NE]
RewriteCond %{ENV:U_1} ^(.*)$
RewriteRule .* - [E=U_3:"%1",NE]

# Test to see if (4) RewriteRule can access the environment variables.
RewriteRule .* - [E=A_4:"%{ENV:A_1}",NE]
RewriteRule .* - [E=B_4:"%{ENV:B_1}",NE]
RewriteRule .* - [E=C_4:"%{ENV:C_1}",NE]
RewriteRule .* - [E=U_4:"%{ENV:U_1}",NE]

# Test to see if (5) <IfDefine> can access the environment variables.
<IfDefine A_1>
    SetEnv A_5 Can_Access
</IfDefine>
<IfDefine B_1>
    SetEnv B_5 Can_Access
</IfDefine>
<IfDefine C_1>
    SetEnv C_5 Can_Access
</IfDefine>
<IfDefine U_1>
    SetEnv U_5 Can_Access
</IfDefine>
SetEnv S_5 Unconditionally_Set

# Test to see if (6) Allow/Deny can access the environment variables.
Options +Indexes
Order Deny,Allow
Deny from all
# To test, only one should be uncommented at any point in time.
#Allow from env=A_1
#Allow from env=B_1
#Allow from env=C_1
#Allow from env=U_1
Allow from all    # Required for (3) RewriteCond and (4) RewriteRule test to work properly.

Test Result

A_1	SetEnv_Works
B_1	SetEnvIf_Works
C_1	RewriteRule_Works
U_1	(null)
A_2	""
B_2	"SetEnvIf_Works"
C_2	""
U_2	""
A_3	""
B_3	"SetEnvIf_Works"
C_3	"RewriteRule_Works"
U_3	""
A_4	""
B_4	"SetEnvIf_Works"
C_4	"RewriteRule_Works"
U_4	""
A_5	(null)
B_5	(null)
C_5	(null)
U_5	(null)
S_5	Unconditionally_Set

Summary

Set Using (U)
Unset
Variable
(A)
SetEnv
(B)
SetEnvIf
(C)
RewriteRule
Accessible By (1) Header Yes Yes Yes (null)
(2) SetEnvIf No Yes No -
(3) RewriteCond* No Yes Yes -
(4) RewriteRule* No Yes Yes -
(5) <IfDefine> No No No No
(6) Allow/Deny
No Yes No -

*Will not work if “Deny from all” is in effect.

Excellent References:
http://httpd.apache.org/docs/2.2/env.html

About these ads

10 Comments »

  1. Steven said

    Wow, thanks for this! I was trying to do some advanced variable setting and rewriting and this was extremely useful.

  2. Vector said

    Hey, i feel your pain on this one. I was about to shoot someone until i finally got this working. And you’re right: there’s NO fcking docs on how to PROPERLY do this. So it’s trial and error, and time wasted.

    Anyway, i DID find a working example, while trying to setup apache to handle mobile redirects for TheSocialExpo.com and i posted an article about it here:

    http://thesocialexpo.com/?a=WCMS_Article_Display&id=13001842310325634&page=1

    I came across you while i was trying to solve this problem, so i figured i’d come back and share my findings as well.

    • turboflash said

      Thanks for the information. :)

    • Do you have a copy of that page? It is offline now :( Would like to find a fix for this…

  3. Christian said

    Thanks for this! very useful, exactly what I was looking for.

  4. This was wonderfully useful. It saved me hours. Thanks so much. I’ve brought it to the webfaction community here: http://community.webfaction.com/questions/8694/using-rewritecond-to-simulate-rewritebase-for-hosting-same-app-at-root-and-subdirectory

  5. Alex said

    May be I didn’t get something, but official documentation IMHO clearly explain it.

    http://httpd.apache.org/docs/2.2/mod/core.html#ifdefine

    “Encloses directives that will be processed only if a test is true >>>at startup<<>>after<<>>If the environment variable you’re setting is meant as input into this early phase of processing such as the RewriteRule directive, you should instead set the environment variable with SetEnvIf.<<<"

  6. Alex said

    May be I didn’t get something, but official documentation IMHO clearly explain it.

    http://httpd.apache.org/docs/2.2/mod/core.html#ifdefine

    “Encloses directives that will be processed only if a test is true +++at startup+++”
    It means any existing system env.vars will be available for IFDefine.
    One more way to pass environment variable on start to Apache only instead of setting it system wide it is place file(s) to directory
    etc/apache22/envvars.d in the same way as it done in standard Burne shell


    #-------------- comments about var ....
    MySpecialSuperDuperIP='11\.22\.33\.44'
    export MySpecialSuperDuperIP
    #=========================

    that “MySpecialSuperDuperIP” will be available later for all tests

    As of “setenv”:

    http://httpd.apache.org/docs/2.2/mod/mod_env.html#setenv

    “The internal environment variables set by this directive are set +++after+++ most early request processing directives are run, such as access control and URI-to-filename mapping. +++If the environment variable you’re setting is meant as input into this early phase of processing such as the RewriteRule directive, you should instead set the environment variable with SetEnvIf.+++”

    P.S.
    Sorry for previous post, forget that wordpress don’t like some characters

  7. […] 首先想到的是通过访问控制模块mod_authz_host的Deny from env来实现。Deny from能够访问的只有SetEnvIf设置的环境变量。有个老外做了个有趣的实验汇总了Apache 2.2下环境变量相关的各个指令(SetEnv/SetEnvIf/RewriteRule/Header/RewriteCond/IfDefine/Allow/Deny)设置/访问的作用范围,有兴趣的可以看看,需要翻墙,Apache: Environment Variables Visibility with SetEnv, SetEnvIf and RewriteRule Directives,翻不了墙的可以直接看这张表。 […]

  8. Cosimo said

    Great post. Thanks for it.

RSS feed for comments on this post · TrackBack URI

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.

%d bloggers like this: