普通视图

发现新文章,点击刷新页面。
今天 — 2025年8月18日首页

nginx 如何配置防止慢速攻击 🤔🤔🤔

作者 Moment
2025年8月18日 09:01

最近在出一个前端的体系课程,里面的内容非常详细,如果你感兴趣,可以加我 v 进行联系 yunmz777:

image.png

浪费你几秒钟时间,内容正式开始

慢速攻击是一类用很少带宽就能长期占用服务器连接/资源的攻击方式。攻击者通过非常慢地发送请求头或请求体,或极慢地读取服务器响应,让每个连接都“挂着不结束”,从而耗尽 Web 服务器(或上游应用、数据库、代理)的并发与缓冲资源。

典型类型主要有以下几个方面:

  • Slowloris(慢请求头):客户端以极低速率分片发送 HTTP 头部,始终不把头部发完,服务器就一直等待。

  • Slow POST / RUDY(慢请求体):先宣称要上传较大的 Content-Length,然后以极慢速率发送请求体,服务器为其保留缓冲与上游连接。

  • Slow Read(慢读取响应):客户端窗口/读取速率极低,迫使服务器缓冲并保持连接很久(尤其响应较大时)。

  • HTTP/2 变种:滥用单连接多流(streams)和窗口控制:开很多流但每流都很慢,放大资源占用。

20250818085811

传统 DDoS 依靠高带宽与高包速直接压垮网络/设备,而慢速攻击用极低带宽长期占用连接,更隐蔽,常被误认为是网络状况差的正常用户。

现场通常会看到活跃连接(尤其 reading)持续攀升,但总体带宽并不高。

error_log 中频繁出现 client timed outclient sent invalid header while reading client request headers 等信息。

上游服务看似空闲却体验发卡,Nginx 的 429/502/504 增多,访问日志还能发现同一 IP 维持大量长期未完成的请求或异常长的响应时间。

  • 429 表示“请求过多被限流”,通常稍后或按 Retry-After 重试即可。

  • 502 表示“网关收到上游无效响应或连不上上游”,多见于上游挂掉、拒连或协议不匹配。

  • 504 表示“等待上游超时”,通常是上游处理太慢一直没回。

如何防护

核心目标就是尽快关闭拖延发送请求头/请求体或极慢读取响应的连接,限制单 IP 的并发与速率,避免慢连接占满 workerworker_connections 与上游资源。

  • 收紧超时:client_header_timeoutclient_body_timeoutsend_timeoutkeepalive_timeout

  • 超时立刻复位:reset_timedout_connection on; 减少 TIME_WAIT/ 资源滞留。

  • 限并发/限速:limit_connlimit_req(必要时返回 429 并带 Retry-After)。

  • HTTP/2 参数:降低 http2_max_concurrent_streams,设置 http2_recv_timeout/http2_idle_timeout

  • 反向代理场景:proxy_request_buffering on; 先把请求缓冲到 Nginx,避免慢上传占住上游。

  • 分路径/分人群:对登录、搜索等接口更严;对可信源/健康检查放宽或白名单。

  • 边缘清洗:结合 CDN/WAF 的连接层/应用层限速更稳。

一些相关的配置可以参考下面的 Nginx 配置:

worker_processes auto;

events {
    worker_connections  4096;
    multi_accept        on;
}

http {
    # 1) 关键超时(防慢头/慢体/慢读)
    client_header_timeout  5s;   # 等头部时间
    client_body_timeout    10s;  # 等请求体每个读周期的时间
    send_timeout           10s;  # 发送响应给客户端每个写周期的时间
    keepalive_timeout      10s;  # keep-alive 连接空闲时间
    keepalive_requests     100;  # 单连接最大请求数,防长时间占用

    # 2) 连接超时直接复位(释放资源更快)
    reset_timedout_connection on;

    # 3) 并发限制(每 IP)
    #    10m 可容纳 ~160k 键(基于 $binary_remote_addr)
    limit_conn_zone $binary_remote_addr zone=perip:10m;

    # 4) 速率限制(每 IP),按需调大/调小 rate
    limit_req_zone  $binary_remote_addr zone=req_perip:10m rate=10r/s;

    # 5) HTTP/2 专项(若开启了 http2)
    http2_max_concurrent_streams 64; # 降并发流数
    http2_recv_timeout           5s; # 接收客户端帧超时
    http2_idle_timeout          10s; # HTTP/2 空闲超时

    # 6) 合理的头部缓冲(避免过大内存占用;默认已够用,按需微调)
    large_client_header_buffers 4 8k;

    server {
        listen 443 ssl http2;
        server_name example.com;

        # 并发/速率在 server 层生效
        limit_conn       perip 20;        # 每 IP 并发连接上限
        limit_conn_status 429;

        limit_req        zone=req_perip burst=20 nodelay;  # 短突发
        limit_req_status 429;

        # 限制请求体大小(配合 body_timeout 可更快淘汰异常大/慢上传)
        client_max_body_size 10m;

        # 【反向代理站点强烈推荐】先把完整请求缓冲到 Nginx
        # 避免上游被慢上传拖住连接
        location / {
            proxy_pass http://app_backend;
            proxy_request_buffering on;

            proxy_connect_timeout  3s;
            proxy_send_timeout    10s;  # 向上游发送(写)超时
            proxy_read_timeout    30s;  # 自上游读取(读)超时
        }

        # 对静态资源可放宽速率限制以提升体验(示例)
        location ~* \.(?:css|js|png|jpg|jpeg|gif|webp|ico|svg)$ {
            root /var/www/html;
            access_log off;
            expires 30d;
        }

        # 自定义 429 页面(可选)
        error_page 429 /429.html;
        location = /429.html { internal; return 429 "Too Many Requests\n"; }
    }
}

除此之外,还有一些数值上的建议:

  1. 高频 API 可将 rate 调小、burst 适度放大;页面类流量可相反。

  2. 对上传较多的业务,将 client_body_timeoutproxy_request_buffering on; 组合尤为关键。

  3. 如果公网复杂、遭遇中等强度慢攻:client_header_timeout 2-3sclient_body_timeout 5-8ssend_timeout 8-10s 往往更稳。

考虑到移动网络或跨境访问确实可能很慢,限流需要在防护与容错间取平衡。可以适度调大 burst,并返回合理的 Retry-After,让偶发拥塞得以通过。把严格策略仅应用在登录、搜索等敏感接口,对静态资源和页面流量适当放宽。对可信来源(如办公网、监控、合作方)设置白名单或更高配额,尽量减少误杀。

之于上面的理解,我们可以针对不同慢速攻击的做不同的优化了:

  • Slowloris(慢头部):用 client_header_timeout 严控请求头收齐时间,配合较短的 keepalive_timeout 降低长连驻留,并用 limit_conn 限制每 IP 并发;一旦超时,借助 reset_timedout_connection on; 立即复位断开。

  • RUDY / Slow POST(慢体):设置较短的 client_body_timeout,并开启 proxy_request_buffering on; 先在 Nginx 缓冲请求体,慢上传直接在边缘被淘汰且不上游;必要时配合 client_max_body_size 约束体积。

  • Slow Read(客户端读超慢):通过 send_timeout 限制客户端读取过慢的连接,触发即复位释放缓冲;若是 SSE/长轮询等合法长连,为对应路径单独放宽 send_timeout,避免误伤。

20250818085955

总结

慢速攻击是用极低带宽长期占用服务器连接/缓冲的攻击:攻击者故意慢发请求头/请求体或慢读响应,让连接一直不结束,耗尽并发与内存。

常见形态有 Slowloris(慢头部)、RUDY/Slow POST(慢请求体)与 Slow Read(慢读响应),在 HTTP/2 下还能通过多流+窗口控制放大影响。

典型症状是活跃连接(尤其 reading)持续升高但总体带宽不高,日志频繁出现超时/异常头部,且 429/502/504 增多、同一 IP 大量长时间未完成请求。

防护要点是收紧超时(client_header/body/send/keepalive)、开启 reset_timedout_connection、用 limit_conn/limit_req 控制每 IP 并发与速率,反向代理时启用 proxy_request_buffering on; 并调优 HTTP/2;同时对敏感路径更严、对可信来源适度放宽或白名单以减少误杀。

昨天以前首页

源码安装 Nginx 并加载第三方模块指南

作者 子洋
2025年8月12日 08:23

Nginx 安装

一、安装所需依赖

sudo apt-get install build-essential libpcre3 libpcre3-dev zlib1g zlib1g-dev libssl-dev perl libperl-dev libxslt-dev

这些依赖是编译 nginx 以及可选模块(如 gzip、ssl、perl、xslt 等)所需要的。

  • build-essential:提供 gccmake 等基本编译工具
  • libpcre3libpcre3-dev:支持正则表达式处理
  • zlib1gzlib1g-dev:提供对 gzip 压缩的支持
  • libssl-dev:启用 https 所需
  • perllibperl-dev:为 http_perl_module 模块准备
  • libxslt-dev:支持 http_xslt_module

二、下载 Nginx 源码包

你可以访问官网 nginx.org/en/download… 查找最新版本号。以下以 1.28.0 为例:

wget http://nginx.org/download/nginx-1.28.0.tar.gz 
tar -zxvf nginx-1.28.0.tar.gz 
cd nginx-1.28.0

注意:

优先使用稳定版(Stable version),主线版本(Mainline version)虽然有新特性但风险更高,你可以替换 <version> 来下载其他版本。

三、执行 ./configure 配置构建参数

在源码编译中,./configure 是最关键的一步,负责:

  • 定义 nginx 的路径结构(配置路径、pid 路径、日志路径等)
  • 决定是否开启模块(比如:gzip、ssl、http_v2 等)
  • 设置编译优化参数(cc-opt, ld-opt

以下为参考 Ubuntu 官方包构建方式的参数(移除了部分不需要的模块):

./configure \
  # 编译器优化参数(调试符号、路径映射、防御编译策略等)
  --with-cc-opt='-g -O2 -Werror=implicit-function-declaration -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer -ffile-prefix-map=/build/nginx-lUDsEK/nginx-1.26.3=. -flto=auto -ffat-lto-objects -fstack-protector-strong -fstack-clash-protection -Wformat -Werror=format-security -mbranch-protection=standard -fdebug-prefix-map=/build/nginx-lUDsEK/nginx-1.26.3=/usr/src/nginx-1.26.3-2ubuntu1.1 -fPIC -Wdate-time -D_FORTIFY_SOURCE=3' \
  --with-ld-opt='-Wl,-Bsymbolic-functions -flto=auto -ffat-lto-objects -Wl,-z,relro -Wl,-z,now -fPIC' \

  # 基础路径配置
  --prefix=/usr/share/nginx \
  --sbin-path=/usr/sbin \
  --conf-path=/etc/nginx/nginx.conf \
  --http-log-path=/var/log/nginx/access.log \
  --error-log-path=stderr \
  --lock-path=/var/lock/nginx.lock \
  --pid-path=/run/nginx.pid \
  --modules-path=/usr/lib/nginx/modules \

  # 临时文件目录配置
  --http-client-body-temp-path=/var/lib/nginx/body \
  --http-fastcgi-temp-path=/var/lib/nginx/fastcgi \
  --http-proxy-temp-path=/var/lib/nginx/proxy \
  --http-scgi-temp-path=/var/lib/nginx/scgi \
  --http-uwsgi-temp-path=/var/lib/nginx/uwsgi \

  # 核心特性
  --with-compat \        # 支持动态模块加载
  --with-debug \         # 启用调试模式
  --with-pcre-jit \      # 提升正则匹配性能
  --with-threads \       # 启用多线程支持

  # HTTP 模块
  --with-http_ssl_module \
  --with-http_stub_status_module \
  --with-http_realip_module \
  --with-http_auth_request_module \
  --with-http_v2_module \
  --with-http_v3_module \
  --with-http_dav_module \
  --with-http_slice_module \
  --with-http_addition_module \
  --with-http_flv_module \
  --with-http_gunzip_module \
  --with-http_gzip_static_module \
  --with-http_mp4_module \
  --with-http_random_index_module \
  --with-http_secure_link_module \
  --with-http_sub_module \

  # Mail & Stream 模块
  --with-mail=dynamic \
  --with-mail_ssl_module \
  --with-stream=dynamic \
  --with-stream_ssl_module \
  --with-stream_ssl_preread_module \
  --with-stream_realip_module \

  # 可选动态模块
  --with-http_perl_module=dynamic \
  --with-http_xslt_module=dynamic

注意:

如果想使用上面的构建参数命令,需要删除所有的注释换行,否则运行会报错。

在官网构建参数的基础上移除了以下模块(因为还需要额外添加依赖,有需要自己安装即可):

--with-http_image_filter_module=dynamic
--with-http_geoip_module=dynamic
--with-stream_geoip_module=dynamic

运行成功如下图所示:

四、构建与安装

# 创建 nginx 运行需要的目录`
mkdir -p /var/lib/nginx/

# 编译
make -j$(nproc)

# 安装到指定路径
sudo make install

运行 Nginx 服务

在执行 ./configure 时,可以通过指定 --sbin-path=/usr/sbin 参数来设置 nginx 可执行文件的安装路径,从而使系统能够全局调用 nginx 命令(无需额外配置 PATH)。

如果在构建时未指定该参数,默认情况下 nginx 可执行文件会被安装到 ./objs/nginx 中。此时你可以手动将其复制到系统可执行目录:

sudo cp objs/nginx /usr/sbin/

检测配置文件是否正确:

nginx -t

启动 nginx:

nginx

测试是否启动成功:

curl 127.0.0.1

查看完整的构建参数:

nginx -V 2>&1 | awk -F: '/configure arguments/ {print $2}' | xargs -n1

加载第三方模块

Nginx 支持两种模块集成方式:

1. 编译时静态集成

./configure --add-module=模块路径

2. 动态模块

./configure --add-dynamic-module=模块路径

动态模块 .so 需要通过 load_module 在配置文件中显式加载。

集成 echo-nginx-module

echo-nginx-module 是由 OpenResty 团队开发的调试模块,可在配置文件中直接返回文本、变量等内容,适合用于测试、演示、调试。

方法一:静态编译进 nginx

# 下载源码
git clone https://github.com/openresty/echo-nginx-module.git
# 执行编译配置
./configure --add-module=./echo-nginx-module
# 先关掉 nginx 服务
nginx -s quit
# 编译并安装
make && sudo make install

编译并安装后,修改 nginx.conf 配置文件:

worker_processes  1;
events {
    worker_connections  1024;
}

http {
  include       mime.types;
  default_type  application/octet-stream;
  sendfile        on;
  keepalive_timeout  65;

  server {
    listen 8080;

    location / {
      add_header Content-Type text/html;
      echo "Hello, this is the echo module! Cureent Time: $time_local";
    }
  }
}

重启 Nginx 后访问 http://127.0.0.1:8080,将看到如下输出:

方法二:构建为动态模块(.so)

Nginx 1.9.11+ 开始支持 --add-dynamic-module,生成 .so 文件,在运行时通过 load_module 加载。

./configure --add-dynamic-module=./echo-nginx-module
make && sudo make install

找到 objs/ngx_http_echo_module.so,并移动到 nginx 模块目录:

sudo cp objs/ngx_http_echo_module.so /usr/lib/nginx/modules/

修改配置文件,在文件首行添加模块加载语句:

load_module /usr/lib/nginx/modules/ngx_http_echo_module.so;

worker_processes  1;
events {
    worker_connections  1024;
}

http {
  include       mime.types;
  default_type  application/octet-stream;
  sendfile        on;
  keepalive_timeout  65;

  server {
    listen 8080;

    location / {
      add_header Content-Type text/html;
      echo "Hello, this is the echo module! Cureent Time: $time_local";
    }
  }
}

重新加载配置后即可访问:

nginx -s reload

相关链接

nginx代理如何配置和如何踩到坑篇

2025年8月11日 17:33

一、需求场景

在 web 页面渲染并操作真机。

二、研发过程

通过websocket获取到H.264视频流数据后,需通过浏览器提供的VideoDecoder方法对其进行解码然后渲染在canvas上操作真机(也就是操作画布)。

三、注意事项

VideoDecoder API(属于 WebCodecs API)仅在 HTTPS 协议或本地开发环境。

四、本地nginx代理,配置自签证书,实现本地https协议访问

1、配置如下:在nginx.bat和nginx.exe同级别下,有一个conf文件夹 image.png

2、conf文件夹下有nginx.conf配置文件,此配置文件中未写主要代理地址,而是在此文件中,将需要加载的.conf内容指向了同级别下的vhost中的所有的.conf文件

worker_processes 1;
worker_rlimit_nofile 65535;
pid logs/nginx.pid;

events {
    worker_connections 1024;
}

http {
    include       mime.types;
    include       vhost/*.conf;  # 包含所有vhost下的配置文件
    
    # WebSocket支持
    map $http_upgrade $connection_upgrade {
        default upgrade;
        '' close;
    }

    default_type  application/octet-stream;
    
    # 其他原有配置保持不变...
}

3、配置解释:

include 指令

-   用于将外部文件的内容动态加载到当前 Nginx 配置中,类似于“合并”文件内容。
-   目的是让配置更清晰、模块化,避免主配置文件(如 `nginx.conf`)过于臃肿。

vhost/*.conf 路径

-   `vhost/` 是目录名(通常存放虚拟主机配置)。
-   `*.conf` 表示匹配该目录下所有以 `.conf` 结尾的文件。
-   例如:`vhost/example.com.conf``vhost/blog.conf` 等文件都会被加载。

4、vhost下的自定义名称.conf文件,https-443.conf

1754901863889.jpg

配置文件的内容:

server {
    listen 443 ssl; # https协议监听443端口
    server_name localhost; # 这里是代理后的访问地址

    # SSL证书配置(请确认路径正确),配置的自签证书
    ssl_certificate D:/nginx-1.16.1/conf/cert/6107996__eversaas.cn.pem;
    ssl_certificate_key D:/nginx-1.16.1/conf/cert/6107996__eversaas.cn.key;
    
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4;
    ssl_prefer_server_ciphers on;
    ssl_session_cache shared:SSL:10m;
    ssl_session_timeout 10m;

    location / {
        proxy_pass http://localhost:8080; #这是本地前端代码起的服务地址,表示访问https://localhost:443代理到此地址展示前端页面
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto https;
    }

    location /ws {
        proxy_pass http://192.168.111.222:5000; # 这里表示将/ws的开头的请求都代理到此地址
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-Proto https;
    }
    location /pcap {
        proxy_pass http://192.168.66.99:5500; # 这里表示将/pcap的开头的请求都代理到此地址
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-Proto https;
    }
    location /action {
        proxy_pass http://192.168.88.22:5000; # 这里表示将/action的开头的请求都代理到此地址
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-Proto https;
    }
}

5、配置完成之后保存,然后打开nginx.bat,选择对应序号重启nginx。

此时nginx进程已经跑起来了,不出意外访问 https://localhsot (这里默认443端口),会直接代理出来你的前端页面。

image.png

五、我踩的坑来了,前提是我在之前配置过这个nginx.conf,启动过nginx进程,本次修改了ws代理地址

我访问https://localshot 这里可以代理出来我的前端页面,但是配置的nginx转发未生效,真机页面无法渲染,/pcap和/action都没有数据。

此时在nginx.exe下,文件地址栏输入powershell

image.png

1.执行:tasklist /fi "imagename eq nginx.exe" 查看我的nginx进程

image.png

发现除了我新启动的两个进程外还有两个进程,那么我先尝试关闭所有进程。

2.执行:taskkill /f /im nginx.exe 关闭所有nginx进程

image.png

此时发现有两个权限不足导致未能关闭的进程。

3.右击电脑左下角windows图标, 打开Power Shell(管理员)(A),再次关闭所有进程

image.png

可以看到之前的两个因为权限不足未关闭的进程被关闭了,此时我访问https://localshsot 直接访问不出来了,发现问题所在了吗?

其实我的代理一直走的是我之前在Power Shell(管理员)(A)中启动后一直未关闭的nginx进程,而非我修改nginx.conf配置之后重启的nginx进程,由于使用的还是之前的nginx进程,我的配置文件又改了且没重启nginx,所以代理肯定不能正确转发。

此时再打开nginx.bat,选择对应序号启动nginx,此时使用的才是新启动的nginx进程,真机正确展示。

总结:不要在两个面板中(例如Power Shell(管理员)(A)和Power Shell(l))用同一个配置文件启动nginx进程,容易混淆具体使用的是那个进程,并且记得使用完之后关闭进程。

❌
❌