Apache HttpClient 使用代理服务器 Proxy 的一个小坑

今天在调试一个用 HttpClient 写的 Demo 的时候遇到了一个问题:

org.apache.http.impl.execchain.RetryExec execute
INFO: I/O exception (org.apache.http.conn.UnsupportedSchemeException) caught when processing request to {tls}->http://proxyserver:port->https://servername:443: http protocol is not supported

也就是在通过 HTTP Proxy 进行 HTTPS 连接的时候,HttpClient 报了一个不支持 HTTP 协议。查了一下发现问题在于我使用 HttpClient 的方法。

由于我在使用 HttpClient 的时候是手动创建的 Registry ,而在创建的时候没有注册 HTTP 协议,导致报了上面那个错误。之前错误的代码是:

        // Create a registry of custom connection socket factories for supported
        // protocol schemes.
        Registry socketFactoryRegistry = RegistryBuilder.create()
                .register("https", sslsf)
                .build();

        // Create a connection manager with custom configuration.
        PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager(socketFactoryRegistry);

需要修改为:

        // Create a registry of custom connection socket factories for supported
        // protocol schemes.
        Registry socketFactoryRegistry = RegistryBuilder.create()
                .register("https", sslsf)
                .register("http", PlainConnectionSocketFactory.INSTANCE)
                .build();

        // Create a connection manager with custom configuration.
        PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager(socketFactoryRegistry);

加的这句保证了这个ConnectionSocketFactory 也可以处理 HTTP 协议,从而避免这个问题。

使用 Nginx 反代 Apache 安装 WordPress

最近由于原先博客主机极度不稳定,所以准备了很久,准备进行主机迁移。由于迁移前的环境和迁移后还是有较大的区别,整体架构也不太一样,所以在这里说说迁移过程中遇到的问题。

环境对比

原主机 新主机
操作系统 CentOS 6 CentOS 7
Web 服务器 Apache 2.2 Openresty 1.9.7 + Apache 2.4
PHP 版本 5.5 5.6
其他 SELinux

SELinux

很多人为了省事,在拿到主机的第一时间就直接禁用了 SELinux。不过在学习了一段时间之后,我发现其实 SELinux 是一个很好的保护机器的手段。

这里简单列举几个需要注意的 SELinux 的配置:

 

httpd_can_network_connect_db boolean 类型,控制 Apache 是否可以连接 DB
http_port_t port 类型,控制 Apache 可以监听的端口
mysqld_port_t port 类型,控制 mysql 可以监听的端口和 Apache 可以连接的 DB 端口

由于我是将 Apache 作为只解析后端 PHP 请求使用,所以需要修改 http_port_t 加入我需要的端口。添加方法类似于:

semanage port -a -t http_port_t  -p tcp 8090

另外由于我没有在本机安装 Mysql 而是使用的远程 Mysql 实例,并且开放的端口并不是标准的 3306,所以需要将端口号添加到 mysqld_port_t 中。

Apache

这玩意是主要的坑所在。下面来一一列举。

配置格式变更

Apache 2.2 和 2.4 的配置文件区别还是比较大的,加了很多新的参数,同时修改了很多配置的方法。最明显的是:

Options -Indexes

Allow from all
Deny from all

这三条配置已经完全被改掉了。如果在配置中出现第一种,会直接起不来。后面的 Allow Deny 的写法虽然不会有问题,但是已经不是官方推荐的了,建议改掉。

配置无效

在配置 Apache 2.4 的 Log Format 的时候,我发现了一个很蛋疼的问题,就是 CentOS yum 安装的版本(2.4.6)有些配置是使用不了的。如:

http://httpd.apache.org/docs/2.4/mod/mod_log_config.html

这个文档中的:

%{UNIT}T	The time taken to serve the request, in a time unit given by UNIT. Valid units are ms for milliseconds, us for microseconds, and s for seconds. Using s gives the same result as %T without any format; using us gives the same result as %D. Combining %T with a unit is available in 2.4.13 and later.

很多参数都有类似的标注(available in 2.4.13 and later),告诉你在旧版本中不能使用。如果不仔细看的话很容易忽略。所以配置之前一定要仔细阅读。

HTTPS

WordPress

由于我的博客是全站 HTTPS 的,因此在 WordPress 上我是有做一些强制 HTTPS 的措施。但是!由于 WordPress 默认的检测 HTTPS 的方法是这样的:

/**
 * Determine if SSL is used.
 *
 * @since 2.6.0
 *
 * @return bool True if SSL, false if not used.
 */
function is_ssl() {
        if ( isset($_SERVER['HTTPS']) ) {
                if ( 'on' == strtolower($_SERVER['HTTPS']) )
                        return true;
                if ( '1' == $_SERVER['HTTPS'] )
                        return true;
        } elseif ( isset($_SERVER['SERVER_PORT']) && ( '443' == $_SERVER['SERVER_PORT'] ) ) {
                return true;
        }
        return false;
}

而我的 HTTPS 是在 Nginx 层做的,所以导致这两个条件均不满足,因此会遇到重定向循环(Redirect Loop)的问题。解决方法有两种:

修改 wp-config.php 文件:

if ( isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && ( 'https' == $_SERVER['HTTP_X_FORWARDED_PROTO'] ) ) {
    $_SERVER['HTTPS'] = 'on';
}

这里的修改需要配合修改 Nginx 的 Proxy 设置,增加下面这行:

proxy_set_header X-Request-Protocol $scheme; #http or https

修改 wp-includes/functions.php 文件(4025行左右):

找到上面说的那段代码,将其替换为:

/**
 * Determine if SSL is used.
 *
 * @since 2.6.0
 *
 * @return bool True if SSL, false if not used.
 */
function is_ssl() {
        if ( isset($_SERVER['HTTPS']) ) {
                if ( 'on' == strtolower($_SERVER['HTTPS']) )
                        return true;
                if ( '1' == $_SERVER['HTTPS'] )
                        return true;
        } elseif ( isset($_SERVER['SERVER_PORT']) && ( '443' == $_SERVER['SERVER_PORT'] ) ) {
                return true;
        } elseif ( isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && ( 'https' == $_SERVER['HTTP_X_FORWARDED_PROTO'] ) ) {
                return true;
        }
        return false;
}

同时这个修改方法也要配合修改 Nginx 的 Proxy 设置。

注意,虽然可以不做判断直接无脑 $_SERVER[‘HTTPS’] = ‘on’; 或者在那个 is_ssl() 方法中无脑返回 true,但是不建议这样修改。因为这样可能会导致安全上面的问题。

Apache .htaccess

由于我在某些目录中通过 .htaccess 的方式强制重定向了非 HTTPS 请求,因此在将 SSL 交给 Nginx 之后相关的跳转判断也要修改。原先的跳转逻辑是:

RewriteEngine on
RewriteCond   %{HTTPS} !=on
RewriteRule   ^(.*)  https://%{SERVER_NAME}/$1 [L,R]

由于 %{HTTPS} 这个变量判断的是 Apache 传进来的内部参数,我们无法控制,所以需要将这段修改为:

RewriteEngine on
RewriteCond %{HTTP:X-Request-Protocol} ^http$
RewriteRule   ^(.*)  https://%{SERVER_NAME}/$1 [L,R]

这里判断的就是 Nginx 传进来的 X-Request-Protocol 头了。不过这种写法并不能在单独使用 Apache 作为 Web 服务器的时候使用,需要注意。

客户端证书

目前只针对某目录或文件的客户端证书配置还没有测试完成,将在后面更新。

SSL 双向认证的一个小问题

最近一直在研究 SSL 双向认证,工作中也经常用到。然后今天遇到了一个非常奇怪的问题,那就是就算配置了

ssl_verify_client optional_no_ca

客户端的访问仍然会失败,证书认证仍然不过。调试了半天,发现了两个问题,那就是:
1. optional_no_ca 并不会像 off 一样放过所有请求,而是对于提交了证书的请求,如果证书验证不过就会握手出错
2. 对于下面这个配置项的设置存在错误:

ssl_verify_depth 1

经过查找资料,找到了这个选项相关的一些说明。(注:以下实验均在 Nginx 和 Apache2.2 上同时进行过)

The depth actually is the maximum number of intermediate certificate issuers, i.e. the number of CA certificates which are max allowed to be followed while verifying the client certificate. A depth of 0 means that self-signed client certificates are accepted only, the default depth of 1 means the client certificate can be self-signed or has to be signed by a CA which is directly known to the server (i.e. the CA’s certificate is under SSLCACertificatePath), etc.

也就是说,当 depth 设置为 1(Nginx 的默认值)的时候,服务端只会接受直接被 CA 签发的客户端证书或自签名的证书。
但是!这段话没说的是,当你放在 SSLCACertificatePath 的文件中的 CA 证书只有中级 CA 的时候,验证仍然是会不过的,看后台的报错会发现:(下面这个是 Apache 的日志,Nginx 的只有 “Error (2): unable to get issuer certificate” 一句)

[Wed Feb 24 04:19:39.975324 2016] [ssl:debug] [pid 13380] ssl_engine_kernel.c(1381): [client xx.xx.xx.xx:48806] AH02275: Certificate Verification, depth 1, CRL checking mode: none [subject: CN=IMM_CA,OU=ROOT,O=ROOT,ST=SH,C=CN / issuer: CN=ST,OU=UP,O=ROOT,ST=SH,C=CN / serial: 02 / notbefore: Jan 14 10:31:00 2013 GMT / notafter: Jan 14 10:31:00 2017 GMT]
[Wed Feb 24 04:19:39.975409 2016] [ssl:info] [pid 13380] [client xx.xx.xx.xx:48806] AH02276: Certificate Verification: Error (2): unable to get issuer certificate [subject: CN=IMM_CA,OU=ROOT,O=ROOT,ST=SH,C=CN / issuer: CN=ROOT_CA,OU=ROOT,O=ROOT,ST=SH,C=CN / serial: 02 / notbefore: Jan 14 10:31:00 2013 GMT / notafter: Jan 14 10:31:00 2017 GMT]

也就是说,直接尝试使用中级 CA 来验证客户端是无法通过的,openssl 会自动的去找中级 CA 的签发者一层层验证上去,直到找到根。
所以,就算将 中级 CA 和 根 CA 都放在信任证书列表中,由于最终 depth 为 2 的缘故,验证还是过不了。

因此,在实际使用的时候,需要注意一下两点:
1. CA 文件中必须同时存在 中级 CA 和 根 CA,必须构成完整证书链,不能少任何一个;
2. 默认的验证深度 SslVerifyDepth ssl_verify_depth 是 1,也就是说只要是中级 CA 签发的客户端证书一律无法通过认证,需要增大该值。

同时还要注意 optional_no_ca 的问题,开了这个选项并不是会放过所有的请求,也会要求证书链完整才能通过。关于这一点个人比较奇怪,因为证书链完整了那就算开 require 应该也能通过了才对。。。
关于这一点做了一些尝试发现以下两种情况:
1. 如果 SSLCACertificateFile/ssl_trusted_certificate SSLCACertificatePath 这两个参数都不设置,那么 optional_no_ca 会放过所有有效的客户端证书(满足客户端证书的基本条件即可);
2. 如果 SSLCACertificateFile/ssl_trusted_certificate SSLCACertificatePath 这两个参数设置了,但是客户端提交的证书并不是这里的 CA 签发的,也会验证成功
但是!如果 SSLCACertificateFile/ssl_trusted_certificate SSLCACertificatePath 这两个参数里设置的证书包括了中级 CA 证书,但是没有包括中级 CA 证书的完整证书链,那么就会报 Error (2): unable to get issuer certificate 错误,验证失败。

使用Apache的mod_headers和mod_setenvif为静态文件取消Cookie

因为静态图片一般都不需要使用Cookie,因此,将静态文件的SetCookie头都去掉是一个很好的加快网站访问速度的办法。使用Apache的话,可以用mod_headers和mod_setenvif两个模块实现。

首先在httpd.conf中加载这两个模块,然后写上如下代码:
SetEnvIf mime image/.* unset-cookie
Header unset Set-Cookie env=unset-cookie

这样,当Apache再遇到类型为图片的文件时,就不会发送Set-Cookie头,自然可以减少一点流量的开销,加快网站的访问速度。

解决WordPress导致Apache的mod_status失效

今天申请了一个Linode账户,因为一直知道Linode的Longview很强大,于是准备体验一下。安装好之后发现自动检测到我运行了Apache,但是看不到具体的信息,因为我的Apache的Status页面没有配置好。
于是按照官方的教程进行配置,结果怎么访问都不成功。实验了多次并查找资料后发现,是我的Wordpress在捣鬼。
因为Wordpress启用了伪静态,所以所有的请求都会被重写向index.php,包括/server-status。于是直接导致了页面404。解决方法是在Wordpress的Rewrite规则中添加这一句:
RewriteRule ^(server-info|server-status) - [L]
这样如果Apache判断你的请求是server-info或server-status就会直接终止Rewrite,这样就不会将该请求重写到index.php,导致404了。

PS:在安装的时候还出现了一个小问题,就是发现在安装perl-DBD-MySQL的时候会失败,找不到依赖包。最后使用yum –enablerepo=remi install perl-DBD-MySQL的方式解决。

修复mod_spdy导致重定向循环

之前在别的服务器上做过一个测试网站,为了全部使用https就写了这么一个重定向规则在.htaccess中:
RewriteEngine On
RewriteCond %{HTTPS} off$ [NC]
RewriteRule (.*) https://%{SERVER_NAME}%{REQUEST_URI} [L,R=301]

之前工作的一直很好,直到我将apache的mod_spdy模块装上,准备给服务器部署上spdy支持。部署完spdy之后,该站的任何网页都打不开了,一直显示
This webpage has a redirect loop
但是使用IE浏览器的话还是正常的,可以正常的打开网页。于是查找资料,发现在启用了spdy协议之后,mod_rewrite就会获取不到正常的%{HTTPS}状态,从而导致无限的重定向,想让客户端使用https协议访问网站。在mod_spdy没有修复之前,有一个临时的解决办法,就是将重定向规则修改为如下这个样子:
RewriteEngine On
RewriteCond %{SERVER_PORT} ^80$ [NC]
RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI}

其实这只是将判断是否是https访问的方法由判断协议变成了判断端口,如果检查到用户是用80端口访问的就进行重定向,否则就不管了。虽然这么写是可以的,但是因为端口写死了,如果有修改服务端口的需要的话,就需要单独再来调整这个规则,比较麻烦。所以还是看看官方能否找到支持mod_rewrite的办法吧~

Mac OS 禁止apache httpd自动启动

mac os不像linux有/etc/init.d/rc.local以及service的方式可以设置程序随机启动,而是使用plist文件管理。
plist文件分布在:/System/Library/LaunchDaemons/中的最多,其中apache的httpd程序启动配置文件org.apache.httpd.plist就在这里。
但这些配置文件可由程序launchctl设置是否加载。也就是说,在launchctl list命令结果中出现的plist文件才会有效。
launchctl需要root权限。
禁止其随机启动方法:

sudo launchctl unload -w /System/Library/LaunchDaemons/org.apache.httpd.plist

如果没有任何输出就是成功卸载了。如果要加载,把unload换成load即可。
第二次运行unload会发现错误:launchctl: Error unloading: org.apache.httpd,这表示已经成功卸载了。

如果要查看launchctl用法,可以在shell终端输入launchctl,然后输入help回车。quit退出。

我在我的mac上操作成功,重启后httpd不会启动了。但奇怪的是当我自己用apachectl启动了httpd后,第二天开电脑发现httpd又自动启动了。于是我怀疑是否apachectl脚本里将其load了,打开/usr/sbin/apachectl,发现启动httpd竟然使用了launchctl的load方法。

为了让启动与否的主动权掌握在我自己手里,只好抛弃使用apachectl启动,使用自己写的httpd脚本启动,其实就是里面实现一下start,stop,restart三个条件判断即可,我使用时间长一些,所以稍复杂一些,见附件。

apachectl.tar.gz

替换后,别忘记再运行一次:
sudo launchctl unload -w /System/Library/LaunchDaemons/org.apache.httpd.plist

Apache 添加limitipconn模块并限制IP的并发连接数

安装&下载

首先到 http://dominia.org/djao/limitipconn2.html 获取最新版本的下载链接。我这里获取到的是:

http://dominia.org/djao/limit/mod_limitipconn-0.24.tar.bz2

wget http://dominia.org/djao/limit/mod_limitipconn-0.24.tar.bz2

bzip2 -d mod_limitipconn-0.24.tar.bz2

tar -xvf mod_limitipconn-0.24.tar

apxs2 -c -i -a mod_limitipconn.c

这里的apxs2是Ubuntu里面的一个可选组件,默认没有安装,需要自行使用apt-get install apache2-dev安装。

如果是CentOS,应该使用yum install httpd-devel来安装,而且安装之后的可执行程序名是apxs。

RH系的可以找httpd-devel的rpm包使用rpm命令安装,在此不再细说。

之后,检查httpd.conf或apache2.conf里面是否有LoadModule limitipconn_module modules/mod_limitipconn.so,如果有则正常,继续向下看:

###下面就是对web目录下的文件下载限制 

 #所限制的目录所在,此处表示主机的根目录
MaxConnPerIP 3 #所限制的每个IP并发连接数为3个
NoIPLimit image/* #对图片不做IP限制

 #所限制的目录所在,此处表示主机的/mp3目录
MaxConnPerIP 1 #所限制的每个IP并发连接数为1个
OnlyIPLimit audio/mpeg video #该限制只对视频和音频格式的文件

重启即可。

将迅雷拒之门外

不知道为什么,本来不受重视的L’Yun,却一直多灾多难,前几天空间呗停掉了,一个很以为的原因,每天将近9G的流量,晕死了,最多的一天才只有6个IP,但竟然有这么大的流量。后来查看了下日志,竟然是两首MP3引起的,每一秒钟都有人在下载。刚开始以为是百度干的,但是后来看了下在百度的位置,还不至于达到那么大的流量,然后自然而然的就想到迅雷了,看看别人的文章,可以肯定下,迅雷是个流氓!

解决方案:

1、对服务器的攻击屏蔽后,不用理会,不会造成太大影响。

2、被百度收录的是一部分MP3,因为不希望不访问网站就直接从后台下载网站的mp3,于是增加搜索引擎访问限制。在网站根目录下放置robots.txt,内容如下:

User-agent: Baiduspider

Disallow: /****

*表示不允许百度搜索引擎收录的路径。相对于百度,雅虎、MSN和Google的搜索引擎机器人没有那么流氓,所以不需要屏蔽。

3、对付迅雷。

相对于有些流氓的百度搜索引擎来说,迅雷就是恶霸了。

对于小网站站长来说,迅雷的分布式下载几乎是一种灾难。尽管迅雷给广大普通用户带来快捷方便,但给小服务器的负载带来严重灾难。

调用access日志,发现瞬间连接超过1000,而连接的集中点,居然是周董的一首《七里香》。尽管迅雷隐蔽的很好,但还是从日志的蛛丝马迹里找出它的影子。

于是先删掉七里香。删掉后仍有大量链接寻找其他MP3,而且删除一首mp3也只是治标不治本。启用Apache2的Rewrite模块。

在Apache的Http.conf中,开启Rewrite模块

LoadModule rewrite_module modules/mod_rewrite.so

然后增加以下Rewirte规则

RewriteEngine On

RewriteCond %{HTTP_REFERER} !^http://www.cfobbs.com/.*$ [NC]

RewriteCond %{HTTP_REFERER} !^http://www.cfobbs.com$ [NC]

RewriteRule .*\.(mp3|rm|wma)$ http://www.cfobbs.com/error.html [R,NC]

该规则表示,只有浏览器的REFERER是本站开头的连接,才可以下载MP3、rm、wma,否则转向error.html错误界面。

重启Apache后,用Flashget测试,无法下载mp3了,IE直接下载也会报错,但迅雷仍然可以下,百思不得其解,于是查阅迅雷官方资料,居然发现迅雷采用了一个十分流氓的手段:伪造下载地址的浏览器REFERER头,真是无耻。

考虑到网站的MP3全部是在网页自动播放,基本不需要额外下载,于是为了对付迅雷,采用了一个比较极端的方式:

RewriteEngine On

RewriteCond %{HTTP_USER_AGENT} !^NSPlayer.*

RewriteCond %{HTTP_USER_AGENT} !^windows.*

RewriteRule .*\.(mp3|rm|wma)$ http://www.cfobbs.com/error.html [R,NC]

也就是说,网站上mp3、rm、wma格式的文件,只允许播放器播放,不允许任何其它方式的访问,否则就转向错误页面。

重启Apache,使用迅雷下载,结果迅雷直接去下载了错误页面,初战告捷。

调用access日志,发现所有的mp3下载都提示302,转向了错误页面,而周董的七里香,则是404,直接报错。

自鸣得意一把。

顺便找到一个限速模块,对网站体积较大的文件进行限速,确保服务器稳定

LoadModule limitipconn_module modules/mod_limitipconn.so

BandwidthModule On

ForceBandWidthModule On

Bandwidth all 0

MinBandwidth all 0

LargeFileLimit *.mp3 500 50000

LargeFileLimit *.wma 500 50000

该模块可以指定文件名、文件大小限速,上面的意思是,MP3和WMA文件,凡是大小超过500K的,限速50K,大小不超过500K的,不予限速。

启用该模块,必须先行启用status模块

LoadModule status_module modules/mod_status.so

ExtendedStatus On

否则限速模块无效。

本文仅说明如何在服务器端屏蔽迅雷下载,包括HTTP方式和FTP方式,不涉及客户端和局域网内如何屏蔽迅雷的内容。

下面这里是废话,欢迎忽略,请直接跳到下面的“在Apache和屏蔽迅雷”
一旦服务器上的文件被迅雷索引,就会引来一大堆盗链的家伙,这对小带宽或低配置的服务器来说是致命的打击,于是如何限制迅雷下载服务器上的资源就成了一个很重要的问题。像我自己的服务器,用1MBps小水管来提供一个小网站的HTTP服务,开了内容压缩并设置好图片文件的缓存时间后,打开网页的速度还是比较快的,直到有一天,我发现网站打开的速度变得很慢,而且不是我自身的网络问题(当时我在外地,服务器在家里),当时仅仅知道是服务器上什么进程占用了大量带宽,还没有发现是迅雷的问题。后来经过了很多调查,才发现是迅雷在盗链,看访问日志里面一行行的大型文件下载记录,那真是触目惊心啊。
发现原因是迅雷盗链以后我就开始研究如何在服务器上屏蔽迅雷的下载。首先在HTTP协议上屏蔽迅雷是比较简单的,靠迅雷的用户代理(User Agent)就可以识别出迅雷了,但是在FTP协议上如何识别迅雷就比较棘手了。在好友的帮助下,最后我们终于发现一个在FTP协议上屏蔽迅雷的方法。在此之间和之后,我就写了IIS的反迅雷插件和Serv-U的反迅雷插件。
不过IIS和Serv-U只能在Windows平台上使用,这也是因为当时我的服务器还是Windows操作系统。其实Apache的mod_rewrite模块可以将用户代理作为重写条件,当时我也写了篇文章说明如何在Apache上屏蔽迅雷,但是在那之后还是有不少人发邮件问我如何在Apache上屏蔽迅雷。好吧,既然如此我就再写一篇文章来详细说明如何在Apache上屏蔽迅雷,顺便介绍libantixunlei,这是用于FTP反迅雷的一个C语言写的库。
上面是废话,欢迎忽略,下面进入正题。

在Apache上屏蔽迅雷

在HTTP协议上识别迅雷是通过迅雷的用户代理(User Agent)字串来进行识别的。我对我自己的网站的IIS访问日志以及一个评分系统的评分记录里面记录的用户字串进行了分析,之后发现迅雷使用的几个用户代理应该是唯一的,在访问日志中,除了下载文件的记录,只发现了极少量使用了和迅雷相同的用户代理的记录,这可能是个别用户出于杂七杂八的目使用迅雷下载普通网页而留下的日志。

有了这个分析结果,就可以保证通过用户代理来识别迅雷不会误杀普通用户了。但通过用户代理来识别迅雷有一个问题,如果以后迅雷把自己的用户代理改成和IE的用户代理一样的话怎么办?没关系,至少到现在为止(09年国庆),我还没有发现迅雷做此举动,等迅雷有动作了再想对策也不迟。另外,这里还有一个“脏数据”的方法,如果迅雷很不厚道地把自己伪装成IE的话,我们就只好也很不厚道地使用脏数据方法先反击一下迅雷。虽然脏数据对屏蔽迅雷没有什么帮助,至少可以出出气,让非最新版迅雷用户下载不到正确的内容,就这点应该够迅雷受的了,用户体验大受打击,我想大多数用户都不会追着使用最新版的。

于是,我在废话里面说了,使用Apache的mod_rewrite模块就可以很容易地屏蔽迅雷,因为这个模块的重写规则可以将用户代理作为判断条件。我们只要把用户代理和迅雷是一样的连接请求重定向到一个错误页面,或者干脆直接返回403,就可以在HTTP协议上屏蔽迅雷了。
到目前为止,我们观察到的迅雷使用的用户代理有以下几个:

  1. Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)
  2. Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)
  3. Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; )
  4. Mozilla/5.0 (compatible; MSIE 6.0; Windows NT 5.0)
  5. Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; .NET CLR 3.5.20706)
  6. Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; .NET CLR 2.0.50727)

放心,根据网站访问日志和评分系统的日志,这些用户代理应该都是迅雷特有的,在.htaccess文件里面把带有这些用户代理的请求重定向到错误页面就可以了。
当然对于普通网页来说,是没有必要屏蔽迅雷的,所以我们只需要屏蔽访问大文件的请求就可以了,于是.htaccess里面的内容就像下面这样:

  1. RewriteEngine On
  2. #Anti Thunder
  3. RewriteCond  %{HTTP_USER_AGENT}  ^Mozilla/4\.0\ \(compatible;\ MSIE\ 6\.0;\ Windows\ NT\ 5\.1\)$  [NC,OR]
  4. RewriteCond  %{HTTP_USER_AGENT}  ^Mozilla/4\.0\ \(compatible;\ MSIE\ 6\.0;\ Windows\ NT\ 5\.0\)$  [NC,OR]
  5. RewriteCond  %{HTTP_USER_AGENT}  ^Mozilla/5\.0\ \(compatible;\ MSIE\ 6\.0;\ Windows\ NT\ 5\.0\)$  [NC,OR]
  6. RewriteCond  %{HTTP_USER_AGENT}  ^Mozilla/4\.0\ \(compatible;\ MSIE\ 6\.0;\ Windows\ NT\ 5\.1;\ \)$   [NC,OR]
  7. RewriteCond  %{HTTP_USER_AGENT}  ^Mozilla/4\.0\ \(compatible;\ MSIE\ 6\.0;\ Windows\ NT\ 5\.0;\ \.NET\ CLR\ 3\.5\.20706\)$  [NC,OR]
  8. RewriteCond  %{HTTP_USER_AGENT}  ^Mozilla/4\.0\ \(compatible;\ MSIE\ 6\.0;\ Windows\ NT\ 5\.1;\ SV1;\ \.NET\ CLR\ 1\.1\.4322;\ \.NET\ CLR\ 2\.0\.50727\)$  [NC]
  9. RewriteRule  ^.*\.(gif|jpg|bmp|zip|rar|exe|mp3|swf)$   /   [NC,F]

如果你想制定更复杂的重写规则,可以参考Apache手册中mod_rewrite的部分,见:http://lamp.linux.gov.cn/Apache/ApacheMenu/mod/mod_rewrite.html
对于其他Web服务器软件,多多少少都能提供一些可将用户代理作为判断条件的网址重写模块或插件,参照上面Apache的设置方法对这些软件进行设置,都能达到屏蔽迅雷的效果。

在FTP协议上反迅雷

在FTP上反迅雷就比较麻烦,这需要获得每一个FTP会话的会话唯一标识和客户端发送的每一条FTP指令。因为这样的需求很少见,所以Linux下的FTP软件很少有提供相应的接口供我们使用。不过还好,Linux下的FTP软件大多都是开源的,我们可以自己修改源码。于是我就写了libantixunlei,然后针对不同的FTP软件,就套用libantixunlei来修改其源码,然后编译安装就可以了。

因为要修改FTP服务器软件的源码,这对技术的要求就比较高了,不见得每个服务器管理员都会C语言,所以对大多数服务器管理员来说目前还是只能等待别人为FTP软件写插件(如果支持的话),或者发布经过修改的FTP服务器软件源码。

于是,如果你想为某个FTP软件加入反迅雷的功能,请访问http://code.google.com/p/libantixunlei 。如果对libantixunlei的用法不太清楚的话,请给我发邮件,我会告诉你FTP协议上屏蔽迅雷的原理和应该使用libantixunei的哪些接口来识别迅雷。

不过先不要失望,现在已经有了可以反迅雷的Linux上的FTP服务器软件了,在我写这篇文章的时候我已经给pure-ftpd 1.0.22版本成功地打上了反迅雷补丁,补丁文件请到:http://code.google.com/p/libantixunlei/downloads/list 去下载,下载回来以后给纯净的pure-ftpd-1.0.22版本打上这个补丁(使用patch命令),然后编译安装就支持反迅雷了。对于其他版本的pure-ftpd我没有试验过是否能使用这个补丁,不知道能否正常使用。另外在此提醒一下没有自己编译安装过软件的管理员,pureftpd的一些功能需要在./configure的时候加上一些参数才能使用,具体请看源码根目录下面的说明文件,偷懒的话可以 ./configure –with-everything,不过印象中官方并不推荐使用这个参数。
另外,因为我很懒,所以把一些特性写死在程序里面了,是否屏蔽使用迅雷的IP和屏蔽IP的时间是写死在程序里面的,要改变的话只能重新编译。这两个配置在libantixunlei.h文件里面可以修改。

libantixunlei使用了pthread库,而在一些平台上编译的时候如果要使用pthread库需要显式指定-lpthread参数,我在PBS服务器上编译的时候没有问题,但是在自家的一台电脑上编译的时候却出错了。如果编译失败的话,点击这个地址查看处理方法:http://code.google.com/p/libantixunlei/wiki/BianYiShiBai

最后做广告:如果需要在Windows系统上反迅雷,请访问:https://www.gsea.com.cn/gs/fanxunlei/isapi.html
这里再贴出一个网友维护的迅雷、QQ旋风等下载软件的离线服务器IP列表,已经做成了Apache可识别的.htaccess,直接添加到自己的.htaccess中即可。
http://ipfilter-emule.googlecode.com/svn/trunk/ipfilter-xl/.htaccess

WordPress 的 .htaccess 规则

原文:wpshout.com

我们知道 .htaccess 文件能轻松地强化你的博客,减少带宽并增加可用性。我曾经写过一篇简易的 .htaccess 教程:《四个例子实战讲解.htaccess文件rewrite规则》。如果你还想继续了解 .htaccess 文件,那么不妨看看下面这26个规则:

但是请先记住一条黄金法则:先备份,再折腾!

A – WP- Admin – 管理员页面

你可以限制访问 WP- Admin 页面的 IP 地址

1
2
3
order deny,allow
allow from a.b.c.d # This is your static IP
deny from all

来源 –BlogSecurity.net

B – Blacklist – 黑名单

.htaccess 的一个重要功能是你能把它作为 IP 黑名单来使用:

1
2
3
4
5

order allow,deny
allow from all
deny from 123.456.789

来源 – Perishable Press

C – WP-Config Protection – 保护 Config 页

WP-Config 文件里包含了你的数据库名、数据库用户名与密码。这样的文件你敢让别人看到吗?所以你会需要用 .htaccess 来保护它。

1
2
3
4
5
# protect wpconfig.php
order allow,deny
deny from all

来源 – Josiah Cole

D – Disable Directory Browsing – 禁止浏览目录

WP-Config 文件里包含了你的数据库名、数据库用户名与密码。这样的文件你敢让别人看到吗?所以你会需要用 .htaccess 来保护它。

1
2
# disable directory browsing
Options All -Indexes

来源- Josiah Cole

E – Explanation – 释疑

如果我问你 .htaccess 是什么,我猜你一定很难说明白。老实说,我自个儿也不明白。好在维基百科给了个明确的解释:

.htaccess 是Apache HTTP Server的文件目录系统级别的配置文件的默认的名字。它提供了在主配置文件中定义用户自定义指令的支持。

维基百科也给出了一些特定的例子,你可以访问:http://zh.wikipedia.org/w/index.php?title=.htaccess&variant=zh-cn 了解更多。

F – Feedburner – RSS烧制

Feedburner 是各位博主的好帮手,通过这个例子你能把原来的 RSS 地址转向到烧制后的地址。

1
2
3
4
5
6
7
# temp redirect wordpress content feeds to feedburner

RewriteEngine on
RewriteCond %{HTTP_USER_AGENT}!FeedBurner [NC]
RewriteCond %{HTTP_USER_AGENT}!FeedValidator [NC]
RewriteRule ^feed/?([_0-9a-z-]+)?/?$ http://feeds.feedburner.com/perishablepress [R=302,NC,L]

来源 – Perishable Press

G – Get an RSS Feed on a static page – 获取静态页的RSS

通过下面这个链接,你能学习到利用 .htaccess 获取静态页 RSS 的办法。

链接 – adityaspeaks.com

H – Disable hotlinking – 防止盗链

所谓盗链,就是别人私自用了你服务器上的图片、声音等文件,占用了你的带宽。你可以通过下面这个 .htaccess 规则来阻止盗链:

1
2
3
4
5
6
#disable hotlinking of images with forbidden or custom image option
RewriteEngine on
RewriteCond %{HTTP_REFERER}!^$
RewriteCond %{HTTP_REFERER}!^http://(www\.)?yourdomain.com/.*$ [NC]
#RewriteRule \.(gif|jpg)$ -[F]
#RewriteRule \.(gif|jpg)$ http://www.yourdomain.com/stealingisbad.gif [R,L]

来源 – Josiah Cole

I – Important! – 重要提示!

是啊,呵呵,“I”开头的词是有些难找,但是它同样重要,very Important!

备份,要记住备份。当你把东西搞得一团糟时,只有备份文件能救你!

J – Jauntily show the admin’s email address in error message

*抱歉,本词条有误*

K – Keep RSS ‘content thieves’ away – 防范“RSS小偷”

你一定不希望有人窃取你网站的内容吧?他们只要有你的 RSS 地址就能复制内容。如果你有对方网站的IP地址(怎么获取?很简单,google 它),就能屏蔽该网站对你的 RSS 的读取。如果有不止一家网站复制你的内容,你只要增加 IP 地址就行了。

1
2
3
RewriteEngine on
RewriteCond %{REMOTE_ADDR}^69.16.226.12
RewriteRule ^(.*)$ http://newfeedurl.com/feed

来源 – Seo Black Hat

L – Limiting number of simultaneous connections – 限制并发连接数

如果你要限制并发连接数(就是同时访问你的网站的人数),就使用下面这个代码。

1 MaxClients < number-of-connections>

M – Maintenance – 制作临时维护页面

无论什么原因,可能是维护、更新,你都可能会要暂时停止你的网站。这时你就需要一个维护页。无论访客访问的是你网站的任一 URL 还是 IP 地址,都能转向到维护页面。

1
2
3
4
RewriteEngine on
RewriteCond %{REQUEST_URI}!/maintenance.html$
RewriteCond %{REMOTE_ADDR}!^123\.123\.123\.123
RewriteRule $ /maintenance.html[R=302,L]

来源 – CatsWhoCode/Woueb.net

N – Deny no referer requests [stop spam comments!] – 拒绝垃圾留言!

这是一个比下文“S”词条更简便的防 Spam 方法。其原理是,如果留言者不公开来源,即是用机器留言的,就屏蔽之。就这么简单。

1
2
3
4
5
6
RewriteEngine On
RewriteCond %{REQUEST_METHOD} POST
RewriteCond %{REQUEST_URI} .wp-comments-post\.php*
RewriteCond %{HTTP_REFERER}!.*yourblog.com.*[OR]
RewriteCond %{HTTP_USER_AGENT}^$
RewriteRule (.*)^http://%{REMOTE_ADDR}/$ [R=301,L]

来源 – WPRecipes

O – Force files when opening to ‘save as’ – 用“另存为”方式打开文档

有时候你空间里的一些文件,比如音乐、视频文件,点开后会有软件自动打开这个文件。如果你不想自动打开,这个规则能把文件强制为另存为方式下载。

1 AddType application/octet-stream .avi .mpg .mov .pdf .xls .mp4

来源 – AskApache

P – Protect your .htaccess file – 保护 .htaccess 文件

如果你的博客已经做好的十足的防护措施,是不是也要考虑一下保护你的 .htaccess 文件呢?黑客也可能通过这个文件发起攻击。下面这个规则能禁止下载 .htaccess 文件。

1
2
3
4
5
6
# STRONG HTACCESS PROTECTION
\.([Hh][Tt][Aa])”>
order allow,deny
deny from all
satisfy all

来源 – Perishable Press

Q – Quicken your site’s loading time by caching – 设置缓存

下面这个链接有详细的教程,教你如何给 WordPress 博客设置缓存。

链接 – Samaxes

R – Redirect to other pages on your site – 301重定向

1 RedirectMatch 301^/blog/.*$ http://domain.tld/target.html

来源 – Perishable Press

S – Spam! – 阻止垃圾留言

通过 .htaccess 来禁止 Spam 是个好办法。下面这个链接给出了一个 Spam 黑名单,复制到你的 .htaccess 里,你就能防止绝大部分的垃圾留言。

来源 – perishablepress.com

T – Set the Timezone of the server – 设置服务器时区

译者:代码给出的是把TZ值设置为美国时间的代码,如果服务器在中国,你可以改为Asia/Shanghai。

1 SetEnv TZ America/Indianapolis

来源 – AskApache

U – Remove /category/ from your category URL – 简化 WP 分类页面地址

WordPress 的分类页面地址里有一个 /category/ ,会不会觉得这很多余呢?下面这个代码就能去掉它!

1 RedirectMatch 301^/category/(.+)$ http://www.askapache.com/$1

或者

1 RewriteRule ^category/(.+)$ http://www.askapache.com/$1 [R=301,L]

来源 – AskApache

V – Valiantly automatically fix URL spelling mistakes – 修复错误地址

这个代码能自动检查英文地址的拼写错误。

1
2
3

CheckSpelling On

来源 – Vortex Mind

W – Redirect from http://Www.whatever to http://Whatever – 去掉网址前面的www.

使用301转跳,实现网址标准化。

1
2
3
4
5
# permanently redirect from www domain to non-www domain
RewriteEngine on
Options +FollowSymLinks
RewriteCond %{HTTP_HOST}^www\.domain\.tld$ [NC]
RewriteRule ^(.*)$ http://domain.tld/$1 [R=301,L]

来源 – Stupid htaccess tricks

X – Make your wp-login.php page Xenophobic – 限制他人访问 wp-login

Xenophobic: “排外,仇视陌生人”

我觉得你应该适当使用这个规则。如果你不是多人博客,可以限制他人访问登录页面,以达到更高的安全性。

1
2
3
4
5

Order deny,allow
Deny from All
Allow from 123.456.789.0

来源 – Reaper-X

Y – Easily rename your .htaccess file – 重命名 .htaccess 文件

如果你的服务器不接受以句点开头的文件怎么办?重命名它呗!下面这个代码能实现 .htaccess 文件的重命名。

1
2
# rename htaccess files
AccessFileName ht.access

来源 – Perishable Press

Z – Say Zygote in your .htaccess file – 在 .htaccess 里写注释

你可能会想在 .htaccess 文件里做些解释,好让别人能看懂。那怎么做注释呢?请看下面的代码:

1 # see -thisis a comment - you can only use letters and numbers and - and _ That is why there are no commas

要注意的是注释里只能写字母、数字与下划线

译者后记:原文的作者看样子也是经过收集才写成这篇文章的。如果你看了原文,请你注意,原文的有些代码里有一些多余或错误代码。我在本译文里都已做了修正。