精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

每個后端都應(yīng)該了解的OpenResty入門以及網(wǎng)關(guān)安全實戰(zhàn)

開發(fā) 前端
自此本文介紹了OpenResty入門以及使用 Lua 腳本實現(xiàn)一些常見的網(wǎng)關(guān)安全功能等。需要注意的就是大家在已有的 Nginx 服務(wù)遷移到 OpenResty 上來時,記得注意 OpenResty 版本,Nginx 與 OpenResty 相同版本情況下,OpenResty 官方是保證完全兼容的。

簡介

在官網(wǎng)上對 OpenResty 是這樣介紹的(http://openresty.org):

“OpenResty 是一個基于 Nginx 與 Lua 的高性能 Web 平臺,其內(nèi)部集成了大量精良的 Lua 庫、第三方模塊以及大多數(shù)的依賴項。用于方便地搭建能夠處理超高并發(fā)、擴展性極高的動態(tài) Web 應(yīng)用、Web 服務(wù)和動態(tài)網(wǎng)關(guān)。”

“OpenResty 通過匯聚各種設(shè)計精良的 Nginx 模塊(主要由 OpenResty 團(tuán)隊自主開發(fā)),從而將 Nginx 有效地變成一個強大的通用 Web 應(yīng)用平臺。這樣,Web 開發(fā)人員和系統(tǒng)工程師可以使用 Lua 腳本語言調(diào)動 Nginx 支持的各種 C 以及 Lua 模塊,快速構(gòu)造出足以勝任 10K 乃至 1000K 以上單機并發(fā)連接的高性能 Web 應(yīng)用系統(tǒng)。”

“OpenResty 的目標(biāo)是讓你的 Web 服務(wù)直接跑在 Nginx 服務(wù)內(nèi)部,充分利用 Nginx 的非阻塞 I/O 模型,不僅僅對 HTTP 客戶端請求,甚至于對遠(yuǎn)程后端諸如 MySQL、PostgreSQL、Memcached 以及 Redis 等都進(jìn)行一致的高性能響應(yīng)。”

從以上官網(wǎng)描述里我們可以知道,OpenResty 官網(wǎng)對其定位是以 Nginx 為核心集成 Lua,打造一個兼具開發(fā)效率和高性能的服務(wù)端開發(fā)平臺。

OpenResty 的核心是基于 Nginx 的一個 C 模塊(lua-Nginx-module),該模塊將 LuaJIT 嵌入到 Nginx 服務(wù)器中,并對外提供一套完整的 Lua API,透明地支持非阻塞 I/O,提供了輕量級線程、定時器等高級抽象。

我們可以用 Lua 語言來進(jìn)行字符串和數(shù)值運算、查詢數(shù)據(jù)庫、發(fā)送 HTTP 請求、執(zhí)行定時任務(wù)、調(diào)用外部命令等,還可以用 FFI 的方式調(diào)用外部 C 函數(shù)。這基本上可以滿足服務(wù)端開發(fā)需要的所有功能。

掌握好了 OpenResty,我們就可以同時擁有腳本語言的開發(fā)效率和迭代速度,以及 Nginx C 模塊的高并發(fā)和高性能優(yōu)勢。

下面為大家介紹本文大綱:

  • OpenResty 的 hello world 該怎么寫
  • 快速上手 Lua 腳本語言
  • OpenResty 用到的 Nginx 知識
  • OpenResty 在網(wǎng)關(guān)安全中如何應(yīng)用

OpenResty 的 hello world 該怎么寫

OpenResty 的安裝

OpenResty 的安裝有多種方法,比如使用操作系統(tǒng)的包管理器、源碼編譯或者 docker 鏡像。推薦優(yōu)先使用 yum、apt-get、brew 這類包管理系統(tǒng),來安裝 OpenResty。

對于 Mac OS X 或 macOS 用戶,強烈推薦您使用 homebrew 包管理工具安裝 OpenResty。可以直接使用下面 這一條命令:

brew install openresty/brew/openresty

對于一些常見的 Linux 發(fā)行版本(Ubuntu、Debian、CentOS、RHEL、Fedora、OpenSUSE、Alpine 和 Amazon Linux), OpenResty 提供 官方預(yù)編譯包。確保首先用這種方式來安裝。這里用 CentOS 舉例,可以使用如下方式,

CentOS 9 或者更新版本

# add the yum repo:
wget https://openresty.org/package/centos/openresty2.repo
sudo mv openresty2.repo /etc/yum.repos.d/openresty.repo

# update the yum index:
sudo yum check-update

CentOS 8 或者更老版本

# add the yum repo:
wget https://openresty.org/package/centos/openresty.repo
sudo mv openresty.repo /etc/yum.repos.d/openresty.repo

# update the yum index:
sudo yum check-update

然后就可以像下面這樣安裝軟件包,比如 openresty:

sudo yum install -y openresty

Docker 安裝

Docker 安裝的方式就最為簡單了,只需要輸入以下命令,就可以獲取打包好的鏡像。

docker pull openresty/openresty

目錄結(jié)構(gòu)

安裝 OpenResty 成功后的目錄結(jié)構(gòu)如下(以默認(rèn)安裝目錄為例):

/usr/local/openresty/                          #安裝主目錄
├── bin                                     #存放可執(zhí)行文件
├── luajit                                  #LuaJIT運行庫
├── lualib                                  #Lua組件
├── Nginx                                   #Nginx核心運行平臺
├── pod                                     #參考手冊(restydoc)使用的數(shù)據(jù)
└── site                                    #包管理工具(opm)使用的數(shù)據(jù)

啟動服務(wù)

yum 安裝完后,就可以直接運行 openresty 命令,啟動 OpenResty 服務(wù)。

/usr/local/openresty/bin/openresty         #啟動OpenResty服務(wù)

OpenResty 默認(rèn)開啟了 localhost:80 服務(wù),使用 wget 或者 curl 這樣的工具就可以驗證 OpenResty 是否正常工作:

curl http://localhost:80                   #curl命令發(fā)送HTTP請求

下面是一些其他常用命令,

/usr/local/openresty/bin/openresty  -s stop       #停止 OpenResty 服務(wù)
/usr/local/openresty/bin/openresty  -s reload     #重新加載 Nginx 配置文件
/usr/local/openresty/bin/openresty  -t            #檢查 Nginx 配置文件是否正確
/usr/local/openresty/bin/openresty  -c            #指定配置文件啟動

OpenResty 的操作命令跟 Nginx 保持一致。可以執(zhí)行 openresty -h 以及 nginx -h 對比看出,

圖片圖片

命令行工具 resty

如果你想安裝命令行工具 resty,那么可以像下面這樣安裝 openresty-resty 包:

sudo yum install -y openresty-resty

resty 是一個 cli 工具,可以使用 -e 參數(shù)可以在命令行里直接執(zhí)行 Lua 代碼,我們可以在命令行執(zhí)行如下命令,

[root@VM-4-5-centos ~]# resty -e "print('hello world')"
hello OpenResty

resty 工具還有很多選項用于配置行為,非常靈活,-e 之外較常用的有

-c                :指定最大并發(fā)連接數(shù)(默認(rèn)值是64);
-I                :指定Lua庫的搜索路徑;
-l                :指定加載某個Lua庫;
--http-conf       :定制在http域里的指令;
--main-include    :定制在main域里的指令;
--shdict          :定制使用的共享內(nèi)存(參見10.2節(jié));
--resolve-ipv6    :允許解析ipv6的地址。

想了解完整的列表,可以查看 resty -h 命令。

包管理工具 opm

跟大多數(shù)語言一樣有包管理工具一樣,OpenResty 也有自己的包管理工具 opm(OpenResty Package Manager),opm 在 openresty-opm 包里,安裝命令如下,

sudo yum install -y openresty-opm

opm 是 OpenResty 自帶的包管理器,在你安裝好 OpenResty 之后,就可以直接使用。一些常見用法如下,

opm search    http                            #搜索關(guān)鍵字http
opm search    kafka                           #搜索關(guān)鍵字kafka
opm get       agentzh/lua-resty-http          #安裝組件,注意需要sudo
opm info      agentzh/lua-resty-http          #顯示組件的版本、作者等信息
opm remove    agentzh/lua-resty-http          #移除組件,同樣需要sudo
opm --install-dir=/opt    get xxx             #把組件安裝到/opt目錄下
opm --cwd                 get xxx             #安裝到當(dāng)前目錄的/resty_modules下

編寫 hello world

在上文中我們使用命令行工具 resty 寫了一個比較簡單的 OpenResty 程序,沒有 master 進(jìn)程,也不會監(jiān)聽端口。下面讓我們寫一個需要啟動 OpenResty 服務(wù)的 hello world。

首先找到 OpenResty 安裝目錄下 nginx/conf/nginx.conf 文件,在 server 下新增 OpenResty 的 content_by_lua 指令,里面嵌入了 ngx.say 的代碼:

server {
        listen       88;
        server_name  localhost;

        location / {
            root   html;
            index  index.html index.htm;
        }

        location /hello {
            content_by_lua '
                ngx.say("hello, world")
            ';
        }
}

接著我們執(zhí)行 openresty -s reload 命令,重新加載 nginx.conf 配置文件。沒有報錯的話,OpenResty 的服務(wù)就已經(jīng)成功啟動了。

最后使用 curl 命令,來查看結(jié)果的返回:

[root@VM-4-5-centos conf]# curl localhost:88/hello
hello, world

到這里,一個真正的 OpenResty 開發(fā)的 hello world 程序就完成了。

快速上手 Lua 腳本語言

Lua 環(huán)境

我們不用專門去安裝標(biāo)準(zhǔn) Lua 5.1 之類的環(huán)境,因為 OpenResty 已經(jīng)不再支持標(biāo)準(zhǔn) Lua,而只支持 LuaJIT。這里我介紹的 Lua 語法,也是和 LuaJIT 兼容的部分,而不是基于最新的 Lua 5.3,這一點需要特別注意。

在 OpenResty 的安裝目錄下,可以找到 LuaJIT 的目錄和可執(zhí)行文件。在 CentOS 系統(tǒng)下,LuaJIT 的目錄如下,

[root@VM-4-5-centos luajit]# cd /usr/local/openresty/luajit/bin/
[root@VM-4-5-centos bin]# ll
total 536
lrwxrwxrwx 1 root root     18 Oct 12 11:22 luajit -> luajit-2.1.0-beta3
-rwxr-xr-x 1 root root 547728 Jul 18 12:38 luajit-2.1.0-beta3

我們可以執(zhí)行 cp luajit /usr/local/bin/ 將 luajit 文件復(fù)制到 /usr/local/bin/ 目錄下,進(jìn)而可以直接使用 luajit 命令。

查看 LuaJIT 的版本號,

[root@VM-4-5-centos ~]# luajit  -v
LuaJIT 2.1.0-beta3 -- Copyright (C) 2005-2022 Mike Pall. https://luajit.org/

執(zhí)行 lua 腳本,

[root@VM-4-5-centos ~]# echo 'print("hello world")' > 1.lua
[root@VM-4-5-centos ~]# cat 1.lua
print("hello world")
[root@VM-4-5-centos ~]# luajit 1.lua
hello world
[root@VM-4-5-centos ~]#

也可以使用 resty 來直接運行,它最終也是用 LuaJIT 來執(zhí)行的,

[root@VM-4-5-centos ~]# resty -e 'print("hello world")'
hello world

基本語法

變量

在 Lua 中聲明變量,可以如下代碼所示,

local a = 'hello'
b = "world"

加了 local 關(guān)鍵字,用于聲明局部變量。

不加 local 關(guān)鍵字的話,變量默認(rèn)是全局的。

注釋

兩個減號是單行注釋

-- 注釋

多行注釋

--[[
 多行注釋
 多行注釋
 --]]

行尾結(jié)束

Lua 中代碼的行尾結(jié)束都不需要添加特殊字符,這跟 Java 不同(Java 在行尾需要添加 ;)。

local a = 'a'
print(a)

數(shù)據(jù)類型

Lua 中的數(shù)據(jù)類型不多,你可以通過 type 函數(shù)來返回一個值的類型,比如下面這樣的操作:

[root@VM-4-5-centos ~]# resty -e 'print(type("hello world"))
>  print(type(print))
>  print(type(true))
>  print(type(360.0))
>  print(type({}))
>  print(type(nil))
>  '

打印如下,

string
function
boolean
number
table
nil

這幾種就是 Lua 中的基本數(shù)據(jù)類型了。下面我們來簡單介紹一下它們。

字符串

在 Lua 中,有三種方式可以表達(dá)一個字符串:單引號、雙引號,以及長括號([[]]),示例如下,

新建 str.lua 文件,寫入以下內(nèi)容,

local s = 'a'
local s1 = "b"
local s2 = [[c]]

print(s)
print(s1)
print(s2)

執(zhí)行 luajit str.lua 返回結(jié)果如下,

a
b
c

在 Lua 中,字符串拼接采用 .. 的方式,示例如下,

編輯 str.lua 文件,寫入以下內(nèi)容,

local s = 'a'
local s1 = "b"
local s2 = [[c]]

print(s)
print(s1)
print(s2)

local s3 =s .. s1 ..s2
print(s3)

執(zhí)行 luajit str.lua 返回結(jié)果如下,

a
b
c
abc

布爾值

在 Lua 中,只有 nil 和 false 為假,其他都為 true,包括 0 和空字符串也為真。我們可以用示例印證一下:

新建 bool.lua 腳本文件,寫入以下內(nèi)容,

local a = 0
local b
if a then
  print("true")
end
a = ""
if a then
  print("true")
end

print(b)

執(zhí)行 luajit str.lua 返回結(jié)果如下,

true
true
nil

在 Lua 中,空值就是 nil。如果你定義了一個變量,但沒有賦值,它的默認(rèn)值就是 nil,對應(yīng)的就是上面示例代碼的局部變量 b。

數(shù)字

Lua 的 number 類型,是用雙精度浮點數(shù)來實現(xiàn)的。值得一提的是,LuaJIT 支持 dual-number(雙數(shù))模式,也就是說,LuaJIT 會根據(jù)上下文來用整型來存儲整數(shù),而用雙精度浮點數(shù)來存放浮點數(shù)。示例如下,

新建 number.lua 腳本文件,寫入以下內(nèi)容,

print(type(2))
print(type(2.2))
print(type(0.2))
print(type(2e+1))
print(type(0.2e-1))
print(type(7.8263692594256e-06))

print(2 + 2)
print(2 + 22.2)

執(zhí)行 luajit number.lua 返回結(jié)果如下,

number
number
number
number
number
number
4
24.2

函數(shù)

函數(shù)在 Lua 中是一等公民,你可以把函數(shù)存放在一個變量中,也可以當(dāng)作另外一個函數(shù)的入?yún)⒑统鰠ⅰJ纠缦拢?/p>

新建 fun.lua 文件,寫入以下代碼,

-- 階乘
function factorial1(n)
    if n == 0 then
        return 1
    else
        return n * factorial1(n - 1)
    end
end
print(factorial1(5))
factorial2 = factorial1
print(factorial2(5))

執(zhí)行 luajit fun.lua 返回結(jié)果如下,

120
120

分支控制

Lua 提供了以下兩種分支控制結(jié)構(gòu)語句:

  • if 語句
  • if...else 語句
  • if...elseif...else 語句

if 語句

Lua if 語句語法格式如下:

if(布爾表達(dá)式)
then
   --[ 在布爾表達(dá)式為 true 時執(zhí)行的語句 --]
end

以下是一個判斷變量 a 的值是否小于 20 的示例,

新建 if1.lua,寫入以下內(nèi)容,

--[ 定義變量 --]
a = 10;

--[ 使用 if 語句 --]
if (a < 20) then
   --[ if 條件為 true 時打印以下信息 --]
   print("a 小于 20" );
end
print("a 的值為:", a);

執(zhí)行 luajit if1.lua 返回結(jié)果如下,

a 小于 20
a 的值為: 10

if...else 語句

Lua if 語句可以與 else 語句搭配使用, 在 if 條件表達(dá)式為 false 時執(zhí)行 else 語句代碼塊。

Lua if...else 語句語法格式如下:

if(布爾表達(dá)式)
then
   --[ 布爾表達(dá)式為 true 時執(zhí)行該語句塊 --]
else
   --[ 布爾表達(dá)式為 false 時執(zhí)行該語句塊 --]
end

以下是一個判斷變量 a 值的示例,

新建 if2.lua,寫入以下內(nèi)容,

--[ 定義變量 --]
a = 100;
--[ 檢查條件 --]
if( a < 20 )
then
   --[ if 條件為 true 時執(zhí)行該語句塊 --]
   print("a 小于 20" )
else
   --[ if 條件為 false 時執(zhí)行該語句塊 --]
   print("a 大于 20" )
end
print("a 的值為 :", a)

執(zhí)行 luajit if2.lua 返回結(jié)果如下,

a 大于 20
a 的值為 : 100

if...elseif...else 語句

Lua if 語句可以與 elseif...else 語句搭配使用, 在 if 條件表達(dá)式為 false 時執(zhí)行 elseif...else 語句代碼塊,用于檢測多個條件語句。

Lua if...elseif...else 語句語法格式如下:

if( 布爾表達(dá)式 1)
then
   --[ 在布爾表達(dá)式 1 為 true 時執(zhí)行該語句塊 --]

elseif( 布爾表達(dá)式 2)
then
   --[ 在布爾表達(dá)式 2 為 true 時執(zhí)行該語句塊 --]

elseif( 布爾表達(dá)式 3)
then
   --[ 在布爾表達(dá)式 3 為 true 時執(zhí)行該語句塊 --]
else
   --[ 如果以上布爾表達(dá)式都不為 true 則執(zhí)行該語句塊 --]
end

以下是一個判斷變量 a 值的示例,

新建 if3.lua,寫入以下內(nèi)容,

--[ 定義變量 --]
a = 100

--[ 檢查布爾條件 --]
if( a == 10 )
then
    --[ 如果條件為 true 打印以下信息 --]
    print("a 的值為 10" )
elseif( a == 20 )
then
    --[ if else if 條件為 true 時打印以下信息 --]
    print("a 的值為 20" )
elseif( a == 30 )
then
    --[ if else if condition 條件為 true 時打印以下信息 --]
    print("a 的值為 30" )
else
    --[ 以上條件語句沒有一個為 true 時打印以下信息 --]
    print("沒有匹配 a 的值" )
end
print("a 的真實值為: ", a )

執(zhí)行 luajit if3.lua 返回結(jié)果如下,

沒有匹配 a 的值
a 的真實值為:  100

循環(huán)

Lua 編程語言中 for 循環(huán)語句可以重復(fù)執(zhí)行指定語句,重復(fù)次數(shù)可在 for 語句中控制。

Lua 編程語言中 for 語句有兩大類:

  • 數(shù)值 for 循環(huán)
  • 泛型 for 循環(huán)

數(shù)值 for 循環(huán)

Lua 編程語言中數(shù)值 for 循環(huán)語法格式:

for var=exp1,exp2,exp3 do
    <執(zhí)行體>
end

var 從 exp1 變化到 exp2,每次變化以 exp3 為步長遞增 var,并執(zhí)行一次 "執(zhí)行體"。exp3 是可選的,如果不指定,默認(rèn)為 1。示例如下,

新建 for1.lua 文件,寫入以下內(nèi)容,

function f(x)
    print("function")
    return x*2
end

for i = 1, f(5) do print(i)
end

執(zhí)行 luajit for1.lua 返回結(jié)果如下,

function
1
2
3
4
5
6
7
8
9
10

泛型 for 循環(huán)

泛型 for 循環(huán)通過一個迭代器函數(shù)來遍歷所有值,類似 java 中的 foreach 語句。

Lua 編程語言中泛型 for 循環(huán)語法格式:

--打印數(shù)組a的所有值
local a = {"one", "two", "three"}
for i, v in ipairs(a) do
    print(i, v)
end

i 是數(shù)組索引值,v 是對應(yīng)索引的數(shù)組元素值。ipairs 是 Lua 提供的一個迭代器函數(shù),用來迭代數(shù)組。

將以上內(nèi)容下入 for2.lua 文件,打印結(jié)果如下,

1 one
2 two
3 three

Lua 模塊與包

模塊類似于一個封裝庫,從 Lua 5.1 開始,Lua 加入了標(biāo)準(zhǔn)的模塊管理機制,可以把一些公用的代碼放在一個文件里,以 API 接口的形式在其他地方調(diào)用,有利于代碼的重用和降低代碼耦合度。

Lua 提供了一個名為 require 的函數(shù)用來加載模塊。要加載一個模塊,只需要簡單地調(diào)用就可以了。例如:

require("cjson")
-- 或者
require "cjson"

Lua 比較小巧,內(nèi)置的標(biāo)準(zhǔn)庫并不多。在 OpenResty 的環(huán)境中默認(rèn)支持了一些官方模塊,如 cjson 可以直接使用,其他的一些第三方庫則需要先使用 lua_package_path 指令配置 OpenResty 的文件尋址路徑,又或者直接使用 opm 包管理工具來安裝一些第三方模塊。

OpenResty 中默認(rèn)啟用了下面列表的絕大部分組件,想要了解更多 OpenResty 相關(guān)組件的話,可以翻閱官網(wǎng)說明 https://openresty.org/cn/components.html。

LuaJIT
ArrayVarNginxModule
AuthRequestNginxModule
CoolkitNginxModule
DrizzleNginxModule
EchoNginxModule
EncryptedSessionNginxModule
FormInputNginxModule
HeadersMoreNginxModule
...

本文的 Lua 語法介紹到這里就足夠在 OpenResty 中編寫 lua 腳本了,想要了解更多 Lua 內(nèi)容,如 table、文件、調(diào)式等可以自行翻閱 https://www.runoob.com/lua/lua-tutorial.html 網(wǎng)站。

OpenResty 用到的 Nginx 知識

內(nèi)置常量和變量

OpenResty 在內(nèi)置 Lua 引擎中新增了一些常用的內(nèi)置變量如下所示。

圖片圖片

圖片來源https://zhuanlan.zhihu.com/p/539546173

OpenResty 在內(nèi)置 Lua 引擎中新增了一些常用的內(nèi)置常量大致如下所示。

圖片圖片

圖片圖片

這些內(nèi)置變量和常量都可以在 Lua 腳本中直接使用。

配置指令

OpenResty 定義了一系列 Nginx 配置指令,用于配置何時運行用戶 Lua 腳本以及如何返回 Lua 腳本的執(zhí)行結(jié)果,這些指令可以直接在 nginx.conf 配置文件中使用。

OpenResty 定義的 Nginx 配置指令大致如下所示。

圖片圖片

圖片來源https://zhuanlan.zhihu.com/p/539546173

這些指令中有 9 個 *_by_lua 指令,它們和 Nginx 的關(guān)系如下圖所示

圖片圖片

圖片來自 lua-Nginx-module 文檔

其中,init_by_lua 只會在 Master 進(jìn)程被創(chuàng)建時執(zhí)行,init_worker_by_lua 只會在每個 Worker 進(jìn)程被創(chuàng)建時執(zhí)行。其他的 *_by_lua 指令則是由終端請求觸發(fā),會被反復(fù)執(zhí)行。

所以在 init_by_lua 階段,我們可以預(yù)先加載 Lua 模塊和公共的只讀數(shù)據(jù),這樣可以利用操作系統(tǒng)的 COW(copy on write)特性,來節(jié)省一些內(nèi)存。

對于業(yè)務(wù)代碼來說,其實大部分的操作都可以在 content_by_lua 里面完成,但更推薦的做法,是根據(jù)不同的功能來進(jìn)行拆分,比如下面這樣:

  • set_by_lua:設(shè)置變量;
  • rewrite_by_lua:轉(zhuǎn)發(fā)、重定向等;
  • access_by_lua:準(zhǔn)入、權(quán)限等;
  • content_by_lua:生成返回內(nèi)容;
  • header_filter_by_lua:應(yīng)答頭過濾處理;
  • body_filter_by_lua:應(yīng)答體過濾處理;
  • log_by_lua:日志記錄。

利用這些階段的特性,我們可以一些通用邏輯進(jìn)行拆分處理,比如我們可以在 access 階段解密,在 body filter 階段加密就可以了,在 content 階段的代碼是不用做任何修改的。

# 加密協(xié)議版本
location /test {
    access_by_lua '...';        # 請求體解密
    content_by_lua '...';       # 處理請求,不需要關(guān)心通信協(xié)議
    body_filter_by_lua '...';   # 應(yīng)答體加密
}

OpenResty 在網(wǎng)關(guān)安全中如何應(yīng)用

WAF 介紹

Web 應(yīng)用防火墻(Web Application Firewall,簡稱 WAF)對網(wǎng)站或者 App 的業(yè)務(wù)流量進(jìn)行惡意特征識別及防護(hù),在對流量清洗和過濾后,將正常、安全的流量返回給服務(wù)器,避免網(wǎng)站服務(wù)器被惡意入侵導(dǎo)致性能異常等問題,從而保障網(wǎng)站的業(yè)務(wù)安全和數(shù)據(jù)安全。

常見 Web 應(yīng)用攻擊防護(hù)

  • 防御一些常見常見威脅:SQL 注入、XSS 跨站、WebShell 上傳、后門攻擊、命令注入、非法 HTTP 協(xié)議請求、常見 Web 服務(wù)器漏洞攻擊、CSRF、核心文件非授權(quán)訪問、路徑穿越、網(wǎng)站被掃描等。
  • CC 惡意攻擊防護(hù):控制單一源 IP 的訪問頻率,基于重定向跳轉(zhuǎn)驗證、人機識別等。針對海量慢速請求攻擊,根據(jù)統(tǒng)計響應(yīng)碼及 URL 請求分布、異常 Referer 及 User-Agent 特征識別,結(jié)合網(wǎng)站精準(zhǔn)防護(hù)規(guī)則綜合防護(hù)。
  • 網(wǎng)站隱身:不對攻擊者暴露站點地址,避免其繞過 Web 應(yīng)用防火墻直接攻擊。

相關(guān)產(chǎn)品

目前 WAF 相關(guān)產(chǎn)品主要有三類:

  • 硬件 WAF:效果好,但是貴!
  • 軟件 WAF:效果還算可以,能用,有開源產(chǎn)品!
  • 云廠商 WAF:云廠商的 WAF 都很貴!

鑒于極客精神(白嫖萬歲 ??),這里介紹幾款業(yè)內(nèi)開源的 WAF 產(chǎn)品,

  • 長亭科技的雷池社區(qū)版,主頁地址:https://waf-ce.chaitin.cn/
  • ModSecurity,主頁地址:https://www.modsecurity.org/
  • Coraza,主頁地址:https://coraza.io/
  • VeryNginx,主頁地址:https://github.com/alexazhou/VeryNginx
  • NAXSI,主頁地址:https://github.com/nbs-system/naxsi
  • NGX_WAF,主頁地址:https://github.com/ADD-SP/ngx_waf
  • 南墻,主頁地址:https://waf.uusec.com/
  • JANUSEC,主頁地址:https://www.janusec.com/
  • HTTPWAF,主頁地址:https://github.com/httpwaf/httpwaf2.0
  • 錦衣盾,主頁地址:https://www.jxwaf.com/

對于以上 WAF 產(chǎn)品的一些評價指標(biāo)如下:

  • 防護(hù)效果:主要是兩個維度,能不能防住攻擊,會不會影響普通用戶
  • 技術(shù)先進(jìn)性:防護(hù)引擎的技術(shù)競爭力,是否具備對抗高級攻擊的能力
  • 項目質(zhì)量:本文將以功能完整性、開源代碼質(zhì)量、文檔完整性等角度作為評價依據(jù)
  • 社區(qū)認(rèn)可度:反映了項目在用戶社區(qū)中的聲譽和影響力,本文將以 GitHub Star 數(shù)作為評價依據(jù)
  • 社區(qū)活躍度:是潛力的體現(xiàn),活躍度越高發(fā)展越快,本文將以社區(qū)用戶的參與度和作者維護(hù)項目的積極性作為

最終的的得分如下,

圖片圖片

圖片來源https://stack.chaitin.com/techblog/detail/115

需要注意的是軟件 WAF 一般在第 7 層中進(jìn)行防御(osi 模型),并非能夠防御所有類型的攻擊,比如 ddos 攻擊就不能防御。不過一般云廠商提供的 WAF 產(chǎn)品也有攜帶了 ddos 攻擊防御的支持,比如阿里云。

OpenResty 在 WAF 中的應(yīng)用

使用 OpenResty 作為流量入口時,我們可以通過編寫一些 Lua 腳本來實現(xiàn) WAF 防御的功能。Lua 腳本可以在 Nginx 配置文件中指定,在不同的階段執(zhí)行。

對于防火墻功能,我們通常可以在 access_by_lua 階段執(zhí)行 Lua 腳本,用于匹配請求或響應(yīng)的頭部或內(nèi)容,并根據(jù)匹配結(jié)果決定是否放行數(shù)據(jù)包或返回錯誤信息。

下面我將給大家演示如何使用 OpenResty 實現(xiàn)一個基于 Lua 的 WAF(Web Application Firewall)功能。用來識別和阻止常見的 Web 攻擊,如 cc 防御、ip 黑名單、ua 參數(shù)校驗等。

cc 防御

  1. 修改 nginx.conf 文件,加入 access_by_lua_file cc.lua 指令,
http {
  # 聲明一個 10m 大小的共享內(nèi)存 cc_dict
  lua_shared_dict cc_dict 10m;
  lua_package_path "/usr/local/openresty/nginx/conf/lua/waf/?.lua;/usr/local/openresty/lualib/?.lua;";
  ...
  server {
    listen       88;
    server_name  localhost;

    # 在access階段執(zhí)行 cc 防御插件
    access_by_lua_file cc.lua;

    location / {
      ...
    }
  }
}
  1. 新建 cc.lua 腳本,寫入以下內(nèi)容,
-- 獲取客戶端ip
local function getClientIp()
    IP  = ngx.var.remote_addr
    if IP == nil then
        IP  = "unknown"
    end
    return IP
end

local function denyCC()
    local uri=ngx.var.uri
    ccCount=100
    ccSecnotallow=6
    local access_uri = getClientIp()..uri
    local limit = ngx.shared.cc_dict
    local req,_=limit:get(access_uri)
    if req then
        if req > ccCount then
            ngx.exit(503)
            return true
        else
            limit:incr(access_uri,1)
        end
    else
        limit:set(access_uri,1,ccSeconds)
    end
    return false
end

if denyCC() then
    return
end
  1. 重啟 OpenResty 服務(wù),就完成了 cc 防御功能。
openresty -s  reload

ip 黑名單

  1. 修改 nginx.conf 文件,加入 access_by_lua_file ip_block.lua 指令,
http {
  lua_package_path "/usr/local/openresty/nginx/conf/lua/waf/?.lua;/usr/local/openresty/lualib/?.lua;";
  ...
  server {
    listen       88;
    server_name  localhost;

    # 在access階段執(zhí)行 ip_block 防御插件
    access_by_lua_file ip_block.lua;

    location / {
      ...
    }
  }
}
  1. 新建 ip_block.lua 腳本,寫入以下內(nèi)容,
local cjson = require "cjson"

local function read_json(var)
    file = io.open(var,"r")
    if file==nil then
        return
    end
    str = file:read("*a")
    file:close()
    list = cjson.decode(str)
    return list
end

local function getClientIp()
    IP  = ngx.var.remote_addr
    if IP == nil then
        IP  = "unknown"
    end
    return IP
end

local function blockIpCheck()
    local ipBlockList=read_json('/usr/local/openresty/nginx/conf/lua/waf/ip_block.json')
    if next(ipBlockList) ~= nil then
        for _,ip in pairs(ipBlockList) do
            if getClientIp()==ip then
                ngx.exit(403)
                return true
            end
        end
    end
    return false
end

if blockIpCheck() then
    return
end
  1. 在 /usr/local/openresty/nginx/conf/lua/waf 目錄下新建 ip_block.json 文件,寫入我們要加入黑名單的 ip,
["58.48.224.7"]
  1. 重啟 OpenResty 服務(wù),就完成了 ip 黑名單功能。
openresty -s  reload

ua 攔截

  1. 修改 nginx.conf 文件,加入 access_by_lua_file ua.lua 指令,
http {
  lua_package_path "/usr/local/openresty/nginx/conf/lua/waf/?.lua;/usr/local/openresty/lualib/?.lua;";
  ...
  server {
    listen       88;
    server_name  localhost;

    # 在access階段執(zhí)行 ua 防御插件
    access_by_lua_file ua.lua;

    location / {
      ...
    }
  }
}
  1. 新建 ua.lua 腳本,寫入以下內(nèi)容,
local ngxMatch=ngx.re.match
local cjson = require "cjson"

local function read_json(var)
    file = io.open(var,"r")
    if file==nil then
        return
    end
    str = file:read("*a")
    file:close()
    list = cjson.decode(str)
    return list
end

function ua()
    local ua = ngx.var.http_user_agent
    local userAgents=read_json('/usr/local/openresty/nginx/conf/lua/waf/user_agent.json')
    if next(userAgents) ~= nil then
        for _,rule in pairs(userAgents) do
            if rule ~="" and ngxMatch(ua,rule,"isjo") then
                ngx.exit(403)
                return true
            end
        end
    end
    return false
end

if ua() then
    return
end
  1. 在 /usr/local/openresty/nginx/conf/lua/waf 目錄下新建 user_agent.json 文件,寫入我們要加入黑名單的 ua 信息,
["Chrome/116.0.0.0"]
  1. 重啟 OpenResty 服務(wù),就完成了 ua 攔截功能。
openresty -s  reload

相關(guān)資料

  • OpenResty 官網(wǎng):https://openresty.org/cn/benchmark.html
  • 菜鳥教程:https://www.runoob.com/lua/lua-tutorial.html
  • 《OpenResty完全開發(fā)指南》:https://weread.qq.com/web/bookDetail/fec3240071848696fec3572
  • 《OpenResty從入門到實戰(zhàn)》:https://time.geekbang.org/column/intro/186?code=hkx6qkdp47iccvn0yf40aowqzyzzchyykmswfogb90g%3D

總結(jié)

自此本文介紹了OpenResty入門以及使用 Lua 腳本實現(xiàn)一些常見的網(wǎng)關(guān)安全功能等。需要注意的就是大家在已有的 Nginx 服務(wù)遷移到 OpenResty 上來時,記得注意 OpenResty 版本,Nginx 與 OpenResty 相同版本情況下,OpenResty 官方是保證完全兼容的。

責(zé)任編輯:武曉燕 來源: waynblog
相關(guān)推薦

2024-04-10 12:36:41

硬件代碼

2019-05-21 16:19:46

前端性能優(yōu)化圖片

2013-03-20 17:58:41

虛擬內(nèi)存程序員

2018-03-27 23:15:11

2023-04-10 10:30:42

2022-10-31 08:02:07

Python函數(shù)式編程

2019-08-21 10:15:41

開發(fā)Redis數(shù)據(jù)

2018-01-23 08:42:34

2012-02-28 10:52:13

2018-03-07 12:57:53

2017-10-24 14:21:30

機器學(xué)習(xí)人工智能算法

2014-01-09 14:43:40

Linux用戶命令行

2020-01-14 08:28:50

Linux命令程序

2014-03-07 14:20:30

2017-04-05 12:04:17

python函數(shù)

2022-05-26 07:31:42

索引SQL后端

2023-07-11 16:45:32

VS Code開發(fā)技巧

2024-05-28 11:38:32

2020-08-07 07:56:50

Ubuntu快捷鍵Windows

2019-05-24 09:04:31

C++編程語言開發(fā)
點贊
收藏

51CTO技術(shù)棧公眾號

网站永久看片免费| 麻豆成人av| 91香蕉一区二区三区在线观看| 精品肉辣文txt下载| 欧美—级在线免费片| 国产精品一二三在线| 少妇高潮在线观看| 日韩免费成人| 精品久久久在线观看| 欧美精品亚洲| 国产精品久久久久久久久毛片 | 日本亚洲欧洲色α| 福利视频第一页| 久久精品福利| 欧美日韩黄色影视| www黄色日本| a视频在线观看免费| 久久综合九色综合97婷婷| 91色在线视频| 日本欧美www| 一区免费视频| 久久久av一区| 欧美成人另类视频| 伦理一区二区三区| 日韩欧美中文字幕精品| 色综合天天色综合| 久草在线中文最新视频| 亚洲三级在线观看| 欧美成人一区二区在线| 亚洲不卡免费视频| 精品一区二区三区视频| 国产精品美女主播| 三级网站在线播放| 中文高清一区| 久久久久久久电影一区| 日本精品人妻无码77777| 日韩国产一区二区| 一区二区三区天堂av| 中文字幕乱码在线| 岛国精品一区| 精品欧美乱码久久久久久| 色婷婷一区二区三区av免费看| 三上悠亚激情av一区二区三区 | 中文字幕亚洲情99在线| 国产精品揄拍100视频| 久久久久久毛片免费看| 亚洲精品在线一区二区| 手机看片国产精品| 香蕉久久一区| 亚洲h精品动漫在线观看| 天天好比中文综合网| 色播色播色播色播色播在线| 成人午夜又粗又硬又大| 5566中文字幕一区二区| 91一区二区视频| 久久se这里有精品| 亚洲天堂视频在线播放| 国产一区二区三区久久久久久久久 | 1024av视频| 精品丝袜在线| 欧美日韩一区二区三区| 亚洲熟妇国产熟妇肥婆| 国产乱码精品一区二三赶尸艳谈| 精品久久中文字幕久久av| 国产精品吊钟奶在线| 日韩精品在线免费视频| 老鸭窝亚洲一区二区三区| 2019日本中文字幕| 国产精品久久久久久久久久精爆| 亚洲综合国产| 国产精品高潮呻吟久久av黑人| 亚洲精品国产欧美在线观看| 久久se精品一区精品二区| 亚洲va欧美va国产综合剧情| 亚洲国产欧美另类| 97se亚洲国产综合在线| 欧洲精品国产| 乱人伦中文视频在线| 亚洲欧美另类久久久精品2019| 国产精品88久久久久久妇女| 大菠萝精品导航| 亚洲欧美综合色| 免费看欧美黑人毛片| 在线女人免费视频| 欧美日韩国产片| 蜜桃视频无码区在线观看| 久久a爱视频| 中文字幕欧美日韩在线| 青青草手机在线观看| 夜久久久久久| 成人激情在线观看| 天天干天天操av| 国产精品视频观看| 日韩精品在线中文字幕| 日韩免费福利视频| 日韩欧美一级二级三级久久久| 偷偷色噜狠狠狠狠的777米奇| 精品99久久| 欧美大片第1页| 免费污污视频在线观看| 国产久卡久卡久卡久卡视频精品| 久久国产精品免费一区| 麻豆网在线观看| 欧美日韩一二三四五区| 伊人影院综合在线| 美日韩黄色大片| 日韩在线观看免费高清完整版| 久久午夜无码鲁丝片午夜精品| 视频一区欧美精品| 99一区二区三区| 第九色区av在线| 亚洲国产一区二区在线播放| 国产福利在线免费| 亚洲国产最新| 欧美精品免费看| 国产免费a视频| 成人av电影在线观看| 午夜啪啪福利视频| 欧美精品资源| 亚洲精品美女免费| 私库av在线播放| 久久aⅴ国产欧美74aaa| 视频三区二区一区| 日本在线啊啊| 精品对白一区国产伦| 手机在线免费看片| 久久国产精品99久久久久久老狼| 麻豆成人在线播放| 国产啊啊啊视频在线观看| 在线不卡免费欧美| 精品一区二区三孕妇视频| 欧美一级一区| 精品九九九九| 成人三级高清视频在线看| 欧美不卡一区二区三区四区| а天堂中文在线资源| 日本亚洲三级在线| 欧美日韩一区二区视频在线观看| 国产99在线观看| 欧美成人一区二区三区在线观看| 国产67194| 韩国一区二区视频| 一区视频二区视频| 久久不卡日韩美女| 日韩亚洲国产中文字幕| 在线免费看毛片| 国产精品第五页| xx欧美撒尿嘘撒尿xx| 欧洲激情视频| 国产欧美va欧美va香蕉在线| 97电影在线观看| 欧美日韩国产一级二级| 亚洲一区电影在线观看| 老汉av免费一区二区三区| 亚洲精品国产精品国自产观看| 日本精品网站| 日韩中文娱乐网| 国产99视频在线| 一区二区三区四区亚洲| xxxx视频在线观看| 亚洲三级国产| 美脚丝袜一区二区三区在线观看| 亚洲天堂导航| 国产亚洲视频在线| 国产又大又黑又粗| 樱花草国产18久久久久| 久草视频福利在线| 免费亚洲网站| 亚洲欧美日韩精品在线| 色成人综合网| 久久久久久久久电影| 日本在线一二三| 亚洲一区中文| 国产亚洲福利社区| 伊人色综合一区二区三区影院视频| 亚洲欧美日韩另类| av在线免费观看不卡| 伊人成人在线视频| 国产精品久久久久77777| 久久这里只有精品免费| 久久裸体网站| 午夜精品一区在线观看| 欧美午夜精品久久久久久孕妇| 91精品国产色综合久久不卡98口| 国产精品久久久免费观看| 欧美系列精品| 欧美一区二区视频在线观看2020| 97在线观看免费视频| 精品亚洲aⅴ乱码一区二区三区| 日韩精品免费一区| 99精品在线视频观看| 美女一区二区三区| 国产人妻人伦精品| 中文字幕日韩经典| 国产精品主播| 欧美大片在线看免费观看| 亚洲区一区二区三| 欧美+日本+国产+在线a∨观看| 国产97色在线|日韩| 国产极品美女高潮无套嗷嗷叫酒店| 国产精品久久| 欧美激情在线播放| 女教师淫辱の教室蜜臀av软件| 亚洲欧洲av| 在线播放国产一区二区三区| 久久精品一区二区免费播放 | 国产精品美女久久久久久久久 | 久久久久五月天| www.亚洲自拍| 精品国产乱子伦一区二区| 国产亚洲欧洲黄色| 污污网站免费观看| 亚洲人成人一区二区三区| 亚洲精品视频网上网址在线观看| 国产性生活网站| 国产精品麻豆欧美日韩ww| 天堂精品一区二区三区| 欧美v亚洲v| 日本精品免费观看高清观看| 国产精品成人一区二区三区电影毛片| 国产在线视频精品一区| 国产91对白刺激露脸在线观看| 国产va免费精品观看精品| xxx一区二区| 草久久免费视频| 久久久精品免费免费| 欧美亚洲国产免费| 亚洲国产精品免费视频| 亚洲欧美国产日韩天堂区| 天堂中文在线网| 日韩精品乱码av一区二区| 日本中文不卡| 自拍偷拍 国产| 嫩草影视亚洲| 亚洲一区二区在线| 亚洲黑人在线| 国产午夜精品美女视频明星a级| 国产成人自拍网站| 久久精品国产亚洲一区二区三区| 亚洲欧美久久久久一区二区三区| 精品国产一区二区三区2021| 亚洲香蕉成视频在线观看| 国产精品无码天天爽视频| 精品视频1区2区3区| 亚洲熟女综合色一区二区三区| 国产精品一品二品| 欧美在线精品免播放器视频| 欧美日韩综合一区二区三区| 国产成人亚洲综合a∨猫咪| 免费的av在线| 亚洲h色精品| 久久99精品国产99久久6尤物| 国产高清免费av在线| 亚洲在线观看免费| 全黄一级裸体片| 欧美午夜在线视频| 日本在线观看不卡| 三级网站视频在在线播放| 久久精品女人| 97欧美精品一区二区三区| 天天干,天天操,天天射| 91精品欧美综合在线观看最新| 国产偷久久久精品专区| www.成人网| 国外视频精品毛片| 五月婷婷在线观看| 91国产丝袜在线播放| 麻豆免费在线观看视频| 国产日产一区 | 午夜一级久久| 99久久99| 都市激情亚洲| 亚洲三级av在线| 99精品视频99| 国产精品一级二级三级| 亚洲欧美激情四射在线日| 亚欧在线免费观看| 国产日韩欧美| 九九九九九九精品| 日韩精品免费一区二区三区竹菊| 欧美日韩不卡一区| 日韩网站在线播放| 99久久99久久精品国产片桃花 | 国产日产欧美一区二区| 国产美女一区视频| 欧美精三区欧美精三区| 亚洲天堂岛国片| 国产日本精品| 成人国产精品免费视频| 欧美黄色aaa| 日本va欧美va瓶| 国产精品影片在线观看| 男人天堂视频网| japanese色国产在线看视频| 国产精品二区一区二区aⅴ污介绍| 一级黄色特级片| 日韩在线观看一区| 92裸体在线视频网站| 国产网友自拍视频导航网站在线观看| 亚洲福利视频三区| 亚洲国产精品毛片av不卡在线| 日韩电影免费观| 欧美日韩国产成人在线| 国产黄色免费在线观看| av高清不卡在线| 日韩精品在线中文字幕| 国产区一区二| 精品久久久久av影院| 国产a免费视频| 欧美天天在线| 欧洲美女7788成人免费视频| 色综合成人av| 欧美激情精品久久久久久久变态| 久久99久久99精品免观看软件| 999日本视频| 99久久.com| 亚洲天堂av线| 91在线观看地址| 久久久久久久久久99| 欧美精品在线一区二区| 成年在线观看免费人视频| 98精品国产高清在线xxxx天堂| 亚洲天堂中文字幕在线观看| 中文字幕剧情在线观看一区| 日韩黄色一级片| 国产精品无码永久免费不卡| 亚洲福中文字幕伊人影院| 国产原创中文av| www高清在线视频日韩欧美| 成人做爰视频www网站小优视频| 久久久一本精品99久久精品66| 国模大胆一区二区三区| 色婷婷狠狠18禁久久| 亚洲免费观看在线视频| 国产美女www| 国产亚洲视频在线观看| www.精品国产| 午夜精品视频在线观看一区二区| 久久久蜜桃一区二区人| 亚洲一区二区观看| 午夜a成v人精品| 四虎电影院在线观看| 欧美在线视频观看| 一区二区三区韩国免费中文网站| 欧美日韩亚洲一| 久久先锋资源网| 免费的毛片视频| 国产亚洲欧美另类中文| 国产一区二区三区四区五区3d| 亚洲欧美一区二区原创| 激情五月激情综合网| 99久久99久久精品国产| 日韩精品综合一本久道在线视频| 欧美videossex| 久久久久久久久久久久久久久久av| 亚洲一区二区三区免费在线观看| 一级性生活大片| 91福利视频网站| 夜级特黄日本大片_在线 | 成人豆花视频| www.18av.com| www.亚洲人| 欧美一区二区三区网站| 在线视频欧美日韩| www 久久久| av网站手机在线观看| 久久网站热最新地址| 涩涩视频在线观看| 不卡av电影在线观看| 国产精品自在| 日韩精品一区中文字幕| 国产精品麻豆99久久久久久| 国产超碰人人模人人爽人人添| 久久免费少妇高潮久久精品99| 香蕉久久夜色精品国产使用方法 | 久久艹免费视频| 一区二区三区国产在线观看| 国产精品毛片无码| 国产h视频在线播放| 国产精品视频一二三| 亚洲欧美另类视频| 国产精品久久久久久中文字| 你懂的一区二区| 人妻av无码一区二区三区| 欧美丰满高潮xxxx喷水动漫| 久草在线资源福利站| 亚洲在线不卡| 99国产精品久久久久| 在线观看一二三区| 性欧美暴力猛交69hd| 久久一本综合| 亚洲av成人精品一区二区三区 | 亚洲天堂2018av| 午夜伊人狠狠久久| 欧美成人二区| 韩国成人av| 国产丶欧美丶日本不卡视频| 亚洲国产av一区二区三区| 欧美激情精品久久久| 国产国产精品|