Chapter 09

安全与访问控制

Nginx 站在最前线,是拦截恶意流量的第一道闸门。限流、访问控制、认证、防盗链与加固,构成一套实用的入口防护。

9.1 核心概念

限流(Rate Limiting)
限制单位时间内某来源的请求数,抵御暴力破解、爬虫、CC 攻击。Nginx 用漏桶算法平滑放行。
limit_req
基于请求速率的限流,如"每 IP 每秒最多 10 个请求"。用 limit_req_zone 定义规则,limit_req 应用。
limit_conn
限制单个来源的并发连接数,防止一个客户端占用过多连接(如慢速攻击、大量下载)。
allow / deny
基于 IP/网段的黑白名单,按顺序匹配,先中先决。常用于把管理后台限制到公司 IP。
Basic Auth
HTTP 基本认证,用用户名密码保护路径。密码存在 htpasswd 文件里,简单但仅在 HTTPS 下才安全。
防盗链(Hotlink Protection)
校验请求的 Referer 头,阻止其他站点直接盗用你的图片/视频,节省带宽。

9.2 请求限流 limit_req

http {
    # 定义限流区:按客户端 IP,每秒 10 个请求,占 10MB 内存
    limit_req_zone  $binary_remote_addr  zone=api_limit:10m  rate=10r/s;

    server {
        location /api/ {
            # burst 允许瞬时突发 20 个,nodelay 不排队直接放行
            limit_req  zone=api_limit  burst=20  nodelay;
            limit_req_status  429;   # 超限返回 429 Too Many Requests
            proxy_pass  http://backend;
        }
    }
}
burst 与 nodelay 的含义

rate=10r/s 是稳态速率;burst=20 是允许排队的突发缓冲。不加 nodelay 时超出速率的请求会被延迟放行(平滑但慢);加 nodelay 时突发内的请求立即处理、超过 burst 才拒绝。真实站点几乎都用 nodelay。

9.3 连接数限流 limit_conn

http {
    limit_conn_zone  $binary_remote_addr  zone=conn_limit:10m;

    server {
        # 单 IP 最多 10 个并发连接
        limit_conn  conn_limit  10;

        location /download/ {
            # 限制下载带宽,防单用户拖垮出口
            limit_rate  1m;   # 每连接 1MB/s
        }
    }
}

9.4 IP 黑白名单

# 管理后台只允许公司出口 IP
location /admin/ {
    allow  203.0.113.0/24;
    allow  198.51.100.7;
    deny   all;               # 其余全部拒绝
    proxy_pass  http://backend;
}

# 封禁已知恶意 IP
location / {
    deny  192.0.2.66;
    allow all;
}
反代后要看真实 IP

如果 Nginx 前面还有 CDN/LB,$remote_addr 是上游代理的 IP,allow/deny 会失效。需要配置 set_real_ip_from + real_ip_header X-Forwarded-For,让 Nginx 从可信代理头里还原真实客户端 IP,再做限流和黑白名单。

9.5 Basic Auth

# 生成密码文件
$ sudo apt install apache2-utils
$ sudo htpasswd -c /etc/nginx/.htpasswd  admin
location /internal/ {
    auth_basic  "Restricted Area";
    auth_basic_user_file  /etc/nginx/.htpasswd;
    proxy_pass  http://backend;
}
Basic Auth 必须配 HTTPS

Basic Auth 把用户名密码用 Base64(不是加密)放在请求头里。在 HTTP 明文下等于裸奔,任何中间人都能解出密码。它只是"简单挡一下"的手段,务必在 HTTPS 之上使用,且不要用于真正敏感的系统。

9.6 防盗链

location ~* \.(jpg|jpeg|png|gif|mp4)$ {
    # 只允许本站和搜索引擎引用;none 允许直接访问(无 Referer)
    valid_referers  none  blocked  example.com  *.example.com;
    if ($invalid_referer) {
        return  403;
    }
}

9.7 隐藏版本号与常见加固

http {
    server_tokens  off;   # 响应头/错误页不显示 Nginx 版本

    # 限制请求体大小,防超大 body 攻击
    client_max_body_size  10m;
    # 限制请求头缓冲,防慢速头攻击
    large_client_header_buffers  4  8k;

    server {
        # 只允许安全的 HTTP 方法
        if ($request_method !~ ^(GET|HEAD|POST)$) {
            return  405;
        }

        # 禁止访问隐藏文件(.git / .env 等)
        location ~ /\.(?!well-known) {
            deny  all;
        }
    }
}

9.8 安全加固清单

做法
隐藏版本server_tokens off;
只用现代 TLSssl_protocols TLSv1.2 TLSv1.3;
安全响应头HSTS / X-Frame-Options / X-Content-Type-Options / CSP
限流登录、API 加 limit_req;全局 limit_conn
请求体上限client_max_body_size 按业务设
隐藏文件拒绝 .git / .env / .htpasswd
后台白名单/admin 只放公司 IP + Basic Auth
真实 IPCDN 后配 real_ip 还原客户端 IP

9.9 小结与下一步