Apache的环境变量
Apache HTTP服务器提供了一个机制,可以把信息存储在叫做环境变量(environment variable)的命名变量中。这个信息可以用于控制诸如日志记录和访问控制之类的操作。此外,还可以作为一个和诸如CGI脚本这样的外部程序进行沟通的机制。本文档讨论了操作和使用这些变量的不同方法。
尽管这些变量也被称作环境变量,但它们和底层的、由操作系统控制的环境变量不能混为一谈。这些变量仅在Apache内部被存储和操纵。仅当它们被提供给外部CGI脚本或服务器端包含脚本(SSI)时,才会变成真正的操作系统环境变量。如果你想操作作为服务器运行基础的操作系统的环境变量,你必须使用由你的操作系统shell提供的标准环境操作机制。
设置环境变量
相关模块 | 相关指令 |
---|---|
基本的环境变量操作
设置一个Apache环境变量最基本的方法,就是使用没有什么限制的SetEnv
指令。也可以使用PassEnv
指令将启动Apache的操作系统shell的环境变量传进来。
针对每个请求进行有条件的设定
为了具有额外的伸缩性,mod_setenvif
提供的指令允许针对每个请求特定的请求特性进行环境变量的设定。比如,可以仅在一个特定的浏览器(User-Agent)进行请求时,或仅在一个特定的"Referer:"头被发现时进行环境变量的设置。如果使用mod_rewrite
的RewriteRule
指令中的 [E=...]
选项来进行环境变量的设置,还会具有更大伸缩性。
唯一标识符
最后,mod_unique_id
将为每个请求设定一个UNIQUE_ID
环境变量的值,这个值对"所有"请求都是唯一的,即使在极为特定的条件下。
标准CGI变量
除了所有Apache配置中的环境变量和由操作系统shell传进来的环境变量之外,还有一组环境变量是提供给CGI脚本和SSI页面的,此组环境变量包含由CGI规范要求的与请求相关的元信息。
一些告诫
- 用环境变量操作指令来覆盖或修改标准的CGI变量是行不通的。
- 当用
suexec
来运行CGI脚本时,环境变量将会被清除到在CGI脚本运行之前只剩一组安全变量。安全变量的列表在编译时由suexec.c定义。 - 出于可移植性的考虑,环境变量的命名必须仅包含字母、数字、下划线。此外,第一个符号不能为数字。不符合此要求的字符将在传递给CGI脚本和SSI页面时被下划线取代。
- 由于
SetEnv
指令在请求处理的后期才运行,所以诸如SetEnvIf
和RewriteCond
之类的指令将看不到SetEnv
指令设置的变量。
使用环境变量
相关模块 | 相关指令 |
---|---|
CGI脚本
环境变量的主要用途之一就是把信息传递给CGI脚本。如前所述,递给CGI脚本的环境变量,除了在Apache配置中定义的以外,还包含一组与请求相关的标准元信息的环境变量。更多细节请参见CGI教程。
SSI页面
由mod_include的INCLUDES
过滤器处理的服务器端解析(Server-parsed[SSI])文档能够用echo
元素打印出环境变量,并能在流程控制元素中使用环境变量来基于请求特性而产生部分页面。Apache当然也会将上述的标准CGI环境变量提供给SSI页面。更多细节请参见SSI教程。
访问控制
可以用 allow from env=
和 deny from env=
指令基于环境变量的值对服务器进行访问控制。在结合了SetEnvIf
之后,能更灵活的基于客户端特性对服务器进行访问控制。比如,你能用这些指令来拒绝一些特定浏览器(User-Agent)的访问。
条件日志记录
可以用LogFormat
的可选项"%e
"将环境变量写入访问日志中。此外,还可以用CustomLog
指令基于环境变量的状态来决定是否将请求写入日志。在结合了SetEnvIf
之后,能更灵活的控制哪些请求将被记录。比如,你可以选择不对以gif
为结尾的文件名请求进行记录,或者选择只记录内网之外的客户端请求。
条件响应头
Header
指令能根据一个环境变量是否存在来决定是否将一个HTTP头放入对客户端的响应里。这将使诸如从客户端收到特定的请求头时返回特定的应答头这样的事情成为可能。
外部过滤器的激活
由mod_ext_filter
的ExtFilterDefine
指令配置的外部过滤器可以用 disableenv=
和 enableenv=
选项根据环境变量的条件进行激活。
URL重写
RewriteCond
中形如 %{ENV:...}
的TestString允许mod_rewrite的重写引擎以环境变量为条件进行决策。注意:mod_rewrite内部可以访问但没有以 ENV:
开头的那些变量并不是真正的环境变量。它们只是mod_rewrite特有的变量而不能被其他模块所访问。
用于特殊目的的环境变量
由于互操作性的问题,在针对特定客户端的处理中,引入了一套修正Apache行为的机制。为了使这些机制尽量灵活,它们将通过环境变量的定义而激活。比如,典型的示例有BrowserMatch
,尽管SetEnv
和PassEnv
也能使用。
downgrade-1.0
即使这个请求符合更新的标准,也强制把它当作一个HTTP/1.0请求来处理。
force-gzip
如果你激活了DEFLATE
过滤器,这个环境变量将忽略浏览器的accept-encoding设置而无条件的使用经过gzip压缩的输出。
force-no-vary
此变量在将应答送回客户端之前删除所有的Vary
头字段。一些客户端不能正确地解析此头字段。此变量的设定将解决此问题,它同时隐含设置了force-response-1.0。
force-response-1.0
设定该变量可以在客户端发送HTTP/1.0请求时,强制进行HTTP/1.0响应。它的实现源于一个AOL的代理产生的问题。一些HTTP/1.0客户端在收到HTTP/1.1的响应后会有不正常的举动。而设定此变量能够解决这一问题。
gzip-only-text/html
当该变量为"1"时,将禁止text/html
之外的内容类型使用由mod_deflate
提供的DEFLATE
输出过滤器。如果你更喜欢使用静态的压缩文件;mod_negotiation
也同样使用该变量(不单单是gzip,而是所有不具有"同一性"的编码)。
no-gzip
如果设置了此变量,mod_deflate
中的DEFLATE
过滤器将被禁用,同时mod_negotiation
将拒绝发送经过编码的资源。
nokeepalive
如果设置了此变量,KeepAlive
将被禁用。
prefer-language
此变量将影响mod_negotiation
的行为。如果它包含一个语言标签(如:en
、fr
、zh_cn
、x-方言
),mod_negotiation
将尝试发送一个标签指定的语言的变种,如果不存在这样的变种,则使用通常的内容协商处理过程。
redirect-carefully
此变量将使服务器在对客户端发送重定向命令时更加小心。典型应用于已知客户端在处理重定向指令时会存在问题的情况下。它的实现源于微软的WebFolders软件存在的一个问题。它在经由DAV方法在目录资源上处理重定向命令时会有问题。
suppress-error-charset
仅存在于2.0.54后的版本中
当Apache针对用户请求响应一个重定向命令的时候,这个响应中包含了一些文字。这些文字将在客户端不能(或没有)自动执行重定向操作的情况下显示。Apache会将这段文字按照ISO-8859-1字符集进行编码。
然而,如果重定向的目的页面使用了不同的字符集,一些有问题的浏览器版本会使用重定向命令文本的字符集,而不是采用目的页面的字符集。比如,希腊文就不会被正确显示。
设置此环境变量将使Apache略过重定向命令文本的字符集设置,这样这些有问题的浏览器就会正确的使用目的页的字符集。
安全提示
发送未指定字符编码的错误页面可能会在某些不严格遵守HTTP/1.1规范的浏览器(MSIE)上导致跨站脚本攻击,因为这些浏览器会企图"猜测"正确的编码。在使用UTF-7字符集的时候,这些浏览器就很容易被愚弄:UTF-7格式的输入数据不会被正确转义,而这些转义原本的目的就是为了防止跨站脚本攻击。
force-proxy-request-1.0, proxy-nokeepalive, proxy-sendchunked, proxy-sendcl
这些指令改变了mod_proxy
协议的行为,参见mod_proxy
文档以获得更多细节。
示例
针对表现不恰当的客户端改变协议的行为
早期的版本建议将以下示例包含到httpd.conf中以解决一些已知的客户端问题。但是这些存在问题的客户端现在基本上已经绝种了,所以,下列示例也就没有存在的必要了。
# 下面的指令将会修改HTTP的普通响应方式。 # 第一个指令为Netscape 2.x浏览器禁用keepalive特性,因为它不能正确处理。 # 第二个指令用于IE4.0,因为它也不能对HTTP/1.1的301/302(重定向)应答正确处理keepalive。 BrowserMatch "Mozilla/2" nokeepalive BrowserMatch "MSIE 4\.0b2;" nokeepalive downgrade-1.0 force-response-1.0 # 下面的指令为违反HTTP/1.0规范的浏览器禁用HTTP/1.1应答。 BrowserMatch "RealPlayer 4\.0" force-response-1.0 BrowserMatch "Java/1\.0" force-response-1.0 BrowserMatch "JDK/1\.0" force-response-1.0
不在访问日志中记录对图片的请求
以下示例将避免将对图片的请求记入访问日志中。你修改一下就可以将它用于避免特定目录或特定主机的请求被记入日志。
SetEnvIf Request_URI \.gif image-request SetEnvIf Request_URI \.jpg image-request SetEnvIf Request_URI \.png image-request CustomLog logs/access_log common env=!image-request
阻止"图片大盗"
下例展示了如何避免不在你服务器上的人在他们的站点中直接引用你服务器上的图片。这不是一个推荐的配置,但它能在有限的环境中加以应用。我们假设你所有的图片都在/web/images目录下。
SetEnvIf Referer "^http://www\.example\.com/" local_referal # 允许未发送Referer头的浏览器 SetEnvIf Referer "^$" local_referal <Directory /web/images> Order Deny,Allow Deny from all Allow from env=local_referal </Directory>
想得知此技术的更多信息,请参阅"今日Apache教程" 《保护你的图片不为他人所用》。