通過(guò)配置nginx 抵御不合法請(qǐng)求
ngx_http_limit_conn_module模塊
使用此模塊主要用來(lái)限制每秒請(qǐng)求數(shù)量,至于依據(jù)什么條件限制是由我們來(lái)自定義的。
官方文檔 Module ngx_http_limit_req_module
中文翻譯的 nginx限制請(qǐng)求數(shù)ngx_http_limit_req_module模塊
文檔講的很詳細(xì)了,大致說(shuō)下:
limit_req_zone $variable zone=name:size rate=rate;
命令的意思是,以$variable變量為條件,起名為name,設(shè)置的存儲(chǔ)空間大小為size,設(shè)置限定頻率為rate;
我們可以設(shè)置**多個(gè),不同條件,不同名稱(chēng),不同大小的限制**。
這個(gè)定義我們是需要寫(xiě)在**http配置段中**。
在匹配的location中寫(xiě)上limit_req zone=name [burst=number] [nodelay];這里burst就是允許的漏桶數(shù),當(dāng)請(qǐng)求頻率大于rate但是超出的數(shù)量不大于burst設(shè)置的數(shù)量,則nginx會(huì)將超出的請(qǐng)求延遲后面返回。如果請(qǐng)求數(shù)量超出burst了,則將超出部分直接返回錯(cuò)誤碼,默認(rèn)503。至于nodelay就是設(shè)置是否要延遲,有它不超過(guò)burst的請(qǐng)求才延遲。
網(wǎng)上大多條件都是$binary_remote_addr,其實(shí)我們可以根據(jù)自己的需求,來(lái)定義自身的相應(yīng)條件,活學(xué)活用嘛,下面會(huì)有實(shí)例。
ngx_http_limit_conn_module模塊
這個(gè)模塊主要限制單獨(dú)ip同一時(shí)間的連接數(shù)
官方文檔 Module ngx_http_limit_conn_module。
中文翻譯的 nginx限制連接數(shù)ngx_http_limit_conn_module模塊。
各位看文檔吧,我的實(shí)戰(zhàn)中沒(méi)有使用此模塊。
實(shí)戰(zhàn)階段
好了,下面進(jìn)入實(shí)戰(zhàn)階段:
首先我們的初始配置文件時(shí)是(不完整):
http { server { listen 8080 default_server; server_name localhost:8080; location ~ .* { proxy_pass http://127.0.0.1:8080; proxy_set_header X-Real-IP $remote_addr; } } }
我們的需求是,有一批接口被頻繁的不合法訪(fǎng)問(wèn),我們要做限制。
第一版:限制為1s一次請(qǐng)求,漏桶數(shù)為5
http { limit_req_zone $binary_remote_addr zone=one:10m rate=1r/s; server { listen 8080 default_server; server_name localhost:8080; location ~ .* { proxy_pass http://127.0.0.1:8080; proxy_set_header X-Real-IP $remote_addr; } location ^~ /interface { limit_req zone=one burst=5 nodelay; proxy_pass http://127.0.0.1:8080; } } }這里加了proxy_pass http://127.0.0.1:8080;這里配置了轉(zhuǎn)發(fā),否則匹配之后會(huì)找不到服務(wù)器的。
但是這樣會(huì)有個(gè)問(wèn)題,目前我們是以ip做的限制,但是有可能網(wǎng)吧或者校內(nèi)出口就是一個(gè)或幾個(gè)ip,我們這樣限制的話(huà)會(huì)把正常用戶(hù)也限制到了,得不償失。其實(shí)我們可以換一種思路來(lái)定位到單一用戶(hù),正常一個(gè)請(qǐng)求過(guò)來(lái),我們都會(huì)設(shè)置攜帶一個(gè)關(guān)于用戶(hù)的`token`信息。至于這個(gè)`token`是如何生成的,只有服務(wù)器知道,那我們加入我們的每次請(qǐng)求中,`header`中帶有這個(gè)信息,`token`值,如果一個(gè)非法的請(qǐng)求可能沒(méi)有這個(gè)值,即使有這個(gè)值我們也可以以`token`為條件來(lái)限制,這樣更合理些。
這里加了proxy_pass http://127.0.0.1:8080;這里配置了轉(zhuǎn)發(fā),否則匹配之后會(huì)找不到服務(wù)器的。
但是這樣會(huì)有個(gè)問(wèn)題,目前我們是以ip做的限制,但是有可能網(wǎng)吧或者校內(nèi)出口就是一個(gè)或幾個(gè)ip,我們這樣限制的話(huà)會(huì)把正常用戶(hù)也限制到了,得不償失。其實(shí)我們可以換一種思路來(lái)定位到單一用戶(hù),正常一個(gè)請(qǐng)求過(guò)來(lái),我們都會(huì)設(shè)置攜帶一個(gè)關(guān)于用戶(hù)的`token`信息。至于這個(gè)`token`是如何生成的,只有服務(wù)器知道,那我們加入我們的每次請(qǐng)求中,`header`中帶有這個(gè)信息,`token`值,如果一個(gè)非法的請(qǐng)求可能沒(méi)有這個(gè)值,即使有這個(gè)值我們也可以以`token`為條件來(lái)限制,這樣更合理些。
第二版
http { limit_req_zone $http_token zone=two:10m rate=1r/s; server { listen 8080 default_server; server_name localhost:8080; location ~ .* { proxy_pass http://127.0.0.1:8080; proxy_set_header X-Real-IP $remote_addr; } location ^~ /interface { if($http_token=""){ return 403; } limit_req zone=two burst=5 nodelay; proxy_pass http://127.0.0.1:8080; } } } 在nginx中,使用$http_變量名,取的就是header中相應(yīng)的變量。
前方預(yù)警:我特意在這個(gè)配置中留了個(gè)坑,如果你像我這樣配置的話(huà),重啟會(huì)報(bào)一個(gè)異常nginx: [emerg] unknown directive "if($http_token",很奇怪是不,這個(gè)異常我花了很長(zhǎng)時(shí)間才解決,原因是if和(中間需要個(gè)**空格**,沒(méi)錯(cuò),就是這個(gè)空格花了我好幾個(gè)小時(shí),血淚的教訓(xùn)啊,希望各位不要再重蹈覆轍。
這個(gè)問(wèn)題的解決的文章:Nginx unknown directive “if($domain”
這次的配置,多少可以限制住的,對(duì)我一個(gè)nginx的小白來(lái)說(shuō),調(diào)研一點(diǎn)用一點(diǎn),也是不錯(cuò)的。
【編輯推薦】






















