# 访问控制

# 关于拒绝访问

# allow 、deny

:允许、禁止某些 IP 地址的访问。

  • 可用范围:http、server、location、limit_except
  • 例:
    deny    192.168.1.1;       # 禁止一个 IP
    allow   192.168.1.0/24;    # 允许一个网段
    deny    all;               # 禁止所有 IP
    allow   all;
    
  • 收到客户端的 HTTP 请求时,Nginx 会从上到下检查访问规则,采用第一条与客户端 IP 匹配的规则。
  • 如果客户端被禁止访问,则返回响应报文:403 Forbidden

# auth_basic

:用于启用 HTTP Basic Auth 。

  • 可用范围:http、server、location
  • 例:
    auth_basic              "";                 # 设置 realm 。默认为 off ,禁用认证
    auth_basic_user_file    /etc/nginx/passwd;  # 使用哪个密码文件
    
    • 密码文件用于保存一组用户名、哈希密码,可通过 htpasswd 命令生成。

# auth_delay

:当客户端认证失败时,延迟一段时间再作出响应。

  • 可用范围:http、server、location
  • 默认值:
    auth_delay 0s;
    
  • 可以与 auth_basic 等认证措施搭配使用,避免暴力破解,不过客户端依然会保持 TCP 连接,占用资源。

# limit_except

:只允许接收指定的 HTTP 请求方法,对其它方法做出限制(通过 deny 限制)。

  • 可用范围:location
  • 例:
    location / {
        limit_except GET POST {
            deny    all;
        }
    }
    
  • 允许 GET 方法时也会允许 HEAD 方法。

# satisfy

:如果 ngx_http_access_module、ngx_http_auth_basic_module、ngx_http_auth_request_module、ngx_http_auth_jwt_module 模块都允许访问(或任一允许),则最终允许访问。

  • 可用范围:http、server、location
  • 语法:
    satisfy all | any;
    
  • 默认值:
    satisfy all;
    

# 关于限流

# limit_rate

:用于限制响应报文的传输速率,单位为 Bytes/s 。

  • 可用范围:http、server、location
  • 例:
    location /www/ {
        limit_rate  10k;
    }
    
  • 默认值为 0 ,表示不限制。

# limit_req

:用于限制每个客户端 IP 在一段时间内的请求数。

  • 可用范围:http、server、location
  • 例:
    http {
        # 创建一个 zone ,以 binary_remote_addr 作为限流的 key
        # zone  :创建一个指定大小的共享内存区域,用于记录 key 信息
        # rate  :限制速率。例如 10r/s 表示每秒 10 个请求,10r/m 表示每分钟 10 个请求
        limit_req_zone $binary_remote_addr zone=perip:10m rate=10r/s;
        # 创建一个 zone ,以 server_name 作为限流的 key
        limit_req_zone $server_name zone=perserver:10m rate=100r/s;
    
        server {
            location / {
                proxy_pass http://10.0.0.1;
                limit_req zone=perip;       # 采用 zone ,限制每个 IP 地址的请求数
                limit_req zone=perserver;
                # burst 队列的长度默认为 0 ,启用它有利于处理客户端的突发大量请求
                # limit_req zone=perip burst=20 nodelay;
    
                # limit_req_status 503;
                # limit_req_log_level error;
            }
        }
    }
    
    • rate 不支持小数,且实际工作时会转换成每 100ms 的平均阈值。例如:
      • 如果配置 rate=10r/m ,则实际限制为每 6s 最多 1 个请求。
        • 如果再配置 burst=10 nodelay ,则允许 6s 内完成 11 个请求,然后每等待 6s 还可完成一个新请求。
      • 如果配置 rate=1r/m ,则实际限制为每 1m 最多 1 个请求。
      • 如果配置 rate=10r/s ,则实际限制为每 100ms 最多 1 个请求。
    • limit_req 采用漏斗算法(leaky bucket):
      • 每 100ms 为一个处理周期。如果当前周期内,收到的请求数超过 rate 限制,则将请求放入称为 burst 的 FIFO 队列中。
        • 每隔一个周期,从队列中取出请求,正常处理。
        • 如果队列溢出,则拒绝新请求:返回 limit_req_status 状态码,并记录报错日志:limiting requests, excess 0.340 by zone "perip" ,其中 excess = 根据当前请求估测的每毫秒请求数 - 平均每毫秒允许的 rate 。
      • 启用 nodelay 策略时,会将超过 rate 限制的请求立即处理,同时将 burst 队列中相应数量的槽位标记为已占用。每隔一个周期,尝试释放一次槽位。
    • 以 binary_remote_addr 作为限流的 key 时,每个 key 需要 128bytes 来存储状态信息,因此 10MB 内存可以记录 8W 个 key 。
      • 每次记录一个新 key 时,会尝试删除两个最近 60s 未使用的 key 。
      • 如果 zone 内存耗尽,也会拒绝新请求。

# limit_conn

:用于限制每个客户端 IP 同时进行的并发连接数。

  • 可用范围:http、server、location
    http {
        limit_conn_zone $binary_remote_addr zone=perip:10m;
        limit_conn_zone $server_name zone=perserver:10m;
    
        server {
            location / {
                proxy_pass http://10.0.0.1;
                limit_conn perip 10;        # 采用 zone ,限制每个 IP 地址的并发连接数
                limit_conn perserver 100;
    
                # limit_conn_status 503;
                # limit_conn_log_level error;
            }
        }
    }
    
    • 当 Nginx 读取完请求的 Headers 之后,才会将该请求计入并发连接数。
    • 以 binary_remote_addr 作为限流的 key 时,每个 key 需要 64bytes 来存储状态信息,因此 10MB 内存可以记录 16W 个 key 。