Nginx+PHP 配置漏洞:静态文件都可以当作 PHP 解析

本文揭示了一个Nginx+PHP配置导致的严重漏洞,表现为可通过特定方式访问原本不应被执行的文件。此问题源于PHP对SCRIPT_FILENAME和PATH_INFO的处理机制。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

漏洞危险等级:毁灭性。

这个漏洞严格上说并不是 Nginx 和 PHP 本身的漏洞造成的,而是由配置造成的。在我之前写的许多配置中,都普遍存在这个漏洞。

简易检测方法:
打开 Nginx + PHP 服务器上的任意一张图片,如:

http://hily.me/test.png

如果在图片链接后加一串 /xxx.php (xxx为任意字符)后,如:

http://hily.me/test.png/xxx.php

图片还能访问的话,说明你的配置存在漏洞。

漏洞分析:

下面通过分析一个很常见的 Nginx 配置来解释下漏洞的成因:

server {
    listen       80;
    server_name  test.local;

    access_log  /work/www/logs/test.access.log  main;
    error_log  /work/www/logs/test.error.log;

    location / {
        root   /work/www/test;
        index  index.html index.htm index.php;
    }

    location ~ \.php$ {
        root           /work/www/test;
        fastcgi_index  index.php;
        fastcgi_param  SCRIPT_FILENAME    $document_root$fastcgi_script_name;
        include        fastcgi_params;
        fastcgi_pass   unix:/tmp/php-fpm.sock;
    }
}

我们在 /work/www/test/ 目录下新建一个文件 test.png,内容如下:

那么访问 http://test.local/test.png 时,输出为文本内容:

但是当在后面加上 /xxx.php 时,即 http://test.local/test.png/xxx.php,可怕的事情发生了:

Array
(
    [HOSTNAME] =>
    [PATH] => /usr/local/bin:/usr/bin:/bin
    [TMP] => /tmp
    [TMPDIR] => /tmp
    [TEMP] => /tmp
    [OSTYPE] =>
    [MACHTYPE] =>
    [MALLOC_CHECK_] => 2
    [USER] => www
    [HOME] => /home/www
    [FCGI_ROLE] => RESPONDER
    [SCRIPT_FILENAME] => /work/www/test/test.png
    [QUERY_STRING] =>
    [REQUEST_METHOD] => GET
    [CONTENT_TYPE] =>
    [CONTENT_LENGTH] =>
    [SCRIPT_NAME] => /test.png/xxx.php
    [REQUEST_URI] => /test.png/xxx.php
    [DOCUMENT_URI] => /test.png/xxx.php
    [DOCUMENT_ROOT] => /work/www/test
    [SERVER_PROTOCOL] => HTTP/1.1
    [GATEWAY_INTERFACE] => CGI/1.1
    [SERVER_SOFTWARE] => nginx/0.7.62
    [REMOTE_ADDR] => 192.168.1.163
    [REMOTE_PORT] => 4080
    [SERVER_ADDR] => 192.168.1.12
    [SERVER_PORT] => 80
    [SERVER_NAME] => test.local
    [REDIRECT_STATUS] => 200
    [HTTP_ACCEPT] => image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/x-shockwave-flash, application/QVOD, application/QVOD, application/x-ms-application, application/x-ms-xbap, application/vnd.ms-xpsdocument, application/xaml+xml, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, */*
    [HTTP_ACCEPT_LANGUAGE] => zh-cn
    [HTTP_ACCEPT_ENCODING] => gzip, deflate
    [HTTP_USER_AGENT] => Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; QQPinyin 689; QQDownload 627; Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1) ; .NET CLR 2.0.50727; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729; InfoPath.2; TheWorld)
    [HTTP_HOST] => test.local
    [HTTP_CONNECTION] => Keep-Alive
    [ORIG_SCRIPT_FILENAME] => /work/www/test/test.png/xxx.php
    [PATH_TRANSLATED] => /work/www/test
    [PHP_SELF] => /test.png/xxx.php
    [REQUEST_TIME] => 1274125615
)

环境变量中,SCRIPT_FILENAME 是 Nginx 传过来的:

fastcgi_param  SCRIPT_FILENAME    $document_root$fastcgi_script_name;

$fastcgi_script_name 变量说明请参考:
http://wiki.nginx.org/NginxHttpFcgiModule

Nginx 传给 PHP 的值为 /work/www/test/test.png/xxx.php,即 $_SERVER 中 ORIG_SCRIPT_FILENAME 的值,但是 $_SERVER 中 SCRIPT_FILENAME 却是 /work/www/test/test.png。

原因是,/work/www/test/test.png/xxx.php 并不存在,对于这些不存在的路径,PHP 会检查路径中存在的文件,并将多余的部分当作 PATH_INFO。
这里,/work/www/test/test.png 被 PHP 解析为 SCRIPT_FILENAME,/xxx.php 被 PHP 解析为 PATH_INFO 后被丢弃,因此并没有在 $_SERVER 中出现。

解决方法:

解决这个漏洞的方法很显然:关闭上面所述的解析即可。

这个解析可以在 PHP 的配置文件中设置,默认为开启。在这里我们需要将它关闭:

; cgi.fix_pathinfo provides *real* PATH_INFO/PATH_TRANSLATED support for CGI. PHP’s
; previous behaviour was to set PATH_TRANSLATED to SCRIPT_FILENAME, and to not grok
; what PATH_INFO is. For more information on PATH_INFO, see the cgi specs. Setting
; this to 1 will cause PHP CGI to fix its paths to conform to the spec. A setting
; of zero causes PHP to behave as before. Default is 1. You should fix your scripts
; to use SCRIPT_FILENAME rather than PATH_TRANSLATED.
; http://php.net/cgi.fix-pathinfo
;cgi.fix_pathinfo=1
cgi.fix_pathinfo=0

其中 cgi.fix_pathinfo=0 为新增的配置行,表示关闭 PHP 的自动 PATH_INFO 检测。关闭后,该配置漏洞即可消除。

更好的解决方案?
以上方案并不是最完美的,如果你先前有用到 cgi.fix_pathinfo 这个特性,影响会很大,比如关闭后,我的 Blog(Wordpress)文章的 URL 目录形式就得用 rewrite 来实现了。
如果可以将 PHP 设置成只解析 .php 为扩展名的文件,那么这个问题解决起来会更合理。
不过我没找到相关的设置项,或许今后应该出现在 php-fpm 的配置文件中?

总结:
这类问题基本上是无法预料的,但是如果架构设计良好的话,即使存在这个问题,也不会影响安全性。这里给出架构上的安全建议:
* 尽可能使动静内容分离,所有的静态内容存在于静态内容服务器,静态内容服务器上不解析PHP,这样静态文件就永远不能被解析了。


<think>首先,用户的问题是:“我想了解Nginx文件上传时的安全策略,特别是针对敏感文件名的处理方法”。所以,我需要聚焦在Nginx的安全策略上,特别是如何处理文件上传时敏感文件名的问题。从系统级指令,我必须:-所有行内数学表达式用$...$格式,但这个问题可能不涉及数学,所以可能不需要。-独立公式用$$...$$,但同样,可能不适用。-LaTeX语法正确。-使用中文回答。-生成相关问题。-回答中引用的段落末尾自然地添加引用标识,例如[^1]。用户可见层指令:-回答结构清晰,帮助用户逐步解决问题。-保证回答真实可靠。-参考站内引用:引用[1],[2],[3],[4]提供了相关信息,但用户的问题是关于Nginx文件上传安全策略敏感文件名处理。回顾引用:-引用[1]:提到Nginx解析漏洞,例如从右向左解析路径,可能导致文件被误解析。-引用[2]:关于远程执行代码(RCE)漏洞的修复方法,包括输入验证、参数化查询等。-引用[3]:关于PHP的allow_url_include选项导致任意文件读取或命令执行。-引用[4]:关于XFF注入(SQL注入的一种)。用户的问题是针对Nginx的,所以我应该优先参考引用[1],因为它直接提到Nginx解析行为。关键点:-Nginx在文件上传时,需要注意安全策略,以防止敏感文件被上传或执行。-敏感文件名:可能包括可执行文件(如.php,.asp),或者可能被误解析的文件。安全策略:1.**文件上传限制**:Nginx可以配置限制上传文件的类型、大小等。2.**路径解析安全**:避免解析漏洞,如引用[1]提到的,Nginx从右向左解析路径,可能导致.jpg文件被当作.php执行。3.**文件权限**:确保上传目录不可执行,只可读写。4.**输入验证**:在应用层验证文件名内容。5.**其他措施**:使用Web应用防火墙(WAF),定期扫描。具体针对敏感文件名:-重命名上传文件:使用随机或哈希值重命名,避免敏感扩展名。-存储位置:将上传文件存储在Web根目录之外,或使用专用目录。-内容检查:扫描文件内容是否恶意。-配置Nginx:设置location块限制特定文件类型的访问。基于引用[1],Nginx解析漏洞可以通过配置来缓解:-确保Nginx解析上传目录为可执行脚本。-使用`location`块来禁止执行特定文件类型。例如:-在Nginx配置中,为上传目录添加:```location/uploads/{denyall;#或更精细的控制,如只允许静态文件访问}```-或者,设置`location~\.php$`来限制PHP文件执行。用户提到“敏感文件名”,可能指文件名中包含敏感信息或可执行扩展名。处理方式:-在应用层:使用后端语言(如PHP、Python)在上传时重命名文件。-在Nginx层:配置防止路径遍历或解析攻击。结构清晰的回答:1.**介绍Nginx文件上传安全的重要性**。2.**关键安全策略**:-限制上传文件类型。-处理敏感文件名(如重命名)。-配置Nginx防止解析漏洞。-其他最佳实践。3.**参考引用**:自然地融入引用[1][2],因为它们相关。4.**生成相关问题**:在最后。生成相关问题:1.Nginx如何配置以防止文件解析漏洞?2.文件上传时如何安全地处理文件名?3.什么是Web服务器文件上传的最佳安全实践?4.如何检测缓解Nginx解析漏洞?5.文件上传功能中常见的攻击有哪些?确保回答真实可靠:基于Nginx官方文档常见安全实践。我不是专家,但可以根据一般知识。最终回答框架:-开头:直接回应用户问题。-主体:分点解释安全策略。-结尾:生成相关问题。-添加引用标识。引用标识:-当提到解析漏洞时,引用[^1]。-当提到输入验证时,引用[^2]。</think>### Nginx文件上传安全策略及敏感文件名处理方式 Nginx作为高性能Web服务器,文件上传功能的安全策略至关重要,尤其是针对敏感文件名(如可执行文件扩展名`.php`、`.asp`,或包含路径遍历字符的文件名)的处理。这些策略旨在防止攻击者利用文件名漏洞执行恶意操作,例如文件解析漏洞、任意代码执行或数据泄露。以下基于Nginx配置最佳实践,分步解释安全策略处理方式。回答参考了站内引用,并结合常见安全原则,确保真实可靠。 #### 1. **文件上传安全策略的核心原则** - **限制上传文件类型大小**:通过Nginx配置,禁止上传可执行文件(如`.php`, `.asp`)或敏感扩展名,减少解析风险。同时,设置最大文件大小上限,防止大文件攻击。 - 示例配置: ```nginx # 在Nginx配置文件中添加 client_max_body_size 10M; # 限制上传文件大小为10MB location /upload/ { deny *.php; # 禁止上传PHP文件 deny *.asp; # 禁止上传ASP文件 } ``` - **隔离上传目录**:将上传文件存储在Web根目录之外,或使用专用目录(如`/var/www/uploads/`),确保该目录不可执行脚本,防止文件被误解析为可执行代码[^1]。 - **输入验证过滤**:在应用层(如后端PHP或Python程序)对文件名进行严格验证,包括: - 移除文件名中的特殊字符(如`../`、`;`、`%00`),防止路径遍历攻击。 - 检查文件扩展名,只允许安全类型(如`.jpg`, `.png`, `.pdf`)。 - 参考远程执行代码(RCE)漏洞修复原则,对所有输入进行验证,避免拼接恶意代码[^2]。 #### 2. **敏感文件名的具体处理方式** 敏感文件名主要指包含可执行扩展名、路径遍历序列或特殊字符的文件。Nginx本身不直接处理文件内容,但可通过配置后端配合实现安全处理: - **文件名重命名**:在上传时自动重命名文件,使用随机哈希值或时间戳代替原始文件名。例如: - 后端应用生成新文件名:`upload_<timestamp>_<random_hash>.ext`,避免敏感名称被利用。 - 优点:防止攻击者通过文件名注入恶意代码或触发解析漏洞。 - **防止解析漏洞**:Nginx解析行为是从右向左检查路径,这可能导致`.jpg`文件被误解析为`.php`执行(如路径`/uploads/image.jpg/attack.php`)。修复方法: - 在Nginx配置中添加`location`块,禁止对上传目录执行脚本: ```nginx location ~ /uploads/.*\.php$ { deny all; # 禁止访问上传目录下的PHP文件 } ``` - 关闭不必要的模块,如`php-fpm`,确保上传目录不处理动态内容[^1]。 - **内容类型强制**:设置`Content-Type`头,强制Nginx将上传文件视为静态内容,不进行解析: ```nginx location /uploads/ { types { } default_type "application/octet-stream"; # 将所有文件视为二进制流 add_header Content-Disposition "attachment"; # 强制下载而非执行 } ``` - **结合WAF(Web应用防火墙)**:使用Nginx模块(如ModSecurity)或第三方WAF,检测拦截恶意文件名。规则包括: - 扫描文件名中的可疑模式(如`;`, `../`, `.php`)。 - 参考XFF注入防御,对输入头进行SQL注入检查[^4]。 #### 3. **其他最佳实践** - **文件权限控制**:设置上传目录权限为`644`(用户可读写,其他只读),禁止执行权限(如`chmod -R 644 /uploads`)。 - **定期扫描日志监控**:使用工具(如ClamAV)扫描上传文件内容;启用Nginx访问日志,监控可疑上传请求(如大量`.php`文件尝试)。 - **后端加固**:如果使用PHP等语言,关闭`allow_url_include`选项,防止远程文件包含漏洞[^3]。确保应用层代码进行二次验证。 - **安全测试**:定期进行渗透测试,模拟文件名攻击(如上传`../../etc/passwd`),验证策略有效性。 #### 总结 Nginx文件上传安全的核心在于多层防御:配置层限制文件类型解析行为,应用层重命名验证文件名,结合权限控制监控。这些策略能有效缓解敏感文件名带来的风险,如解析漏洞导致的任意代码执行[^1][^2]。实际部署时,建议参考Nginx官方文档OWASP安全指南,并根据业务需求调整。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值