不同的業(yè)務(wù)應(yīng)用場景,會有完全不同的非法終端控制策略,常見的限制策略有終端 IP 、訪問域名端口,這些可以通過防火墻等很多成熟手段完成。可也有一些特定限制策略,例如特定 cookie、url、location,甚至請求 body 包含有特殊內(nèi)容,這種情況下普通防火墻就比較難限制。
Nginx 是 HTTP 7 層協(xié)議的實現(xiàn)者,相對普通防火墻從通訊協(xié)議有自己的弱勢,同等的配置下的性能表現(xiàn)絕對遠不如防火墻,但它的優(yōu)勢勝在價格便宜、調(diào)整方便,還可以完成 HTTP 協(xié)議上一些更具體的控制策略,與 iptable 的聯(lián)合使用,讓 Nginx 玩出更多花樣。
示例配置(allow、deny)
location / {
deny 192.168.1.1;
allow 192.168.1.0/24;
allow 10.1.1.0/16;
allow 2001:0db8::/32;
deny all;
}
這些規(guī)則都是按照順序解析執(zhí)行直到某一條匹配成功。在這里示例中,10.1.1.0/16 and 192.168.1.0/24 都是用來限制 IPv4 的,2001:0db8::/32 的配置是用來限制 IPv6。具體有關(guān) allow、deny 配置,請參考這里。
示例配置(geo)
Example:
geo $country {
default ZZ;
proxy 192.168.100.0/24;
127.0.0.0/24 US;
127.0.0.1/32 RU;
10.1.0.0/16 RU;
192.168.1.0/24 UK;
}
if ($country == ZZ){
return 403;
}
使用 geo,讓我們有更多的分支條件。注意:在 Nginx 的配置中,盡量少用或者不用 if ,因為 "if is evil"。點擊查看
目前為止所有的控制,都是用 Nginx 模塊完成,執(zhí)行效率、配置明確是它的優(yōu)點。缺點也比較明顯,修改配置代價比較高(reload 服務(wù))。并且無法完成與第三方服務(wù)的對接功能交互(例如調(diào)用 iptable)。
在 OpenResty 里面,這些問題就都容易解決,還記得 access_by_lua*
么?推薦一個第三方庫lua-resty-iputils。
示例代碼:
init_by_lua_block {
local iputils = require("resty.iputils")
iputils.enable_lrucache()
local whitelist_ips = {
"127.0.0.1",
"10.10.10.0/24",
"192.168.0.0/16",
}
-- WARNING: Global variable, recommend this is cached at the module level
-- https://github.com/openresty/lua-nginx-module#data-sharing-within-an-nginx-worker
whitelist = iputils.parse_cidrs(whitelist_ips)
}
access_by_lua_block {
local iputils = require("resty.iputils")
if not iputils.ip_in_cidrs(ngx.var.remote_addr, whitelist) then
return ngx.exit(ngx.HTTP_FORBIDDEN)
end
}
以次類推,我們想要完成域名、Cookie、location、特定 body 的準入控制,甚至可以做到與本地 iptable 防火墻聯(lián)動。 我們可以把 IP 規(guī)則存到數(shù)據(jù)庫中,這樣我們就再也不用 reload Nginx,在有規(guī)則變動的時候,刷新下 Nginx 的緩存就行了。
思路打開,大家后面多嘗試各種玩法吧。