nginx无法全面阻断webshell,但可拦截80%以上常见行为:封死入口路径(如location ^~ /.php { return 404; })、禁用高危扩展名与隐藏文件、阻断系统路径暴露、拦截工具指纹及异常参数,并严格校验配置优先级与匹配规则。

直接结论:Nginx 无法“全面阻断 Webshell”,但能用几条轻量、可落地的规则,拦住 80% 以上的常见 Webshell 访问行为——关键不是识别脚本内容,而是封死它的**入口路径、执行条件和暴露方式**。
禁止直接请求 .php 等敏感后缀文件
很多 Webshell(如 shell.php、cmd.php)被上传后,攻击者会直接浏览器访问它。Nginx 默认若没配 PHP 处理逻辑,可能把它当静态文件返回源码;即使配了,也可能被畸形路径绕过(如 /.phpinfo、/config.php/123)。
- 在
server块顶部加高优先级前缀匹配:location ^~ /.php { return 404; }它比正则更早触发,能拦截/.php?c=system('id')这类扫描器常用路径 - 再补一条正则规则,覆盖常规请求:
location ~ \.php$ { try_files $uri =404; fastcgi_pass 127.0.0.1:9000; }注意必须带try_files,否则/config.php可能跳过 deny 直接进 fastcgi - 别只写
deny all——对 PHP 文件,return 404或try_files ... =404更可靠,避免因配置顺序错位导致失效
封禁高危扩展名与隐藏文件
Webshell 常用扩展名远不止 .php,且喜欢用大小写混淆、空字节、双扩展绕过。Nginx 本身不解析 URL 编码或处理空字节,所以规则必须预处理。
- 用
~*(忽略大小写)匹配常见危险后缀:location ~* \.(php|phtml|php3|php4|php5|phar|jsp|jspx|asp|aspx|pl|py|sh|env|log|conf|bak|swp|yml|yaml|htaccess)$ { deny all; } - 单独封禁点开头的隐藏文件和目录(
.git、.svn、.env):location ~ /\. { deny all; } location ~ ^/(.git|.svn|.hg|.project|composer.json|package.json)$ { deny all; }注意^/锚定根路径,避免误杀/api/v1.git这类正常接口 - 不要依赖单一黑名单——攻击者传
shell.php.jpg时,Nginx 按后缀匹配会放过。真正有效的做法是:业务上传接口统一用独立location,只允许白名单类型(如image/jpeg),并限制client_max_body_size不超过 2MB
拦截系统路径与配置文件暴露
有些 Webshell 会尝试读取 /etc/passwd、/proc/self/environ 或 Nginx 自身配置(如 /nginx.conf),这往往源于 root/alias 配置错误或目录遍历漏洞。
- 在
http或server块中显式拒绝敏感路径:location ~ ^/(etc|usr|var/log|proc|sys|root|boot|dev)/ { deny all; } location = /nginx.conf { deny all; } location ^~ /etc/nginx/ { deny all; } - 检查所有
root和alias指令是否指向 Web 根目录外的位置,例如alias /etc/nginx/;是高危配置,必须删掉 - 确认
autoindex off;已全局关闭,否则目录遍历成功后可能列出文件名,为后续攻击提供线索
阻断 Webshell 工具指纹与异常参数
AntSword、Behinder、Godzilla 等工具发包时会在请求头或参数里留下固定痕迹,Nginx 可以低成本拦截这类已知模式。
- 用
if匹配 User-Agent:if ($http_user_agent ~* "(antSword|behinder|godzilla|sqlmap|dirbuster)") { return 403; }注意:该语句只能放在server或location块内,不能在http块顶层用 - 检查常见 Webshell 参数名(如
cmd、exec、eval、assert)出现在 query string 中:if ($args ~* "(cmd|exec|system|passthru|eval|assert|base64_decode|file_put_contents)=.*") { return 403; }慎用:过度匹配可能误杀正常业务参数(如 CMS 的?cmd=login),建议先日志记录再逐步收紧 - 更稳妥的做法是配合 OpenResty + Lua,在请求体解析阶段做更精细判断,但普通 Nginx 编译默认不带 Lua 支持,上线前需确认环境
最易被忽略的一点:所有这些规则都依赖 Nginx 配置加载顺序和匹配优先级。把 deny 规则写在 location / 后面,或者没加 ^~ / ~* 修饰符,就等于没写。每次改完务必 nginx -t && nginx -s reload,再用 curl -v http://host/shell.php 和 curl -v http://host/.git/config 实测是否真返回 403/404。











