nginx是一把利刃,配置起来也有很多学问,配置不当可能对性能有一定影响,甚至导致错误,引起安全隐患。

本文对nginx的rewrite模块的last、break做个测试,使存在的性能问题和安全隐患显露出来。

功能一:用nginx的proxy模块代理一台windows的iis7
功能二:用nginx的fastcgi模块处理php脚本

架构及拓扑:
192.168.0.6:nginx+fastcgi
192.168.0.8:windows的iis7服务器

目标:
将10000以内的帖子通过nginx转发到iis7上,将10000及以上的帖子转给nginx本机的fastcgi模块处理

数据:
iis7的根目录有post目录和其下的9999个htm文件,如:1.htm.......9999.htm,内容就是文件的绝对路径。
nginx的根目录是/usr/local/nginx/html,其下有php脚本文件post.php,内容如下:
$id = $_GET['id'];
print "id = [$id]";

nginx配置文件内容:
server {
  listen             80;
  server_name    localhost;
  root     html;
  location ~* "/\d{1,4}\.htm$" {
    proxy_pass http://192.168.0.8;
    rewrite /(\d+\.htm)$ /post/$1 last;
  }
  location ~* "/\d{5,}\.htm$" {
    rewrite "/(\d{5,})\.htm" /post.php?id=$1 last;
    fastcgi_pass 127.0.0.1:9000;
    include fastcgi.conf;
  }
  location / {

  }
}

现在我们访问1w以内的帖子:
[root@demo conf]# curl 192.168.0.6/1.htm

500 Internal Server Error

500 Internal Server Error



nginx/1.2.5


看,发生了500 内部服务器错误,看日志可以确定是内部循环重定向错误,即rewrite死循环。因为这里在location里使用了last,第一次请求的uri是/1.htm匹配,rewrite后的uri为/post/1.htm,因为是last所以会再次对server发起请求,再一次匹配了,继续反复循环下去,直到达到服务器定义的10次,才终止,并返回500内部服务器错误
解决:将last换成break

现在我们访问1w以外的帖子:
[root@demo conf]# curl 192.168.0.6/10000.htm
$id = $_GET['id'];
print "id = [$id]";
看到了吧,多危险啊,php脚本代码暴露了,如果用浏览器访问会下载这个php处理脚本文件,即10000.htm。这是什么原因导致的呢?这是因为在location里使用了last造成的,具体是这样的:第一次请求的uri是/10000.htm,匹配,rewrite后的uri为/post.php?id=10000,因为是last所以会再次对server发起请求,这次匹配不上前面两个location了,只能匹配最后的一个location /了,因为location /的根目录在/usr/local/nginx/html,而且是对post.php文件的请求,就处理这个请求,将post.php文件的内容作为10000.htm的内容返回,由于这个不是正常的htm文件,就用默认的default_type application/octet-stream处理,就是下载了。如果将默认类型换成text/plain,即文本文件的类型,就不会提示下载了,直接显示出来了。一样危险!!!
解决:将last换成break

总结:last会对server再次发起请求,而break不会,因此看需求,如果rewrite后还需要再次请求完成正确的匹配,那就用last。