08《Nginx 入门教程》Nginx 的 Http 模块介绍(中)

在前面介绍完 post-read、server-rewrite、find-config、rewrite 和 post-rewrite 阶段后,我们将继续学习 preaccess 和 access 两个阶段,中间会涉及部分模块,一同进行说明。

1. preaccess 阶段

在 preaccess 阶段在 access 阶段之前,主要是限制用户的请求,比如并发连接数(limit_conn模块)和每秒请求数(limit_req 模块)等。这两个模块对于预防一些攻击请求是很有效的。

1.1 limit_conn 模块

ngx_http_limit_conn_module 模块限制单个 ip 的建立连接的个数,该模块内有 6 个指令。分别如下:

  • limit_conn_zone: 该指令主要的作用就是分配共享内存。 下面的指令格式中 key 定义键,这个 key 往往取客户端的真实 ip,zone=name 定义区域名称,后面的 limit_conn 指令会用到的。size 定义各个键共享内存空间大小;
Syntax: limit_conn_zone key zone=name:size;
Default: —
Context: http

  • limit_conn_status: 对于连接拒绝的请求,返回设置的状态码,默认是 503;
Syntax: limit_conn_status code;
Default: limit_conn_status 503;
Context: http, server, location

  • limit_conn: 该指令实际限制请求的并发连接数。指令指定每个给定键值的最大同时连接数,当超过这个数字时被返回 503 (默认,可以由指令 limit_conn_status 设置)错误;
Syntax: limit_conn zone number;
Default: —
Context: http, server, location

  • limit_conn_log_level: 当达到最大限制连接数后,记录日志的等级;
Syntax: 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 版本中才出现的,用于设置演习模式。在这个模式中,连接数不受限制。但是在共享内存的区域中,过多的连接数也会照常处理。
Syntax: 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:10m

    server {
        ...
        location / {
            limit_conn_status 500;
            limit_conn_log_level warn;
            # 限制向用户返回的速度,每秒50个字节
            limit_rate 50;
            limit_conn addr 10;
        }
    }

}

1.2 limit_req 模块

ngx_http_limit_req_module 模块主要用于处理突发流量,它基于漏斗算法将突发的流量限定为恒定的流量。如果请求容量没有超出设定的极限,后续的突发请求的响应会变慢,而对于超过容量的请求,则会立即返回 503(默认)错误。

该模块模块中比较重要的指令有:

  • limit_req_zone 指令,定义共享内存, key 关键字以及限制速率
Syntax: limit_req_zone key zone=name:size rate=rate [sync];
Default: —
Context: http
代码块123
  • limit_req 指令,限制并发连接数
Syntax: limit_req zone=name [burst=number] [nodelay | delay=number];
Default: —
Context: http, server, location
代码块123
  • limit_req_log_level 指令,设置服务拒绝请求发生时打印的日志级别
Syntax: limit_req_log_level info | notice | warn | error;
Default:
limit_req_log_level error;
Context:    http, server, location
代码块1234
  • limit_req_status 指令, 设置服务拒绝请求发生时返回状态码
Syntax: limit_req_status code;
Default: limit_req_status 503;
Context: http, server, location
代码块123

2. access 阶段

2.1 限制某些 ip 地址的访问权限

在 access 阶段,我们可以通 allow 和 deny 指令来允许和拒绝某些 ip 的访问权限,指令的用法如下:

Syntax: allow address | CIDR | unix: | all;
Default: —
Context: http, server, location, limit_except

Syntax: deny address | CIDR | unix: | all;
Default: —
Context: http, server, location, limit_except


实例

allow 和 deny 指令后面可以跟具体 ip 地址,也可以跟一个 ip 段, 或者所有(all)。

location / {
    deny  192.168.1.1;
    allow 192.168.1.0/24;
    allow 10.1.1.0/16;
    allow 2001:0db8::/32;
    deny  all;
}

2.2 auth_basic 模块

auth_basic 模块是基于 HTTP Basic Authentication 协议进行用户名和密码的认证,它默认是编译进 Nginx 中的,可以在源码编译阶段通过 --without-http_auth_basic_module 禁用该模块。它的用法如下:

Syntax: auth_basic string | off;
# 默认是关闭的
Default: auth_basic off;
Context: http, server, location, limit_except

Syntax: auth_basic_user_file file;
Default: —
Context: http, server, location, limit_except

对于使用文件保存用户名和密码,二者之间需用冒号隔开,如下所示。

# comment
name1: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 请求做好认证工作。

2.3 第三方访问控制

第三方的访问控制是用到了auth_request模块,该模块的功能是向上游服务转发请求,如果上游服务返回的相应码是 2xx,则通过认证,继续向后执行;若返回的 401 或者 403,则将响应返回给客户端。

auth_request 模块默认是未编译进 Nginx 中的,因此我们需要使用 --with-http_auth_reques_module
将该模块编译进 Nginx 中,然后我们才能使用该模块。

Syntax: auth_request uri | off;
Default: auth_request off;
Context: http, server, location

Syntax: 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. 实验

3.1 limit_conn 模块实验

本次案例将使用 limit_conn 模块中的指令完成限速功能实验。实验配置块如下:

...
http {
    ...
    # 没有这个会报错,必须要定义共享内存
    limit_conn_zone $binary_remote_addr zone=addr:10m;
    ...
    server {
        server_name localhost;
        listen 8010;

        location / {
           limit_rate 50;
           limit_conn addr 1;
        }

    }
    ...
}
...

使用 limit_rate 指令用于限制 Nginx 相应速度,每秒返回 50 个字节,然后是限制并发数为 2,这样方便展示效果。当我们打开一个浏览器请求该端口下的根路径时,由于相应会比较慢,迅速打开另一个窗口请求同样的地址,会发现再次请求时,正好达到了同时并发数为 2,启动限制功能,第二个窗口返回 503 错误(默认)。

访问第一次

5e4f5c1a09af5ad213600340.png

快速访问第二次

5e4f5c280994943713660304.jpg

3.2 access 模块实验

我们做一个简单的示例,配置如下。在 /root/test/web 下有 web1.html 和 web2.html 两个静态文件。访问/web1.html 时,使用 allow all指令将所有来源的 ip 请求全部放过(当然也可以不写);使用 deny all 会拒绝所有,所以访问 /web2.htm l时,会出现 403 的报错页面。

server {
   server_name access.test.com;
   listen 8011;

   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 页面


5e4f5c3a09661bfc13660246.jpg

访问禁止的 web2.html


5e4f5c5c0964755013660326.jpg

大家可以思考下,如果使用的是 return 指令呢,会有怎样的结果?打开注释,重新加载 Nginx 后,可以看到无论是访问 /web1.html 还是 /web2.html,我们都可以看到想要的 return 指令中的结果。这是因为 return 指令所在的 rewrite 模块先于 access 模块执行,所以不会执行到 allow 和 deny 指令就直接返回了。但是对于访问静态页面资源,则是在 content 阶段执行的,所以会在经过 allow 和 deny 指令处理后才获取静态资源页面的内容,并返回给用户。

3.3 auth_basic 模块实验

   $ htpasswd -bc /root/user.pass store @store.123!
   $ cat /root/user.pass
   store:$apr1$36xHOQGz$yk4O3roiW3SIJrkXFJ0pS1
代码块123

在 Nginx 加入如下 server 块的配置,监听 8012 端口,并在 / 路径中加入认证模块。

server {
   server_name auth_basic.test.com;
   listen 8012;

   location / {
       auth_basic           "my site";
       auth_basic_user_file /root/user.pass;
   }
}

重新加载 Nginx 后,访问主机的 8012 端口的根路径时,就会发现需要输入账号和密码了。成功输入账号和密码后,就可以看到 Nginx 的欢迎页了。

使用 auth_basic 模块认证

5e52711b092e22d013660403.jpg

认证成功后的页面

5e52712909fdadeb13660355.jpg

4. 小结

本篇文章中,我们介绍了 Http 请求的 11 个阶段中的中间阶段,分别为 preaccess 和 access 阶段。在这两个阶段中,主要生效的指令有limit_conn、limit_req、allow、deny 等,这些指令几乎都是用来做访问控制的,用来限制 Nginx 的并发连接、访问限速、设置访问白名单以及认证访问等。这些安全限制在线上环境是十分必要的,必须要限制恶意的请求以及添加白名单操作。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,657评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,662评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,143评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,732评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,837评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,036评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,126评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,868评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,315评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,641评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,773评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,470评论 4 333
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,126评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,859评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,095评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,584评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,676评论 2 351

推荐阅读更多精彩内容