今天在进行PHP相关参数配置优化时,将cgi.fix_pathinfo=0
后网站出现的Access denied字样及排解方法。
参数说明
PHP里经常要获取当前请求的URL路径信息。一般可以通过环境变量$SERVER[‘PATH_INFO’]
获取,而配置文件中的cgi.fix_pathinifo
选项则与这个值的获取相关。而$SERVER[‘PATH_INFO’]
中的key PATH_INFO
是一个CGI 1.1的标准,经常用来做为传递参数给后端的CGI服务器。
PHP的以前的行为是将PATH_TRANSLATED
设置为SCRIPT_FILENAME
,并且不要弄清PATH_INFO
是什么。设置cgi.fix_pathinfo=1
后,cgi设置完整的路径信息PATH_TRANSLATED
的值为SCRIPT_FILENAME
,并且设置PATH_INFO
信息;如果设为cgi.fix_pathinfo=0
则只设置绝对路径PATH_TRANSLATED
的值为SCRIPT_FILENAME
。在php.ini
文件中cgi.fix_pathinfo
的默认值是1。
Nginx默认是不会设置PATH_INFO
环境变量的的值,需要通过正则匹配设置SCRIPT_FILENAME
,但这样会带来安全隐患,需要把cgi.fix_pathinfo
设置为0。但是一旦关闭这个选项,PHP就获取不到PATH_INFO
信息,那些依赖PATH_INFO
的程序就失效了,甚至网站也会出现Access denied字样,如下:
[root@localhost ~]# curl -i http://192.168.17.130:8090/7.html
HTTP/1.1 403 Forbidden
Server: nginx/1.19.6
Date: Wed, 24 Feb 2021 12:16:30 GMT
Content-Type: text/html; charset=UTF-8
Transfer-Encoding: chunked
Connection: keep-alive
Vary: Accept-Encoding
Access denied.
[root@localhost ~]#
可造成的危害
我们配置php时将cgi.fix_pathinfo
参数设置为0的主要作用是禁止解析非法php文件,如/a.jpg/1.php
这样的图片下的一个php文件属于非法的,设置为0就是禁止执行。这种将木马伪装成图片上传的文件攻击方式存在已久,禁止这类文件运行,即使被上传了文件木马,由于设置了不允许运行,所以就没有用了。关于该安全隐患的问题,可参考这篇文章:https://www.laruence.com/2010/05/20/1495.html
Nginx支持pathinfo实现
在将cgi.fix_pathinfo
参数设置为0后,为解决网站正常运作而不出现Access denied的问题,遂就在网上查阅了大量资料并结合自己所测试,现给出如下的nginx解析php的代码
location ~ [^/]\.php(/|$) {
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
#增加 fastcgi_split_path_info指令,将URI匹配成PHP脚本的URI和pathinfo两个变量
#即$fastcgi_script_name 和$fastcgi_path_info
fastcgi_split_path_info ^(.+?\.php)(/.*)$;
fastcgi_param PATH_INFO $fastcgi_path_info;
# 正则解析路径,使用set指令产生nginx变量并赋值
set $real_script_name $fastcgi_script_name;
# 正则匹配URI,若能匹配将产生两个子组
if ($fastcgi_script_name ~ "^(.+?\.php)(/.+)$") {
#将两个子组赋值给刚生成的nginx变量
set $real_script_name $1;
set $path_info $2;
}
# 将可能匹配到的$path_info值通过fastcgi_param指令设置进去
fastcgi_param PATH_INFO $path_info;
# 覆盖fastcgi_params文件中默认的SCRIPT_NAME配置项
fastcgi_param SCRIPT_NAME $real_script_name;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
# 加载默认的fastcgi配置项
include fastcgi_params;
}
这样cgi.fix_pathinfo
参数为0也可以正常解析了,此处建议在cgi.fix_pathinfo=1
时可将上述参数fastcgi_split_path_info ^(.+?\.php)(/.*)$;
和fastcgi_param PATH_INFO $fastcgi_path_info;
将其注释,保留其它即可,可能此处也有自己理解错误的地方,若有错误,还望各位大佬指正!