Nginx功能篇15—安全防护

概述

本章,您将学习到如何加强 Nginx 的安全防护,主要涉及到这样几部分的内容:

  • 访问控制 - 省略,已在 前面的文档 中说明
  • 安全头部
  • 防 DDoS 攻击

安全头部

安全头部(Security Headers):属于 HTTP 响应头的一部分,用于指示浏览器如何安全地处理网页内容。通过在主配置文件中配置安全头部,可减少潜在的安全风险。

常见的安全头部包括:

  • X-Frame-Options - 防止网站被嵌入到第三方 iframe 中,有效抵御点击劫持攻击,常用值为 SAMEORIGIN(仅允许同源嵌入)或 DENY(完全禁止嵌入)
  • X-Content-Type-Options - 禁用浏览器的 MIME 类型嗅探行为,避免浏览器把文本类文件误解析为可执行脚本,大幅降低上传文件被恶意利用的风险
  • X-XSS-Protection - 启用浏览器内置的 XSS 防护机制,当检测到跨站脚本攻击 (XSS) 时,浏览器将停止加载页面
  • Referrer-Policy - 控制跨站请求时 Referer 字段的发送规则
  • Permissions-Policy - 限制浏览器对摄像头、麦克风、地理位置等硬件功能的访问权限,禁止非授权的功能调用
  • ‌Strict-Transport-Security - 强制使用 HTTPS 而不是 HTTP 进行通信
  • Content-Security-Policy - 通过白名单机制明确指定浏览器允许加载资源的来源,防止 XSS 攻击

相关的指令为 add_header,语法为 add_header name value [always];,通常会配置在 server 上下文中。关于安全头部更加详细的说明,可参阅 这里

配置示例:

...
http {
    ...

    # 80 端口的 server 上下文
    server {
        listen 192.168.100.20:80;
        server_name www.my-tests.com;

        return 301 https://www.my-tests.com$request_uri;
    }

    # 443 端口的 server 上下文
    server {
        listen 192.168.100.20:443 ssl http2 backlog=8000 reuseport;
        server_name www.my-tests.com;

        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 "camera=(), microphone=(), geolocation=(self)" always;
        add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;

        # 这里可以先不配置,或者根据实际的业务情况做调整
        add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; object-src 'none'; frame-ancestors 'self'; base-uri 'self';" always;

        # SSL/TLS 证书方面的配置
        ...

        # 一个或多个 location 上下文的配置
        location / {
            ...
        }
        ...
    }
}

当在 nginx.conf 中配置完成后可执行以下操作:

# 先验证语法后再启动 Nginx 程序
Shell > /usr/local/nginx/sbin/nginx -t && /usr/local/nginx/sbin/nginx

# 查看所有的响应头是否正常返回
Shell > curl -I https://www.my-tests.com

防 DDoS 攻击

DDoS 攻击:DDoS(Distributed Denial of Service,分布式拒绝服务)是一种常见的网络攻击手段,攻击者通过控制分布在不同地理位置的联网设备向目标服务器发送海量伪造请求或垃圾请求,耗尽其系统资源与带宽,使其无法正常响应合法用户的请求。

说明
当联网设备感染特定恶意软件后,就可能被攻击者控制。被控制的联网设备俗称 "肉鸡" 或 "傀儡机",大量 "肉鸡" 组成的网络被称为 "僵尸网络" 。

目前已知的公开可查的最大 DDoS 流量峰值为 29.7 Tbps,由名为 "Aisuru" 的僵尸网络在 2025 年第三季度发起,该记录由 Cloudflare 在其 Q3 2025 DDoS 威胁报告中正式披露。

在 Nginx 中,系统管理员可通过以下的方式来抵御 DDoS 的攻击:

  • 限制单个 IP 地址的连接数
  • 限制单个 IP 地址的请求速率
  • 限制单个 IP 地址的带宽
  • 限制单个 IP 地址对特定 location 的访问
  • 对客户端的请求做调整
  • 限制 HTTP 方法
  • 调整访问日志的写入频率

这些方式可组合使用,但是需要注意的是,单台 Nginx 的 DDos 防护能力是有其局限性以及上限的:对于中小规模的 DDoS 攻击(流量峰值在 10 Gbps 及以下)可以抵御,但难以抵御 Tbps 级别的超大规模攻击。

限制单个 IP 地址的连接数

使用的是 ngx_http_limit_conn_module 模块,相关指令有:

  • limit_conn_zone 指令 - 定义一个共享内存区域来存储连接数的状态,语法为 limit_conn_zone key zone=name:size;,只能配置在 http 上下文中
  • limit_conn 指令 - 在特定 location 中限制连接数,语法为 limit_conn zone number;

示例配置:

...
http {
    ...
    # $binary_remote_addr 表示客户端的 IP 地址
    # zone=addr:10m 表示分配 10M 共享内存大小来存储连接数状态
    limit_conn_zone $binary_remote_addr zone=addr:10m;

    server {
        ...
        location / {
            ...
            # 每个 IP 地址只能有 10 个并发连接数
            limit_conn addr 10;
            ...
        }
    }
}

限制单个 IP 地址的请求速率

使用的是 ngx_http_limit_req_module 模块,相关指令有:

  • limit_req_zone 指令 - 定义一个共享内存区域来存储请求速率的状态,语法为 limit_req_zone key zone=name:size rate=rate [sync];,只能配置在 http 上下文中
  • limit_req 指令 - 在特定 location 中对速率进行限制,语法为 limit_req zone=name [burst=number] [nodelay | delay=number];

示例配置:

...
http {
    ...
    # $binary_remote_addr 表示客户端的 IP 地址
    # zone=req_limit:10m 表示分配 10M 共享内存大小来存储请求速率状态
    # rate=10r/s 表示每秒允许 10 个 HTTP 请求
    limit_req_zone $binary_remote_addr zone=req_limit:10m rate=10r/s;

    server {
        ...
        location / {
            ...
            # 允许突发 20 个 HTTP 请求排队等待,若超过,则直接拒绝并立刻返回 503 状态码
            limit_req zone=req_limit burst=20 nodelay;
            ...
        }
    }
}

限制单个 IP 地址的带宽

主要与浏览器下载资源相关。使用的是 ngx_http_core_module 模块,相关指令有:

  • limit_rate 指令 - 限制单个 TCP 连接的传输速率,语法为 limit_rate rate;,默认为 limit_rate 0;。速率单位可以是:

    • k 或 K - 表示 KB/s
    • m 或 M - 表示 MB/s
    • g 或 G - 表示 GB/s
    • 不书写单位 - 默认表示为 bytes/s‌

    单位之间的进制为 1024 ,如 1k=1024 bytes/s‌

  • limit_rate_after 指令 - 多少大小之前不限制传输速率,超过后则执行 limit_rate 指令所定义的传输速率限制,语法为 limit_rate_after size;,默认为 limit_rate_after 0;

示例配置:

...
http {
    ...
    limit_rate 100k;
    limit_rate_after 2m;

    server {
        ...
        location / {
            ...
        }
    }
}

限制单个 IP 地址对特定 location 的访问

可对一些比较重要的 uri 采取限制,比如登陆、API、上传、备份等:

...
http {
    ...
    limit_req_zone $binary_remote_addr zone=req:10m rate=10r/s;
    limit_conn_zone $binary_remote_addr zone=conn:10m;

    server {
        ...
        location /login/ {
            ...
            limit_req zone=req burst=5 nodelay;
            limit_conn conn 3;
        }

        location /api/ {
            ...
            limit_req zone=req burst=10 nodelay;
        }

        location /upload/ {
            ...
            limit_conn conn 2;
            # 限制文件上传的大小为 10 兆
            client_max_body_size 10m;
            # 上传的超时时间
            client_body_timeout 60s;
        }

        location /backup/ {
            ...
            limit_req zone=req burst=2 nodelay;
            limit_conn conn 1;
        }
    }
}

对客户端的请求做调整

...
http {
    ...
    # 客户端请求头读取超时(防止慢速攻击)
    client_header_timeout 10s;

    # 客户端请求体读取超时
    client_body_timeout 10s;

    # 发送响应超时
    send_timeout 10s;

    # 长连接超时时间
    keepalive_timeout 15s;

    # 客户端请求头缓冲区大小(防止缓冲区溢出攻击)
    client_header_buffer_size 1k;
    large_client_header_buffers 4 8k;

    # 客户端请求体最大大小
    client_max_body_size 10m;

    server {
        ...
        location / {
            ...
        }
    }
}

限制 HTTP 方法

...
http {
    ...
    server {
        ...
        # 如果请求方法不是 GET、POST和 HEAD,返回 405 状态码
        if ($request_method !~ ^(GET|POST|HEAD)$ ) {
            return 405;
        }

        location / {
            ...
        }

        ...
    }
}

调整访问日志的写入频率

可定义一些日志参数,提高访问日志的写入性能,如:

...
error_log  logs/error.log  error;
...
http {
    ...
    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';
    ...

    # 80 端口的 server 上下文
    server {
        listen 192.168.100.20:80;
        server_name www.my-tests.com;
        # 重定向跳转配置
        return 301 https://www.my-tests.com$request_uri;
    }

    # 443 端口的 server 上下文
    server {
        listen 192.168.100.20:443 ssl http2 backlog=8000 reuseport;
        server_name www.my-tests.com;

        access_log  logs/tests-https-access.log  main buffer=64k flush=5s;

        ...

        location / {
            ...
        }
        ...
    }
}

默认情况下,Nginx 每处理一个请求都会立即调用系统 write() 接口将日志写入到磁盘。但在高并发场景下,这种 "每条日志都写入一次到磁盘的操作" 会导致出现大量的随机 I/O,影响性能。启用 buffer 和 flush 后,即延迟写入日志记录,具体流程为:

  • 日志记录会先写入到内存中一块固定大小的区域,也就是 buffer 指定的大小
  • 满足以下的任一条件,Nginx 都会将缓冲区中的日志记录一次性批量写入到磁盘

    • buffer 指定的大小被填满
    • 距离上次写入磁盘的时间超过了 flush 指定的时间
    • Worker 进程退出或重新载入配置

参数说明:

  • buffer 参数 - 为每个 Worker 进程分配一块 64 KB 大小的缓冲区域,用于暂存日志记录
  • flush 参数 - 缓冲区最长驻留时间
Avatar photo

关于 陸風睿

GNU/Linux 从业者、开源爱好者、技术钻研者,撰写文档既是兴趣也是工作内容之一。Q - "281957576";WeChat - "jiulongxiaotianci",Github - https://github.com/jimcat8
用一杯咖啡支持我们,我们的每一篇[文档]都经过实际操作和精心打磨,而不是简单地从网上复制粘贴。期间投入了大量心血,只为能够真正帮助到您。
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇