友声网

 找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
开启左侧

Apache服务器的内容缓存

[复制链接]
admin 发表于 2017-12-22 08:27 | 显示全部楼层 |阅读模式
Apache2.2起有两个缓存模块被正式使用:mod_cache和mod_file_cache。这些缓冲体系提供了一个强有力的途径来加速原始web服务器(origin webserver)和代理服务器(proxy)的HTTP处理速度。官方手册的说明

mod_cache与mod_file_cache的区别:

mod_cache缓存的实现,要依靠两个模块mod_mem_cache和mod_disk_cache,他们提供了智能的HTTP缓冲。内容(content)本身被存储在缓冲区中,mod_cache的目的在于管理控制内容缓冲能力的各种HTTP头和选项。它可以同时处理本地的内容和代理的内容。mod_cache被设计为同时针对简单的和复杂的缓冲配置,以用于处理代理的内容、动态的本地内容、必须加速访问的随时间而改变本地文件。阅读开启mod_cache模块方法。
mod_file_cache实现了一个更基本的、但是在某些情况下更有效的缓冲形式,它避免了主动确保URL缓冲能力所需的维护复杂性,mod_file_cache通过提供文件句柄(file-handle)和内存映射(memory-mapping)的技巧来维持一个自Apache最后一次启动以来的文件缓冲区。同样地,mod_file_cache的目标是改善不常修改的本地静态文件的访问时间。由于mod_file_cache提供了一个相对简单的缓冲实现。
除了CacheFile和MMapStatic文档的特定段落之外,这篇指南的说明覆盖了mod_cache的缓存体系结构为了更好的理解这篇文档,你应当熟悉HTTP的基础知识,并且已经阅读过从URL到文件系统的映射和内容协商这两篇用户指南。

缓冲概述
相关模块       
mod_cache
mod_mem_cache
mod_disk_cache
mod_file_cache

相关指令
CacheEnable
CacheDisable
MMapStatic
CacheFile
CacheFile
UseCanonicalName
CacheNegotiatedDocs

在一个请求的生存期中,mod_cache将是一个URL映射模块,mod_cache内可能会发生两个主要阶段。

如果一个URL已经被缓存并且这个缓存尚未失效,该请求将由mod_cache直接处理。这也意味着在处理一个请求时通常还要发生的其他阶段:比如由mod_proxy或mod_rewrite处理的阶段。mod_cache直接处理的请求,一个请求期间的其他阶段将不会发生。这正是将内容缓存起来的关键所在。(某些阶段被省略了,这正是启用缓冲特性的初衷:减少处理步骤以提高速度。)

如果该URL存在于缓存中并且已经失效的话,mod_cache将会在请求的处理过程中添加一个过滤器,mod_cache将会同时向后端(backend)提交一个条件请求以确定缓存的版本是否是当前的最新版本。如果是最新版本,那么它的元信息(meta-information)将会被更新并且使用这个缓存的版本来服务于该请求。如果不是最新版本,那么过滤器将使用刚才为请求提供服务的最新内容更新缓存。

如果这个URL不在缓存中,mod_cache将会在请求的处理过程中添加一个过滤器。在Apache使用通常的方法定位内容之后,该过滤器将会在内容被用于服务以后运行。如果该内容被确定为可以缓存,那么它将被保存在缓冲区中以便为将来的请求提供服务。

提高缓存命中率

在缓存本地生成的内容的时候,将UseCanonicalName指令设置为 On 可以显著提高缓存的命中率。这是由于为缓冲区提供内容的虚拟主机的主机名是缓冲键(cache key)的组成部分。当该指令设置为 On 时,具有多个服务器名或别名的虚拟主机将不会产生不同的缓存实体,而是按照各自的规范主机名(canonical hostname)来存储。

由于缓存发生在将URL映射到文件系统的阶段,缓存的文档将只被用来响应对URL的请求。通常情况下这没什么重大意义,但是当你使用服务端包含(Server Side Includes)时,这一点将显得特别重要:

<!-- 下面的包含可以被缓存 -->
<!--#include virtual="/footer.html" -->
<!-- 下面的包含不可以被缓存 -->
<!--#include file="/path/to/footer.html" -->
如果你使用服务端包含(SSI),并且希望从缓冲中获得快速服务好处,你应当使用virtual类型的包含。

失效周期(Expiry Periods)

缓存实体的默认失效周期是一个小时(3600秒),当然这个可以轻易的通过CacheDefaultExpire指令来修改。这个默认值仅仅用在产生内容的原始资源没有明确指定失效时间或最后修改时间的情况下。

如果一个应答没有包含Expires头但却包含Last-Modified头时,mod_cache可以根据CacheLastModifiedFactor指令推断出失效周期。

对于本地内容,mod_expires可以用来调整失效周期。

失效周期的最大值还可以通过CacheMaxExpire指令来控制。

关于条件请求(Conditional Request)的简短说明

当缓存的内容失效并且被从后端(backend)或内容提供者(content provider)那里重新请求的时候,Apache并不直接传递原始的请求,而是使用一个条件请求(conditional request)。

HTTP协议使用的一些头(header)允许客户端或缓冲区鉴别同一个内容的不同版本。例如,如果一个资源应答了"Etag:"头,那么就可以生成一个包含"If-Match:"头的条件请求;如果一个资源应答了"Last-Modified:"头,那么就可以生成一个包含"If-Modified-Since:"头的条件请求;等等。

对于这样的条件请求,应答的不同取决于内容是否匹配这些条件。如果一个请求包含一个"If-Modified-Since:"头,而请求的内容在指定的时间之后并未发生改变,那么一个简洁的"304 Not Modified"应答就可以了。

如果请求的内容已经变化,那么将按照原来没有条件请求的普通方式来应答。

和缓存相关的条件请求的好处有两个方面。首先,当向后端提交这样的条件请求时,如果从后端获得的内容与存储的内容相匹配(这很容易确定),就可以避免由于传递全部资源所带来的开销。

其次,条件请求通常只让后端花费较小的开销。对于静态文件,通常所有的开销就是一个stat()或类似的系统调用以确定改文件的大小是否变化以及最后修改时间。这样,如果被请求的内容尚未变化,甚至在Apache缓存的本地内容已经失效的情况下,仍然可以从缓冲区中快速取得以服务于请求——只要从缓冲区读取比从后端读取更快(例如从内存缓冲区读取就比从硬盘上读取更快)。

什么可以被缓存?

如前所述,Apache中的缓冲存在两种不同工作方式。mod_file_cache的缓冲区负责维护Apache启动时的文件内容。当一个存在于该模块缓冲区中的文件被请求时,该请求将被拦截并用缓冲区中的内容为其提供服务。

mod_cache的缓冲区相对而言较为复杂。当服务于一个请求时,如果它先前并未被缓存,则缓冲模块将会判断该内容是否可以被缓存。判断应答的缓冲能力(cachability)基于以下条件:

必须为该URL启用了缓冲。请参考CacheEnable和CacheDisable指令。
应答必须具有如下HTTP状态码:200, 203, 300, 301, 410 。
该请求必须是一个HTTP GET请求。
如果请求包含"Authorization:"头,则应答不被缓存。
如果应答包含"Authorization:"头,它必须同时也在"Cache-Control:"头中包含"s-maxage"、"must-reva lidate"或"public"选项。
如果该URL包含一个请求字符串(比如来自于一个使用GET方法的HTML表格),除非应答包含"Expires:"头,否则将不被缓存。这是基于RFC2616的13.9小节的规范。
如果应答的状态码是200(OK),除非明确打开了CacheIgnoreNoLastMod指令,否则该应答还必须至少包含一个"Etag"、"Last-Modified"或"Expires"头才能被缓存。
如果应答头"Cache-Control:"中包含"private"选项,除非明确打开了CacheStorePrivate指令,否则将不被缓存。
同样,如果应答头"Cache-Control:"中包含"no-store"选项,除非明确打开了CacheStoreNoStore指令,否则将不被缓存。
如果应答包含"Vary:"头,并且其中包含通配符"*"(匹配所有),也将不被缓存。
什么不应该被缓存?

简而言之,随时间变化的内容不应该被缓存;取决于特定请求的内容不应该被缓存;依赖于不被HTTP内容协商处理的请求的内容也不应该被缓存。[本句翻译的很没把握,原文:In short, any content which is highly time-sensitive, or which varies depending on the particulars of the request that are not covered by HTTP negotiation, should not be cached.]

如果你有某些动态内容,它们的变化依赖于请求发起者的IP地址或者差不多每5分钟就会发生改变,那么这些内容毫无疑问是不应该被缓存的。

另一方面,如果内容的变化依赖于各种HTTP头,更加明智的做法可能是通过使用"Vary"头进行缓存。

易变的/协商的内容

当mod_cache接收到一个后端发出的、带有"Vary"头的应答的时候,它将尽可能智能的处理它。如果有机会,mod_cache将会检查之后进入的请求的"Vary"头属性,然后用正确的缓冲区内容为这个请求提供服务。

举个例子来说,接收到一个带有如下"Vary"头的应答:

Vary: negotiate,accept-language,accept-charset

mod_cache将只会使用与原始请求的accept-language和accept-charset头匹配的缓存内容来提供服务。

安全方面的考虑

授权(Authorisation),访问控制(Access & Control)

mod_cache非常像一个内置的反向代理(reverse-proxy)。除非必须要向后端提交请求,否则缓冲模块将直接为请求提供服务。对于缓冲本地资源,这种模式彻底改变了Apache的安全模型。

因为遍历文件系统的目录结构以寻找可能存在的.htaccess文件是一个开销非常昂贵的操作,它部分地抵消了缓冲所带来的好处(加速请求),所以mod_cache并不检查缓存中的实体是否被允许(authorised)用于提供服务。换句话说,只要mod_cache中缓存的内容尚未失效,那么它们将被直接用于为请求提供服务。

举例来说,如果你为某个资源按照IP地址配置了访问许可,你必须要确保这些内容不被缓存。你可以使用CacheDisable指令或mod_expires模块达到这个目的。不做权限检查的mod_cache模块非常像一个反向代理:缓存内容并用缓存的内容向任意IP地址上的任意客户提供服务。

本地利用(Local exploits)

因为终端用户的请求可以由缓冲区直接提供服务,所以缓冲区自身便成为一个那些企图干扰、破坏内容的攻击者的攻击目标。很重要的、需要牢记的一点是:缓冲区必须始终对运行Apache的用户是可写的。这正好与通常的原则:始终保持所有内容对运行Apache的用户不可写,完全相反!

如果运行Apache的用户是潜在的不安全用户,比如,通过一个有漏洞的CGI进程,就有可能对缓冲区发起攻击,当使用mod_disk_cache的时候,就很容易插入或者修改缓冲区中内容。

这样一来,运行Apache的用户就会增加一个与其它类型的攻击相比更加危险的安全隐患。如果你正在使用mod_disk_cache ,你必须时刻牢记:确保为Apache及时打上所有的安全补丁并且使用suEXEC以一个不同于运行Apache用户的其他用户身份运行CGI进程。

缓存中毒(Cache Poisoning)

当将Apache作为一个缓冲代理服务器运行的时候,将可能存在一个所谓"缓存中毒"的问题。"缓存中毒"是一个泛称术语,用于指代各种造成代理服务器从后台检索到错误内容的攻击。

举个例子来说,如果你运行Apache的系统所使用的DNS服务器发生了DNS缓存中毒,攻击者将可能欺骗Apache连接到一个错误的服务器去请求内容。另一个例子是所谓的HTTP请求走私(request-smuggling)攻击。

这篇文档并不是深入探讨HTTP请求走私的地方(你应当去问google),但有一点你必须知道:攻击者可以通过制造一连串的请求并利用原始web服务器的漏洞,达到完全控制代理服务器所检索到的内容的目的。

RSS|无图版|手机版|友声网 ( 鲁ICP备15020090号-1 )|网站地图 | 点击这里给我发消息 |

GMT+8, 2024-4-18 13:23 , Processed in 0.024753 second(s), 8 queries , MemCache On.

Powered by Discuz! X

© ys166.com

快速回复 返回顶部 返回列表