Nginx Http 模块介绍(中)
在前面介绍完 post-read、server-rewrite、find-con、rewrite 和 post-rewrite 阶段后,我们将继续学习 preaccess 和 access 两个阶段,中间会涉及部分模块,一同进行说明。
1. preaccess 阶段
在 preaccess 阶段在 access 阶段之前,主要是限制的请求,比如并发连接数(limit_conn模块)和每秒请求数(limit_req 模块)等。这两个模块对于预防一些攻击请求是很有效的。
ngx_http_limit_conn_module 模块限制单个 ip 的建立连接的个数,该模块内有 6 个指令。分别如下:
limit_conn_zone: 该指令主要的作用就是分配共享内存。 下面的指令格式中 key 定义键,这个 key 往往取客户端的真实 ip,zone=name 定义区域,后面的 limit_conn 指令会用到的。size 定义各个键共享内存空间大小;
: limit_conn_zone key zone=name:size;Default: —Context: http
limit_conn_status: 对于连接拒绝的请求,返回设置的状态码,认是 503;
: limit_conn_status code;Default: limit_conn_status 503;Context: http, server, location
limit_conn: 该指令实际限制请求的并发连接数。指令指定每个给定键值的最大同时连接数,当超过这个数字时被返回 503 (认,可以由指令 limit_conn_status 设置);
: limit_conn zone number;Default: —Context: http, server, location
limit_conn_log_level: 当达到最大限制连接数后,记录日志的等级;
: limit_conn_log_level info | notice | warn | error;Default: limit_conn_log_level error;Context: http, server, location
limit_conn_dry_run: 这个指令是 1.17.6 版本中才出现的,用于设置演习模式。个模式中,连接数不受限制。但是在共享内存的区域中,过多的连接数也会照常处理。
: limit_conn_dry_run on | off;Default: limit_conn_dry_run off;Context: http, server, location
limit_zone: 该指令已弃用,由 limit_conn_zone 代替,不再进行说明。
实例
http {...limit_conn_zone $binary_remote_addr zone=addr:10mserver {...location / {limit_conn_status ;limit_conn_log_level warn;# 限制向返回的速度,每秒50个字节limit_rate ;limit_conn addr ;}}}
ngx_http_limit_req_module 模块主要用于处理突发流量,它基于漏斗算法将突发的流量限定为恒定的流量。如果请求容量没有超出设定的极限,后续的突发请求的响应会变慢,而对于超过容量的请求,则会立即返回 503(认)。
该模块模块中比较重要的指令有:
limit_req_zone 指令,定义共享内存, key 关键字以及限制速率
: limit_req_zone key zone=name:size rate=rate [sync];Default: —Context: http
limit_req 指令,限制并发连接数
: limit_req zone=name [burst=number] [nodelay | delay=number];Default: —Context: http, server, location
limit_req_log_level 指令,设置服务拒绝请求发生时打印的日志级别
: limit_req_log_level info | notice | warn | error;Default:limit_req_log_level error;Context: http, server, location
limit_req_status 指令, 设置服务拒绝请求发生时返回状态码
: limit_req_status code;Default: limit_req_status 503;Context: http, server, location
2. access 阶段
在 access 阶段,我们可以通 allow 和 deny 指令来允许和拒绝某些 ip 的访问权限,指令的如下:
: allow address | CIDR | unix: | all;Default: —Context: http, server, location, limit_except: deny address | CIDR | unix: | all;Default: —Context: http, server, location, limit_except
实例
allow 和 deny 指令后面可以跟具体 ip 地址,也可以跟 ip 段, 或者所有(all)。
location / {deny .;allow ./;allow ./;allow :0db8::/;deny all;}
auth_basic 模块是基于 HTTP Basic Authentication 协议进行和密码的认证,它认是编译进 中的,可以在源码编译阶段通过 --without-http_auth_basic_module 禁用该模块。它的如下:
: auth_basic string | off;# 认是的Default: auth_basic off;Context: http, server, location, limit_except: auth_basic_user_file file;Default: —Context: http, server, location, limit_except
对于使用保存和密码,二者之间需用冒号隔开,如下所示。
# commentname1:password1 name2:password2:comment name3:password3
在 centos 系统上,想要这样的密码,我们可以使用 httpd-tools 工具完成,直接使用 yum install
安装即可。
$ sudo yum install httpd-tools# 密码user_file,帐号为user,密码为pass$ htpasswd -bc user_file user pass
接下来,我们只需要配置好 auth_basic 指令,即可对相应的 http 请求做好认证工作。
第三方的访问控制是用到了auth_request模块,该模块的是向上游服务转发请求,如果上游服务返回的相应码是 2xx,则通过认证,继续向;若返回的 401 或者 ,则将响应返回给客户端。
auth_request 模块认是未编译进 中的,因此我们需要使用 --with-http_auth_reques_module
将该模块编译进 中,然后我们才能使用该模块。
: auth_request uri | off;Default: auth_request off;Context: http, server, location: auth_request_set $variable value;Default: —Context: http, server, location
官方示例:
location /private/ {auth_request /auth;...}location = /auth {# 上游认证服务地址proxy_pass ...proxy_pass_request_body off;proxy_set_header Content-Length "";proxy_set_header X-Original-URI $request_uri;}
3. 实验
本次案例将使用 limit_conn 模块中的指令完成限速实验。实验配置块如下:
...http {...# 没有这个会报错,必须要定义共享内存limit_conn_zone $binary_remote_addr zone=addr:10m;...server {server_name localhost;listen ;location / { limit_rate ; limit_conn addr ;}}...}...
使用 limit_rate 指令用于限制 相应速度,每秒返回 50 个字节,然后是限制并发数为 2,这样方便展示。当我们打开浏览器请求该端口下的根路径时,由于相应会比较慢,迅速打开另窗口请求同样的地址,会发现再次请求时,正好达到了同时并发数为 2,启动限制,第二个窗口返回 503 (认)。
访问第一次
访问第二次
我们做简单的示例,配置如下。在 /root/test/web 下有 web1.html 和 web2.html 两个。访问/web1.html 时,使用 allow all指令将所有来源的 ip 请求全部放过(当然也可以不写);使用 deny all 会拒绝所有,所以访问 /web2.htm l时,会出现 的报错。
server { server_name access.test.com; listen ; root /root/test/web; location /web1.html { default_type text/html; allow all; # return 200 'access'; } location /web2.html { default_type text/html; deny all; # return 200 'deny'; }}
访问允许的 web1.html
访问的 web2.html
大家可以思考下,如果使用的是 return 指令呢,会有怎样的结果?打开注释,重新加载 后,可以看到无论是访问 /web1.html 还是 /web2.html,我们都可以看到想要的 return 指令中的结果。这是因为 return 指令所在的 rewrite 模块先于 access 模块执行,所以不会执行到 allow 和 deny 指令就直接返回了。但是对于访问静态资源,则是在 content 阶段执行的,所以会在经过 allow 和 deny 指令处理后才静态资源的,并返回给。
$ htpasswd -bc /root/user.pass store @store! $ cat /root/user.pass store:$apr$36xHOQGz$yk4O3roiW3SIJrkXFJ0pS1
在 加入如下 server 块的配置,监听 8012 端口,并在 / 路径中加入认证模块。
server { server_name auth_basic.test.com; listen ; location / { auth_basic "my site"; auth_basic_user_file /root/user.pass; }}
重新加载 后,访问主机的 8012 端口的根路径时,就会发现需要输入账号和密码了。成功输入账号和密码后,就可以看到 的欢迎页了。
使用 auth_basic 模块认证
4. 小结
本篇中,我们介绍了 Http 请求的 11 个阶段中的中间阶段,分别为 preaccess 和 access 阶段。两个阶段中,主要生效的指令有limit_conn、limit_req、allow、deny 等,这些指令几乎都是用来做访问控制的,用来限制 的并发连接、访问限速、设置访问白名单以及认证访问等。这些安全限制在线上环境是十分必要的,必须要限制恶意的请求以及白名单操作。