Nginx站点隔离防跨站入侵教程
Nginx站点隔离防跨站入侵设置教程,新手也能搞定
跨站入侵指的是同一台服务器上某个站点被入侵后,攻击者利用系统漏洞读取或篡改其他站点的文件。
对使用Nginx+PHP的建站环境来说,做好站点隔离就能有效阻断这种横向扩散。
本文的步骤完全面向零基础用户,你只需SSH连上服务器,复制命令执行即可。
准备工作
开始操作前,请确认以下条件:
- 你拥有服务器的root或sudo权限。
- Nginx和PHP-FPM已经安装且正常运行。
- 至少有两个站点(例如 example.com 和 test.com),方便后续验证隔离效果。
- 建议先备份现有配置:
cp /etc/nginx/nginx.conf /etc/nginx/nginx.conf.bak
第一步:为每个站点分配独立的操作系统用户
默认情况下,Nginx 的 worker 进程通常以 www-data 或 nginx 用户运行,所有站点共用一个用户,一个站点被入侵就能访问其他站点的文件。
最佳实践是为每个站点创建独立的系统用户和组。
执行以下命令创建用户和组(以站点 example.com 为例):
sudo useradd -m -s /bin/false nginx_example
sudo groupadd nginx_example
sudo usermod -a -G nginx_example nginx_example
然后将站点根目录的所有权改为此用户:
sudo chown -R nginx_example:nginx_example /var/www/example.com
sudo chmod 750 /var/www/example.com
解释:useradd -m创建用户主目录,-s /bin/false禁止该用户登录,只用于文件权限。chmod 750表示所有者可读写执行,同组可读执行,其他人无权限。
第二步:修改PHP-FPM池配置,绑定用户
每个站点使用独立的PHP-FPM pool,并指定为用户本身。
编辑PHP-FPM的pool配置文件(通常位于 /etc/php/*/fpm/pool.d/),创建或修改对应站点的配置文件。
例如建立 example.conf,内容如下:
[example]
user = nginx_example
group = nginx_example
listen = /run/php/php8.1-fpm-example.sock
listen.owner = www-data
listen.group = www-data
listen.mode = 0660
pm = dynamic
pm.max_children = 5
pm.start_servers = 2
pm.min_spare_servers = 1
pm.max_spare_servers = 3
注意:listen使用Unix socket时,要保证Nginx能访问。这里监听socket文件的所有者是www-data(Nginx运行用户),权限0660让Nginx和PHP-FPM双方可读写。
修改完成后重启PHP-FPM:
sudo systemctl restart php8.1-fpm # 请根据你的PHP版本调整
第三步:配置Nginx站点,使用独立PHP-FPM socket
编辑Nginx的站点配置(例如 /etc/nginx/sites-available/example.com),
修改 location ~ \.php$ 块,
使用对应的socket:
location ~ \.php$ {
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/run/php/php8.1-fpm-example.sock;
}
同时设置站点根目录的 root 和 index。
整个配置大致如下:
server {
listen 80;
server_name example.com;
root /var/www/example.com;
index index.php index.html;
location / {
try_files $uri $uri/ =404;
}
location ~ \.php$ {
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/run/php/php8.1-fpm-example.sock;
}
}
检查配置并重载Nginx:
sudo nginx -t
sudo systemctl reload nginx
第四步:开启PHP open_basedir 限制(双重保险)
单纯靠用户隔离还不够,攻击者可能利用 file_get_contents() 等函数访问系统文件。
PHP内置的 open_basedir 可以限制脚本能访问的目录范围。
在PHP-FPM pool配置中(同一个 pool 文件),添加:
php_admin_value[open_basedir] = /var/www/example.com/:/tmp/
说明:这表示PHP脚本只能访问/var/www/example.com/和/tmp/目录,无法读取其他站点的文件或系统敏感目录。注意:/tmp/前面的冒号是分隔多个目录。
然后重启PHP-FPM:
sudo systemctl restart php8.1-fpm
第五步:额外限制Nginx目录穿越
有些情况下,攻击者可能利用Nginx的别名或路径配置漏洞访问上级目录。
建议在 server 块中增加以下规则:
# 禁止访问 . 开头的文件(如 .git .env)
location ~ /\. {
deny all;
}
# 禁止直接访问保留文件
location ~ /(README|LICENSE|CHANGELOG) {
deny all;
}
同时确保 root 指令不包含可猜测的路径。
重启Nginx即可。
避坑指南(新手常见错误)
- 不要只改Nginx用户:如果PHP-FPM仍然以
www-data运行,站点隔离效果几乎为零。必须同时改PHP-FPM pool的用户。 - open_basedir 写错路径:检查路径末尾是否有斜杠,多目录用冒号分隔,不要用分号。
- 忘记给 socket 文件正确权限:如果Nginx用户无法读取socket,站点会报502错误。记得
listen.mode = 0660且listen.owner/group设置为Nginx运行用户。 - 测试前清空浏览器缓存:有时候旧的PHP进程缓存会导致权限检查不生效。
效果验证
在每个站点的根目录下创建一个测试文件 test.php:
通过浏览器分别访问两个站点的 test.php,如果都输出“无法访问其他站点文件”,说明隔离成功。
你还可以尝试 open_basedir 测试:在脚本中加入 phpinfo();,查看 open_basedir 的值是否只包含本站目录和 /tmp/。
常见问题
Q:我的服务器上站点很多,每个建一个用户太麻烦,有快速方法吗?
A:可以使用脚本批量创建,但数量超过几十个时建议使用容器或虚拟化方案,比如 Docker 或 LXC,隔离更彻底。
Q:开启 open_basedir 后,网站报错“open_basedir restriction in effect”。
A:说明脚本访问了限制以外的路径,请在 open_basedir 中添加所需的目录(例如文件上传目录 /var/www/example.com/uploads,或 :/tmp/)。
Q:Nginx 站点配置里 fastcgi_param 用不用改?
A:主要依赖上面几步,fastcgi_param 通常不需要手动修改,但注意保留默认的 SCRIPT_FILENAME 等参数。
如果你正在配置多站点环境,建议先按照本文步骤完成所有站点的隔离,再投入使用。
遇到报错时先回看避坑部分,通常能解决七成问题。
想要进一步了解Nginx安全配置,可以查阅官方文档或站内相关教程。