吹毛求疵还是精益求精?再谈 nginx fastcgi/fpm 正则禁止上传目录 php 执行

2016-07-29 11:55:57 +08:00
 tntsec

注意,本文讨论的仅仅是如何绕过禁止规则进入 cgi 。

nginx fastcgi/fpm 禁止上传目录 php 执行 因为上传目录是具备写入权限的,写入权限很恐怖。

1.最常见的,完全错误的方法 来源,百度下最常见的

location ~ ^/upload/.*\.(php|php5)$
{
deny all;
}

正则解释 ^/upload/.*.(php|php5)$ 开头匹配^ 中间任意匹配.* 点匹配\. (php|php5)php扩展名选择器 结尾匹配$

绕过方法, 1.php 可以是个目录 /1.php/3038714494.png

2.Nginx 下多站点正确限制目录 php 执行权限 来源 http://www.freebuf.com/articles/system/49428.html

location ~ /(ups)/.*\.(php|php5)?$
                       {
                               deny all;
                        }

正则解释 比上面的多了一个?问号,问号代表零次或一次。

绕过方式,同上 /1.php/3038714494.png

3.nginx+cgi 解析 php 容易出现的漏洞 来源 http://www.nginx.cn/316.html

location ~* ^/upload/.*.(php|php5)($|/)
{
    deny all;
}

正则解释 ^/upload/.*.(php|php5)($|/) 开始匹配^ 匹配任意多字符.* 匹配任意字符请输入代码.(怀疑此处其实他想匹配点,但是正则中的点代表任意字符) 结束或者目录符号($|/)

此方式解决了上面的绕过问题

缺点,封杀太严格,目录中包含 php 三个字母就会封杀 /php/3038714494.png

4.关于 lnmp 目录禁止执行的绕过与正确方法 来源地址 http://zone.wooyun.org/content/16213 谷歌缓存 http://webcache.googleusercontent.com/search?q=cache:g3B4qj-SGXgJ:zone.wooyun.org/content/16213+&cd=1&hl=zh-CN&ct=clnk&gl=cn

location ^~ /upload/ { 
    default_type text/plain; 
    expires 30d; 
} 

解释,这不是正则,却更加有趣 ^~表示匹配一次,不再让其他 location 处理,从而不会匹配到 cgi 中 这种方式需要的判断最少,是非常好的方式

他只有一点点瑕疵,那就是源码泄漏 如果 config.php 文件被复制到这个目录下,源码一览无余。因为这个方法只是不让 php 进入 cgi ,但是却没有禁止他的解析。

5.我的方法 当你看完上面的内容,相信你已经有了自己的方法了 我这里稍微修改下第三种方法,就是括号里的部分

location ~ (/usr/uploads/|/admin/).*\.(php|php5)($|/) {
    deny all;
}

增加的部分 location ~ (/usr/uploads/|/admin/).*\.(php|php5)($|/) 将从匹配任意字符调整为匹配点,这样就不会拦截包含 php 字符的目录了,但是依然会拦截 如果出现.php目录,我们可以默认认为他是黑客行为。

小提示,注意(/usr/uploads/|/admin/)和(/usr/uploads|/admin)的区别

6272 次点击
所在节点    NGINX
28 条回复
falcon05
2016-07-29 13:40:14 +08:00
第 3 条的 规则并不会 “封杀目录中包含 php 三个字母的文件如 /php/3038714494.png ” ,

正则解释 ^/upload/.*.(php|php5)($|/) 开始匹配^ 匹配任意多字符.* 匹配任意字符请输入代码.(怀疑此处其实他想匹配点,但是正则中的点代表任意字符) 结束或者目录符号($|/)

nginx 的 “.” 单独用的话它就是代表 “.” ,不用转义。
strwei
2016-07-29 13:55:34 +08:00
建议还是用 apache 跑 php
lhbc
2016-07-29 14:58:17 +08:00
正确的做法不是 try_files 吗?
tntsec
2016-07-29 17:38:19 +08:00
@falcon05 测试会封杀,再次测试依然被封杀
不转移, nginx 仅仅识别一个目录下而不能识别目录的目录下
/php/3038714494.png 404
/1/php/3038714494.png 403
tntsec
2016-07-29 17:38:51 +08:00
@lhbc 啥?
ryd994
2016-07-29 18:37:25 +08:00
问题是……对于 nginx 来说,只要没有 fastcgi
ryd994
2016-07-29 18:43:26 +08:00
问题是……对于 nginx 来说,只要没有 fastcgi_pass 就不会交给 php 来处理
于是你为什么要给上传目录加 fastcgi_pass 呢?

只需要用^~ 防止上传路径被匹配到 php 的 block 里就可以了
同时,对于 php 的 block ,用 try_files 检查文件是否存在
或者用 fastcgi_split_path_info 代替 php 自己的 path_info 检测

这些都是性能很好而且简单清晰的解法
ryd994
2016-07-29 18:44:48 +08:00
@Livid Duplicate with: /t/295225
ysc3839
2016-07-29 18:49:27 +08:00
我之前配置过一个,是把全部都重写到 index.php 的,也不知道怎么配置的,上传目录里面 php 那些全都不能执行,访问的话就变文件下载
tntsec
2016-07-29 19:06:29 +08:00
@ryd994 你这跟第四种方法有啥不一样的吗?
ryd994
2016-07-29 20:31:54 +08:00
@tntsec 天……那我是不是可以说我把 /etc/passwd 拷贝到任意文件夹下会泄漏?
是不是还要考虑 config.php 复制后被改名?
你知道 regex 很低效么?
falcon05
2016-07-29 20:51:47 +08:00
@tntsec 我不知道你怎么测试的,还会有 404 的?
然后我写了一个,打开浏览器:

<https://www.cellmean.com/upload/hello.php> 403
<https://www.cellmean.com/upload/php/a.jpg> 200

事实上我觉得用第一条就可以了,后面的几条包括你给的反而画蛇添足,把 php 的目录也排过滤掉了,比如网站头像图片存在 /usr/uploads/用户名目录下,当注册用户恰好叫 php ,如果用你那一条,那这个用户的头像 /usr/uploads/php/avatar.jpg 就无法显示了。

你举的反例我觉得很奇怪。

“绕过方法, 1.php 可以是个目录 /1.php/3038714494.png ”

绕过了什么? nginx 在这里并不是用来阻止上传文件上传到 /1.php 这个目录的,你要证明的是这个 png 会被当成 php 文件执行。
falcon05
2016-07-29 20:57:28 +08:00
z5864703
2016-07-30 00:30:09 +08:00
上传文件不放公开目录,必须通过程序转发直接输出下载。
不过好像楼主说的是通过 nginx 正则...文不对题了...
tntsec
2016-07-30 09:34:25 +08:00
@ryd994 /etc/passwd 受 chroot 限制,不会越出网站目录,顶多访问 tmp 和网站根目录。当然 chroot 是自己配的
需要考虑,但是在目前只能称他为瑕疵,因为改后缀名就变得不好考虑了
很低是有多低,很高效又是多高效
tntsec
2016-07-30 09:40:42 +08:00
@falcon05 禁止上传目录 php 执行,不是禁止上传
tntsec
2016-07-30 09:41:24 +08:00
@z5864703 禁止上传目录 php 执行 请连起来看
kiwi95
2016-07-30 09:47:11 +08:00
后面的正则确实太过复杂,效率太低,其实防止上传的文件保存为 .php 后缀到 upload 文件夹就没事了,将上传的文件 hash 一下不带后缀或者后缀检查

nginx 配置讲究简洁高效,程序和 nginx 配合做到高效安全就好了
aprikyblue
2016-07-30 09:52:12 +08:00
这是在讨论正则吗。。
jarlyyn
2016-07-30 09:52:44 +08:00
理论上述说,还是代码和其他文件分开比较好

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/295734

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX