3

我刚刚使用 Zend_Cache_Backend_Static 设置了静态页面缓存,以在我的应用程序中提供缓存的 html 文件,效果很好。我唯一担心的是它使用 $_GET 参数缓存文件的方式。因为它会自动创建一个映射到提供的 URL 路由的文件夹结构,所以在可能故意将大量 $_GET 参数附加到现有页面的情况下,这是否存在潜在的安全风险?达到最大目录深度还是最大文件长度?

例如:目前我正在缓存我的页面,/public/cache/static/因此使用标准路由器/module/controller/action/param1/val1/param2/val2或标准查询字符串/module/controller/action?param1=val1&param2=val2将创建以下目录结构:

/public/cache/static/module/controller/action/param1/val1/param2/val2.html 
/public/cache/static/module/controller/action?param1=val1&param2=val2.html

允许人们以这种方式(尽管有限)访问创建目录结构让我有点担心。Zend_Cache_Backend_Static 和相应的 Zend_Cache_Frontend_Capture 都必须在 ini 文件中设置,而不是通过 Zend_Cache 工厂,并且似乎没有任何设置选项。

是否只是用限制 $_GET 变量数量的自定义路由替换默认路由器的情况?这可能吗,还是我需要准确指定每条路线所需的变量(不是世界末日,而是更多限制)

更新:

所以现有的处理静态缓存的重写规则如下:

RewriteCond %{REQUEST_METHOD} GET
RewriteCond %{DOCUMENT_ROOT}/cached/index.html -f
RewriteRule ^/*$ cached/index.html [L]

RewriteCond %{REQUEST_METHOD} GET
RewriteCond %{DOCUMENT_ROOT}/cached/%{REQUEST_URI}\.html -f
RewriteRule .* cached/%{REQUEST_URI}\.html [L]

RewriteCond %{REQUEST_FILENAME} -s [OR]
RewriteCond %{REQUEST_FILENAME} -l [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^.*$ - [NC,L]

RewriteRule ^.*$ index.php [NC,L]

如果请求命中静态缓存中的页面,它将发送该 html 页面。如果不是,它将命中 Zend Framework 并生成它。

我可以在开头添加以下内容:

RewriteCond %{QUERY_STRING} \S
RewriteRule [^\?]+ /$0? [R=301,L]

这将完全擦除我的查询字符串。这很好,因为我仍然可以使用 Zend 框架的 URL 路径方法传递 $_GET 变量(我也通过提供非常明确的路由来限制它)。但是是否可以在不重定向的情况下做到这一点?

4

2 回答 2

1

理想的方法是将其定义为 RewriteCond,但我不确定是否可以使用 mod_rewrite 计算 GET 参数的数量。

因此,最好的解决方案可能是重定向到一个独立的 php 脚本,该脚本决定是否使用缓存的 html 文件。

<?php

if (count($_GET) >= 20) {
  require __DIR__ . 'index.php';
} else {
  require '/path/to/cache.html';
}
于 2012-02-18T17:10:19.410 回答
0

好的,因此剥离查询字符串的 RewriteRule 将在没有重定向的情况下工作。

问题(我怀疑)是 Zend_Cache_Backend_Static 在某处使用 $_SERVER['REQUEST_URI'] ,因此可以访问原始文件名。我对 mod_rewrite 的了解非常少,我没有意识到这个值没有改变。

因此,为了防止大量查询字符串创建文件和目录,我必须执行以下操作:

首先对于标准查询字符串:

在我的 mod_rewrite 开始时剥离查询字符串,而不进行重定向:

RewriteCond %{QUERY_STRING} \S
RewriteRule [^\?]+ /$0?

然后在我的 index.php 中,我通过剥离查询字符串来更改 $_SERVER['REQUEST_URI'] 以匹配重定向,这意味着我不再需要破解 ZF:

$queryIndex = strpos($_SERVER['REQUEST_URI'], '?');
if($queryIndex !== false) {
    $_SERVER['REQUEST_URI'] = substr($_SERVER['REQUEST_URI'], 0, $queryIndex);
}

现在,这将阻止我的应用程序解释任何查询字符串。因此,为了将变量传递给页面,我使用 Zend Framework url 路径参数。为了防止这些创建过深的缓存文件夹,我在 Bootstrap 中用一些非常明确定义的路由替换了默认路由:

$frontController = Zend_Controller_Front::getInstance(); 
$router = $frontController->getRouter();

$route = new Zend_Controller_Router_Route(
    ':module/:controller/:action',
    array(
        'module' => 'default',
        'controller' => 'index',
        'action' => 'index'
    )
);

$router->addRoute('default', $route);

$route = new Zend_Controller_Router_Route(
    'article/:alias',
    array(
        'module' => 'default',
        'controller' => 'article',
        'action' => 'index',
        'alias' => ''
    )
);

$router->addRoute('article', $route);

在这里,我已经替换了默认路由,因此不允许使用其他参数。因此,任何需要参数的操作都必须明确设置,例如在我的第二条路线中。这意味着可能有很多已定义的路线。值得庆幸的是,在我的特定应用程序中并非如此。

一种限制路由并允许通过 ZF URL 路径的一些 GET 参数的方法是对 REQUEST_URI 中的斜杠数量设置限制,从而有效地限制静态页面缓存的最大目录深度(下面的 10)。这也可以在 index.php 中更改:

if(substr_count($_SERVER['REQUEST_URI'], '/') > 10) {
    preg_match_all("/\//", $_SERVER['REQUEST_URI'] ,$capture, PREG_OFFSET_CAPTURE);
    $_SERVER['REQUEST_URI'] = substr($_SERVER['REQUEST_URI'], 0, $capture[0][9][1]);
}
于 2012-02-20T11:44:26.177 回答