在Windows Server上跑Nginx做反向代理,很多人配置完HTTPS转发就觉得万事大吉了。实际上默认配置在公网上跑不出三天,日志里就会挤满各种扫描探测和恶意利用的请求。安全调优不是锦上添花,而是上线前的必要步骤。下面直接讲具体问题怎么解决,每一项都能立刻落地。

隐藏Nginx版本号和服务器标识

默认情况下,Nginx返回的错误页面和HTTP响应头里会带着具体的版本号,比如Server: nginx/1.24.0。攻击者拿到版本号后,可以针对该版本的已知漏洞进行精准打击。在nginx.confhttp块里加上server_tokens off;就能隐藏版本号,但这还不够,响应头里仍然会显示Server: nginx。要进一步修改或隐藏这个字段,需要借助ngx_http_headers_module模块,在配置中直接覆盖:

http {
    server_tokens off;
    more_clear_headers "Server";
    add_header Server "WINDOWS-SERVER" always;
}

注意more_clear_headers需要额外编译headers-more-nginx-module模块,如果用的是官方预编译的Windows版本没有这个模块,可以直接在nginx.conf里用proxy_pass_headerproxy_hide_header组合来控制后端透传的头部信息,至少做到不暴露真实后端服务器类型。

限制请求速率和并发连接数

Windows服务器最怕的就是资源耗尽型攻击。Nginx在Windows上使用的是基于select的事件模型,不像Linux下的epoll那样高效,大量并发连接会迅速拖垮系统。必须做两层限制:一是单个IP的请求速率,二是单个IP的并发连接数。在http块里定义限制区域:

http {
    limit_req_zone $binary_remote_addr zone=req_limit:10m rate=30r/s;
    limit_conn_zone $binary_remote_addr zone=conn_limit:10m;
    
    server {
        location / {
            limit_req zone=req_limit burst=10 nodelay;
            limit_conn conn_limit 10;
            proxy_pass http://backend;
        }
    }
}

这里rate=30r/s表示每秒允许30个请求,burst=10是突发容量,nodelay表示超出部分立即返回503而不是排队。并发连接限制设为10,对于一般的企业站点足够了。如果某个子目录是API接口或者登录入口,可以单独设置更严格的限制,比如登录接口每秒只允许3次请求,能有效阻止暴力破解。

配置合理的超时参数

Windows上Nginx的默认超时设置偏长,容易被慢速攻击利用。慢速攻击的原理是客户端故意以极慢的速度发送请求,占用服务器连接资源。需要在httpserver块里收紧几个关键超时:

http {
    client_body_timeout 10s;
    client_header_timeout 10s;
    send_timeout 10s;
    keepalive_timeout 30s;
    proxy_connect_timeout 10s;
    proxy_read_timeout 30s;
    proxy_send_timeout 30s;
}

client_body_timeoutclient_header_timeout分别控制读取请求体和请求头的超时时间,设为10秒意味着如果客户端在10秒内没有发送完数据,连接就会被断开。keepalive_timeout控制长连接保持时间,30秒对大多数场景都合理。后端代理的超时也要收紧,避免某个慢响应后端拖住所有工作进程。

限制请求体大小和请求头大小

不限制请求体大小,攻击者上传一个大文件就能把后端服务的内存撑爆。在httpserver块里设置:

http {
    client_max_body_size 20m;
    client_body_buffer_size 128k;
    large_client_header_buffers 4 16k;
}

client_max_body_size 20m限制请求体最大20MB,根据业务实际需求调整,如果是文件上传服务可以单独给上传接口设置更大的值。large_client_header_buffers限制请求头的大小和数量,防止有人发送超长的Cookie或者自定义头部来触发缓冲区溢出。

启用HTTPS并强制使用现代加密套件

反向代理作为流量入口,TLS配置直接决定了整个站点的传输安全。在Windows上配置SSL证书后,需要在server块里禁用过时的协议和弱加密算法:

server {
    listen 443 ssl http2;
    ssl_certificate     cert/server.crt;
    ssl_certificate_key cert/server.key;
    
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers 'ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256';
    ssl_prefer_server_ciphers on;
    ssl_session_cache shared:SSL:10m;
    ssl_session_timeout 10m;
    
    add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;
}

这里只启用了TLS 1.2和1.3,彻底关闭了TLS 1.0和1.1以及所有SSL协议。加密套件只保留支持前向保密的高强度算法。Strict-Transport-Security头部告诉浏览器在接下来两年里只通过HTTPS访问该站点,能有效防止SSL剥离攻击。如果站点还有HTTP入口,务必做一个全局重定向:

server {
    listen 80;
    server_name yourdomain.com;
    return 301 https://$host$request_uri;
}
配置安全响应头

反向代理是添加安全响应头的最佳位置,可以统一为所有后端服务加上防护层。在server块里集中添加以下头部:

add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-XSS-Protection "1; mode=block" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header Permissions-Policy "geolocation=(), microphone=(), camera=()" always;

X-Frame-Options防止站点被嵌入到iframe中,杜绝点击劫持。X-Content-Type-Options禁止浏览器对响应内容类型进行猜测,防止MIME类型嗅探攻击。X-XSS-Protection启用浏览器内置的XSS过滤器。Referrer-Policy控制跨域请求时Referer信息的携带策略。Permissions-Policy则直接禁用掉不需要的浏览器特性权限。这些头部加在反向代理层,后端应用即使有疏漏也能被兜底防护。

过滤恶意请求和非法HTTP方法

公网上每天都有大量扫描器在探测不安全的HTTP方法,比如TRACETRACKDELETE等。如果后端应用不需要这些方法,直接在Nginx层拦截:

server {
    location / {
        if ($request_method !~ ^(GET|POST|HEAD|OPTIONS)$) {
            return 405;
        }
        proxy_pass http://backend;
    }
}

更进一步,可以针对常见的漏洞扫描路径直接返回404或444(直接关闭连接,不返回任何响应)。在server块里添加精确匹配规则:

location ~* (\.php|\.asp|\.aspx|\.jsp|wp-admin|wp-login|\.env|\.git) {
    return 444;
}

这条规则匹配所有对PHP、ASP、JSP文件以及WordPress后台、环境变量文件、Git目录的请求,直接关闭连接。因为你的后端可能根本不是这些技术栈,扫描器扫这些路径就是在浪费资源。返回444比返回403更好,因为攻击者收不到任何响应,无法判断这个路径是否真实存在。

限制后端访问来源IP

如果反向代理和后端服务部署在同一台Windows服务器上,或者后端服务器只应该接收来自Nginx的请求,那必须在Nginx配置里做IP白名单。在location块里使用allowdeny指令:

location / {
    allow 127.0.0.1;
    allow 10.0.0.0/8;
    allow 172.16.0.0/12;
    allow 192.168.0.0/16;
    deny all;
    proxy_pass http://backend;
}

同时在后端服务(比如IIS、Tomcat、Node.js进程)的绑定地址上,只监听127.0.0.1而不是0.0.0.0,这样即使有人绕过了防火墙,也无法从外网直接访问后端端口。Windows防火墙里也要把后端服务的端口(比如8080、3000)的入站规则限制为仅本地子网。

配置日志审计和异常监控

安全配置做完之后,必须有手段验证效果并及时发现攻击行为。Nginx的日志格式可以自定义,建议把以下关键字段都记录下来:

http {
    log_format security '$remote_addr - $remote_user [$time_local] '
                        '"$request" $status $body_bytes_sent '
                        '"$http_referer" "$http_user_agent" '
                        '$request_time $upstream_response_time '
                        '$http_x_forwarded_for $ssl_protocol $ssl_cipher';
    
    access_log logs/access.log security;
    error_log logs/error.log warn;
}

这个日志格式包含了客户端真实IP、请求耗时、上游响应时间、转发IP链、SSL协议版本和加密套件。Windows上可以用PowerShell脚本定时解析日志,统计状态码分布和异常IP。比如统计返回444最多的IP:

Get-Content "C:\nginx\logs\access.log" | Select-String " 444 " | 
    ForEach-Object { ($_ -split " ")[0] } | Group-Object | 
    Sort-Object Count -Descending | Select-Object -First 20

把这些IP加入Windows防火墙的入站阻止规则,实现自动化封禁。Nginx本身没有动态封禁功能,但在Windows上可以配合计划任务和PowerShell脚本实现简单的自动防御。

进程权限最小化

Windows上安装Nginx时,默认可能以SYSTEM或者管理员权限运行。一旦Nginx工作进程被攻破,攻击者就拿到了最高系统权限。必须创建一个专用的低权限用户来运行Nginx。在Windows服务管理器里找到Nginx服务,在“登录”选项卡里指定一个新建的本地用户,该用户只赋予Nginx安装目录和日志目录的读写权限,其他系统目录一概拒绝访问。同时确保Nginx的worker_processes配置与CPU核心数匹配,在Windows上不建议设置auto,手动指定为实际核心数即可,避免进程数过多造成上下文切换开销。

禁用不必要的模块和目录列表

Nginx编译时会包含很多模块,但实际用到的可能只有http_proxyhttp_sslhttp_rewrite等几个核心模块。Windows上虽然不能像Linux那样灵活裁剪编译,但可以通过配置关闭不需要的功能。比如关闭目录列表:

http {
    autoindex off;
}

如果某个location是静态文件目录,确实需要列出文件,再单独开启。另外,确保没有配置root指向敏感目录,alias指令的使用也要谨慎检查路径穿越风险。

定期更新和基线检查

Windows上的Nginx更新不像Linux那样可以通过包管理器一键完成,需要手动下载新版本、停止服务、替换文件、重启服务。建议把Nginx的安装目录纳入文件完整性监控,用Windows自带的审计策略记录对Nginx目录的所有修改操作。每次配置变更后,先用nginx -t测试配置语法,确认无误后再重载。建立一个配置基线文档,记录所有安全相关的配置项及其当前值,每次变更都做版本对比。

把这些配置项全部落地之后,用curl或者浏览器开发者工具逐项验证响应头是否生效,用压力测试工具验证限流是否正常工作,用SSL测试工具验证TLS配置评分。安全调优不是一次性工作,攻击手法在进化,Nginx版本在更新,业务需求在变化,每个季度至少做一次配置复查和加固。