关于漏洞原理参见 ,最开始是直接把php.ini中设置 cgi.fix_pathinfo = 0想一劳永逸解决。不过后来发现其导致PHP的超全局变量 $_SERVER['PHP_SELF']为空于是有些程序会出错(比如Discuz会拼接出错误图片头像路径)。于是考虑在保持 cgi.fix_pathinfo =1时如何避免漏洞。网上搜索到的解决办法挺多比如 ,因为 加上正则判断存在漏判问题,所以尝试使用其他方式解决。
经过试验找到一个终极解决办法,用try_files替代if判断文件
try_files $fastcgi_script_name =404;
debug日志中会有类似判断
*308 trying to use file: "/robots.txt/a.php" "/var/htdoc/mychery.net/robots.txt/a.php"
之前在网上搜索到一个办法,经过测试是无效的
try_files $request_filename =404; #无效的用法!
debug日志如下,判断路径重复拼接是错误的
*339 trying to use file: "/var/htdoc/mychery.net/robots.txt/a.php" "/var/htdoc/mychery.net/var/htdoc/mychery.net/robots.txt/a.php"
可以把正确的判断命令加入到fastcgi.conf中:
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; fastcgi_param QUERY_STRING $query_string; fastcgi_param REQUEST_METHOD $request_method; fastcgi_param CONTENT_TYPE $content_type; fastcgi_param CONTENT_LENGTH $content_length; fastcgi_param SCRIPT_NAME $fastcgi_script_name; fastcgi_param REQUEST_URI $request_uri; fastcgi_param DOCUMENT_URI $document_uri; fastcgi_param DOCUMENT_ROOT $document_root; fastcgi_param SERVER_PROTOCOL $server_protocol; fastcgi_param GATEWAY_INTERFACE CGI/1.1; fastcgi_param SERVER_SOFTWARE nginx/$nginx_version; fastcgi_param REMOTE_ADDR $remote_addr; fastcgi_param REMOTE_PORT $remote_port; fastcgi_param SERVER_ADDR $server_addr; fastcgi_param SERVER_PORT $server_port; fastcgi_param SERVER_NAME $server_name; # PHP only, required if PHP was built with --enable-force-cgi-redirect fastcgi_param REDIRECT_STATUS 200; try_files $fastcgi_script_name =404;
然后在location中引用它:
location ~ \.php$ { fastcgi_pass unix:/tmp/phpfpm/php-fpm.sock; include fastcgi.conf; }
另外,nginx官方推荐使用try_files替代if相应功能。