08《Nginx 入門教程》Nginx 的 Http 模塊介紹(中)

在前面介紹完 post-read、server-rewrite、find-config、rewrite 和 post-rewrite 階段后,我們將繼續(xù)學(xué)習(xí) preaccess 和 access 兩個階段,中間會涉及部分模塊,一同進(jìn)行說明。

1. preaccess 階段

在 preaccess 階段在 access 階段之前,主要是限制用戶的請求,比如并發(fā)連接數(shù)(limit_conn模塊)和每秒請求數(shù)(limit_req 模塊)等。這兩個模塊對于預(yù)防一些攻擊請求是很有效的。

1.1 limit_conn 模塊

ngx_http_limit_conn_module 模塊限制單個 ip 的建立連接的個數(shù),該模塊內(nèi)有 6 個指令。分別如下:

  • limit_conn_zone: 該指令主要的作用就是分配共享內(nèi)存。 下面的指令格式中 key 定義鍵,這個 key 往往取客戶端的真實(shí) ip,zone=name 定義區(qū)域名稱,后面的 limit_conn 指令會用到的。size 定義各個鍵共享內(nèi)存空間大小;
Syntax: limit_conn_zone key zone=name:size;
Default: —
Context: http

  • limit_conn_status: 對于連接拒絕的請求,返回設(shè)置的狀態(tài)碼,默認(rèn)是 503;
Syntax: limit_conn_status code;
Default: limit_conn_status 503;
Context: http, server, location

  • limit_conn: 該指令實(shí)際限制請求的并發(fā)連接數(shù)。指令指定每個給定鍵值的最大同時連接數(shù),當(dāng)超過這個數(shù)字時被返回 503 (默認(rèn),可以由指令 limit_conn_status 設(shè)置)錯誤;
Syntax: limit_conn zone number;
Default: —
Context: http, server, location

  • limit_conn_log_level: 當(dāng)達(dá)到最大限制連接數(shù)后,記錄日志的等級;
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 版本中才出現(xiàn)的,用于設(shè)置演習(xí)模式。在這個模式中,連接數(shù)不受限制。但是在共享內(nèi)存的區(qū)域中,過多的連接數(shù)也會照常處理。
Syntax: limit_conn_dry_run on | off;
Default: limit_conn_dry_run off;
Context: http, server, location

  • limit_zone: 該指令已棄用,由 limit_conn_zone 代替,不再進(jìn)行說明。

實(shí)例

http {
    ...
    limit_conn_zone $binary_remote_addr zone=addr:10m

    server {
        ...
        location / {
            limit_conn_status 500;
            limit_conn_log_level warn;
            # 限制向用戶返回的速度,每秒50個字節(jié)
            limit_rate 50;
            limit_conn addr 10;
        }
    }

}

1.2 limit_req 模塊

ngx_http_limit_req_module 模塊主要用于處理突發(fā)流量,它基于漏斗算法將突發(fā)的流量限定為恒定的流量。如果請求容量沒有超出設(shè)定的極限,后續(xù)的突發(fā)請求的響應(yīng)會變慢,而對于超過容量的請求,則會立即返回 503(默認(rèn))錯誤。

該模塊模塊中比較重要的指令有:

  • limit_req_zone 指令,定義共享內(nèi)存, key 關(guān)鍵字以及限制速率
Syntax: limit_req_zone key zone=name:size rate=rate [sync];
Default: —
Context: http
代碼塊123
  • limit_req 指令,限制并發(fā)連接數(shù)
Syntax: limit_req zone=name [burst=number] [nodelay | delay=number];
Default: —
Context: http, server, location
代碼塊123
  • limit_req_log_level 指令,設(shè)置服務(wù)拒絕請求發(fā)生時打印的日志級別
Syntax: limit_req_log_level info | notice | warn | error;
Default:
limit_req_log_level error;
Context:    http, server, location
代碼塊1234
  • limit_req_status 指令, 設(shè)置服務(wù)拒絕請求發(fā)生時返回狀態(tài)碼
Syntax: limit_req_status code;
Default: limit_req_status 503;
Context: http, server, location
代碼塊123

2. access 階段

2.1 限制某些 ip 地址的訪問權(quán)限

在 access 階段,我們可以通 allow 和 deny 指令來允許和拒絕某些 ip 的訪問權(quán)限,指令的用法如下:

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


實(shí)例

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 協(xié)議進(jìn)行用戶名和密碼的認(rèn)證,它默認(rèn)是編譯進(jìn) Nginx 中的,可以在源碼編譯階段通過 --without-http_auth_basic_module 禁用該模塊。它的用法如下:

Syntax: auth_basic string | off;
# 默認(rèn)是關(guān)閉的
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 系統(tǒng)上,想要生成這樣的密碼文件,我們可以使用 httpd-tools 工具完成,直接使用 yum install安裝即可。

$ sudo yum install httpd-tools
# 生成密碼文件user_file,帳號為user,密碼為pass
$ htpasswd -bc user_file user pass

接下來,我們只需要配置好 auth_basic 指令,即可對相應(yīng)的 http 請求做好認(rèn)證工作。

2.3 第三方訪問控制

第三方的訪問控制是用到了auth_request模塊,該模塊的功能是向上游服務(wù)轉(zhuǎn)發(fā)請求,如果上游服務(wù)返回的相應(yīng)碼是 2xx,則通過認(rèn)證,繼續(xù)向后執(zhí)行;若返回的 401 或者 403,則將響應(yīng)返回給客戶端。

auth_request 模塊默認(rèn)是未編譯進(jìn) Nginx 中的,因此我們需要使用 --with-http_auth_reques_module
將該模塊編譯進(jìn) 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 {
    # 上游認(rèn)證服務(wù)地址
    proxy_pass ...
    proxy_pass_request_body off;
    proxy_set_header Content-Length "";
    proxy_set_header X-Original-URI $request_uri;
}

3. 實(shí)驗(yàn)

3.1 limit_conn 模塊實(shí)驗(yàn)

本次案例將使用 limit_conn 模塊中的指令完成限速功能實(shí)驗(yàn)。實(shí)驗(yàn)配置塊如下:

...
http {
    ...
    # 沒有這個會報(bào)錯,必須要定義共享內(nèi)存
    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 相應(yīng)速度,每秒返回 50 個字節(jié),然后是限制并發(fā)數(shù)為 2,這樣方便展示效果。當(dāng)我們打開一個瀏覽器請求該端口下的根路徑時,由于相應(yīng)會比較慢,迅速打開另一個窗口請求同樣的地址,會發(fā)現(xiàn)再次請求時,正好達(dá)到了同時并發(fā)數(shù)為 2,啟動限制功能,第二個窗口返回 503 錯誤(默認(rèn))。

訪問第一次

5e4f5c1a09af5ad213600340.png

快速訪問第二次

5e4f5c280994943713660304.jpg

3.2 access 模塊實(shí)驗(yàn)

我們做一個簡單的示例,配置如下。在 /root/test/web 下有 web1.html 和 web2.html 兩個靜態(tài)文件。訪問/web1.html 時,使用 allow all指令將所有來源的 ip 請求全部放過(當(dāng)然也可以不寫);使用 deny all 會拒絕所有,所以訪問 /web2.htm l時,會出現(xiàn) 403 的報(bào)錯頁面。

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 指令呢,會有怎樣的結(jié)果?打開注釋,重新加載 Nginx 后,可以看到無論是訪問 /web1.html 還是 /web2.html,我們都可以看到想要的 return 指令中的結(jié)果。這是因?yàn)?return 指令所在的 rewrite 模塊先于 access 模塊執(zhí)行,所以不會執(zhí)行到 allow 和 deny 指令就直接返回了。但是對于訪問靜態(tài)頁面資源,則是在 content 階段執(zhí)行的,所以會在經(jīng)過 allow 和 deny 指令處理后才獲取靜態(tài)資源頁面的內(nèi)容,并返回給用戶。

3.3 auth_basic 模塊實(shí)驗(yàn)

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

在 Nginx 加入如下 server 塊的配置,監(jiān)聽 8012 端口,并在 / 路徑中加入認(rèn)證模塊。

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

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

重新加載 Nginx 后,訪問主機(jī)的 8012 端口的根路徑時,就會發(fā)現(xiàn)需要輸入賬號和密碼了。成功輸入賬號和密碼后,就可以看到 Nginx 的歡迎頁了。

使用 auth_basic 模塊認(rèn)證

5e52711b092e22d013660403.jpg

認(rèn)證成功后的頁面

5e52712909fdadeb13660355.jpg

4. 小結(jié)

本篇文章中,我們介紹了 Http 請求的 11 個階段中的中間階段,分別為 preaccess 和 access 階段。在這兩個階段中,主要生效的指令有l(wèi)imit_conn、limit_req、allow、deny 等,這些指令幾乎都是用來做訪問控制的,用來限制 Nginx 的并發(fā)連接、訪問限速、設(shè)置訪問白名單以及認(rèn)證訪問等。這些安全限制在線上環(huán)境是十分必要的,必須要限制惡意的請求以及添加白名單操作。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容