防止缓存溢出

时间:2011-05-31 10:47:27

标签: php

目前我正在开发一个缓存动态创建文件的系统,那里没什么新东西。基本上它是如何工作的,它将通过$ _GET数组,并将基于查询字符串变量创建一个目录结构。当然,它比这更安全,但你得到的图片。

问题在于任何人都可以冲浪,例如:

  

www.example.com/?page=foo&page2=bar(会生成/cachefiles/foo/bar.html)

每次随机更改page2值,从而创建一个新的缓存文件。 因此,有人可以使用随机查询字符串生成10000个请求,并且会为每个请求生成新的缓存文件。

另一个问题是我实际上想要以某种方式允许这种情况,因为它将成为CMS的一部分,人们应该能够编写插件并因此使用他们自己的查询字符串变量。由于查询字符串通常对页面内容至关重要,因此应该有一个新的chachefile用于不同的查询字符串。

所以基本上我想在这种情况下允许使用查询字符串,但要防止滥用它们。

对我来说,拥有一个而不是另一个听起来是不可能的,但是因为我不是大师,所以我希望你们中的一些人可以分享你对此的看法,并对最佳做法(和/或替代方法)抱怨

我知道那里有一些缓存库,但我更喜欢自己做事,所以我理解发生了什么以及它是如何工作的。

编辑:感谢您的回复。我想我会尝试将你的一些建议合并到一个系统中。所以我将为插件开发人员添加功能,将他们的查询字符串变量注册到API中,以及进行更深入的检查。但是,请考虑以下情况:

用户请求静态页面,但在其模板中加载了插件日历:例如。 example.com/?page1=static&calenderStartmonth=5 以下是问题的根源:calendarStartMonth可以是12中的一个,并且需要能够更改,因此每次calendarStartMonth更改时都需要重新进行缓存。如果插件开发人员没有检查输入,并且有人使用随机nr进行10000次请求,那么会溢出缓存,不是吗?当然我意识到每次calenderMonth改变时再次缓存页面都不是很有效,这就是为什么我要求一些最佳实践建议。我是否必须想出一个除了插件之外的所有系统?再次感谢您的回答。

4 个答案:

答案 0 :(得分:1)

要防止滥用,您需要在启动缓存引擎之前添加额外的检查。

检查$_GET keys and values的内容以及如果某些内容不佳,则会打印die('Error');

您可以使用array_intersect_key检查$_GET密钥是否只是允许的。

另外,我建议您不要根据$ _GET参数创建文件夹。

您应该设置缓存的基础目录,例如/var/www/myCache/,然后使用

创建缓存文件
$cacheBaseDir .= sha1($_SERVER['REQUEST_URI']);

这就是我在CMS中实际做的事情。

当然,如果您担心只有一个目录中有太多文件缓存,这可能会扩展此行为(这可能会导致旧机器出现性能问题)

您实际上可以根据sha1();

的第一个字符传播缓存文件

所以你会做类似的事情:

$hash = sha1($_SERVER['REQUEST_URI']);    
$finalCacheDir = $cacheBaseDir . substr($hash,0,2) . '/' . $hash;

这样,您的缓存文件将在约256个子目录上传播。

答案 1 :(得分:0)

在提供页面之前检查页面,如果它不存在,请执行与此类似的操作:

if (!$page_exists) {
   header('HTTP/1.0 404 Not Found');
   die("<h1>404 Not Found</h1>\nThe page that you have requested could not be found.");
}

答案 2 :(得分:0)

我建议您编写一些小API,让CMS和插件开发人员在他们要创建的数据库中注册页面(读取:允许)。

通过这种方式,您还可以解决缓存刷新问题,因为您确实知道要删除的内容以及何时删除。

答案 3 :(得分:0)

您可以在参数之间创建哈希值,并将其附加到查询字符串。如果传递的参数与您的查询字符串匹配,则仅缓存页面。

e.g。

$vars= array('hello'=>'world','second'=>'value');
$vars['hash'] = md5('MySecret' . serialize($vars));

foreach($vars as $k=>$v){
    $out[] = $k .'='. $v;
}

$link = 'index.php?' . implode('&amp;',$out);

在接收方:

$vars = $_GET;
$hashUrl = $vars['hash'];
unset($vars['hash']);

if(md5('MySecret' . serialize($vars)) == $hashUrl){
    // cache the page and proceed
}else{
    // someone fiddled with the parameters
}

(这显然不能成为您以不同方式检查价值的原因。)