Nginx+Lua实战

Lua脚本基础语法

Lua 是⼀个简洁、轻量、可扩展的脚本语⾔
Nginx+Lua优势
充分的结合Nginx的并发处理epool优势和Lua的轻量实现简单的功能且⾼并发的场景
统计IP
统计⽤户信息
安全WAF

1.安装 lua
[root@Nginx-Lua ~]# yum install lua -y

2. lua 的运⾏⽅式
//命令⾏执⾏, 交互式
[root@Nginx-Lua ~]# lua
Lua 5.1.4 Copyright (C) 1994-2008 Lua.org, PUC-Rio
> print("Hello,World")
Hello,World

//⽂件执⾏⽅式, ⾮交互式
[root@nginx-php-k-1 lua]# pwd
/soft/lua
[root@Nginx-Lua ~]# cat test.lua
#!/usr/bin/lua
print("Hi is xu!")
[root@Nginx-Lua ~]# lua ./test.lua
Hi is xu!

3.Lua的注释语法
// --⾏注释
#!/usr/bin/lua
--print("Hi is xu!")

//块注释
--[[
 注释代码
--]]

4.Lua的基础语法
变量定义
a = 123

// 注意事项
//布尔类型只有true和false
//数字0,空字符串都是true
//lua中的变量如果没有特殊说明, 全是全局变量

# while 循环语句
计算1+2+3..+100

[root@nginx lua]# cat while.lua
#!/usr/bin/lua
sum =0
num =1
while num <= 100 do
 sum = sum + num
 num = num + 1
end
print("sum=",sum)
//执⾏结果
[root@nginx lua]# lua while.lua
sum= 5050
//Lua没有++或是+=这样的操作

# for 循环语句
循环1..100个数,sum每次+1到100

[root@nginx lua]# cat for.lua
#!/usr/bin/lua
sum = 0
for i = 1,100 do
 sum = sum + 1
 print("i=",i,"sum",sum)
end
print("sum=", sum)
//执⾏结果
[root@nginx ~]# lua for.lua
sum= 100

# if 判断语句

[root@nginx lua]# cat if.lua
#!/usr/bin/lua
age=30
sex="Man"
if age == 40 and sex == "Man" then
 print("男⼈⼤于40")
 elseif age > 60 and sex ~= "Woman" then
 print("⾮⼥⼈⽽且⼤于60")
 else
 local age = io.read()
 print("Your age is",age)
 end
//~=是不等于
//字符串的拼接操作符".."
//io库的分别从stdin和stdout读写,read和write函数
[root@nginx lua]# lua if.lua
10
Your age is 1

Nginx加载Lua环境

默认情况下 Nginx 不⽀持 Lua 模块, 需要安装 LuaJIT 解释器, 并且需要重新编译 Nginx , 本次使⽤ openrestry
LuaJIT
Ngx_devel_kit和lua-nginx-module

LuaJIT是⼀种⾼性能的 Just-In-Time (JIT) 编译器实现的Lua解释器,它基于 Lua 5.1 版本,但是它不仅仅是⼀个解释器,更是⼀个集成了 JIT 编译器、动态类型机制、⾼效 GC 等新特性的 Lua 实现。LuaJIT 通过使⽤⼀种叫做“ Trace 编译”的技术,将 Lua 代码动态地翻译成本地机器码,因此 LuaJIT 具有⾮常⾼的执⾏性能和内存利⽤率。相应地,LuaJIT 还对 Lua 语法进⾏了扩充和改进,同时保留了原有的语法和 API 接⼝,完全兼容 Lua5.1。

与原⽣的 Lua 解释器相⽐,LuaJIT 可以将 Lua 代码的执⾏速度提升数⼗倍,这使得 LuaJIT 在需要⾼性能和低延迟的场合下⼗分适⽤,⽐如在计算机游戏开发、⽹络服务器和嵌⼊式系统等领域,都能发挥出⾮常显著的优势。另外,在某些特定场景中,例如进⾏⼤量矩阵运算的科学计算和数学模拟等,LuaJIT 可以⽐纯 C 代码还要快。

除了性能和语⾔扩展⽅⾯的改进之外,LuaJIT 还具有良好的可移植性和稳定性,⽀持多平台(包括 x64、arm 和MIPS 等);还提供了 C 语⾔ API 接⼝,⽅便 LuaJIT 与其他语⾔集成使⽤。综上,LuaJIT 是⼀个⾮常优秀的Lua 实现,⼴泛应⽤于众多场合。

1.环境准备
[root@nginx ~]# yum -y install gcc gcc-c++ make pcre-devel zlib-devel openssl-devel

2.下载最新的 luajit 和 ngx_devel_kit 以及 lua-nginx-module
[root@nginx ~]# mkdir -p /soft/src && cd /soft/src
[root@nginx ~]# wget http://luajit.org/download/LuaJIT-2.0.4.tar.gz
[root@nginx ~]# wget https://github.com/simpl/ngx_devel_kit/archive/v0.2.19.tar.gz
[root@nginx ~]# wget https://github.com/openresty/lua-nginxmodule/archive/v0.10.13.tar.gz
[root@nginx ~]#https://github.com/openresty/echo-nginxmodule/archive/refs/tags/v0.63.tar.gz

3.解压 ngx_devel_kit 和 lua-nginx-module
//解压后为ngx_devel_kit-0.2.19
[root@nginx ~]# tar xf v0.2.19.tar.gz
//解压后为lua-nginx-module-0.9.16
[root@nginx ~]# tar xf v0.10.13.tar.gz

4.安装 LuaJIT Luajit 是 Lua 即时编译器。
[root@nginx ~]# tar zxvf LuaJIT-2.0.4.tar.gz
[root@nginx ~]# cd LuaJIT-2.0.4
[root@nginx ~]# make && make install

5. 安装 echo 模块
tar xf v0.63.tar.gz

6.安装 Nginx 并加载模块
[root@nginx ~]# cd /soft/src
[root@nginx ~]# wget http://nginx.org/download/nginx-1.21.0.tar.gz
[root@nginx ~]# tar xf nginx-1.21.0.tar.gz
[root@nginx ~]# cd nginx-1.21.0
./configure --prefix=/usr/local/nginx/ --with-http_ssl_module \
--with-http_stub_status_module --with-http_dav_module \
--add-module=../ngx_devel_kit-0.2.19/ \
--add-module=../lua-nginx-module-0.10.13 \
--add-module=../echo-nginx-module-0.63
[root@nginx ~]# make -j2 && make install

//建⽴软链接, 不建⽴会出现share object错误
ln -s /usr/local/lib/libluajit-5.1.so.2 /lib64/libluajit-5.1.so.2

//4.加载lua库,加⼊到ld.so.conf⽂件
echo "/usr/local/LuaJIT/lib" >> /etc/ld.so.conf
ldconfig

也可以直接部署春哥的开源项⽬:https://openresty.org/cn/

//安装依赖包
# yum install -y readline-devel pcre-devel openssl-devel
# cd /soft/src

下载并编译安装openresty
# wget https://openresty.org/download/ngx_openresty-1.9.3.2.tar.gz
# tar zxf ngx_openresty-1.9.3.2.tar.gz
# cd ngx_openresty-1.9.3.2
# ./configure --prefix=/soft/openresty-1.9.3.2 \
--with-luajit --with-http_stub_status_module \
--with-pcre --with-pcre-jit
# gmake && gmake install
# ln -s /soft/openresty-1.9.3.2/ /soft/openresty

#配置
[root@180-143 conf]# cd /soft/openresty-1.9.3.2/nginx/conf
[root@180-143 conf]# cat nginx.conf
worker_processes 1;
events {
 worker_connections 1024;
}
http {
 include mime.types;
 default_type application/octet-stream;
 sendfile on;
 keepalive_timeout 65;
 include ./conf.d/*.conf ;
}
#测试openresty安装
# vim /soft/openresty/nginx/conf/nginx.conf
server {
 listen 80;
 server_name www.wingsredevsecops.top;
 location /hello {
 default_type text/html;
 content_by_lua_block {
 content_by_lua 'ngx.say("hello ,lua scripts")';
 }
 }
}
# 启动openresty
[root@nginx-php-k-1 conf.d]# /soft/openresty/nginx/sbin/nginx

Nginx调⽤Lua指令

Nginx 调⽤ Lua 模块指令, Nginx的可插拔模块加载执⾏

set_by_lua set_by_lua_file 设置Nginx变量,可以实现负载的赋值逻辑
access_by_lua access_by_lua_file 请求访问阶段处理, ⽤于访问控制
content_by_lua content_by_lua_file 内容处理器, 接受请求处理并输出响应

Nginx 调⽤ Lua API

ngx.var nginx变量
ngx.req.get_headers 获取请求头
ngx.req.get_uri_args 获取url请求参数
ngx.redirect 重定向
ngx.print 输出响应内容体
ngx.say 输出响应内容体,最后输出⼀个换⾏符
ngx.header 输出响应头

# set_by_lua 和 set_by_lua_file
set_by_lua 和 set_by_lua_file :这两个模块都⽤于设置 Nginx 变量。set_by_lua 通过 inline Lua 代码设置变量的
值,set_by_lua_file 则可以通过引⼊ Lua 脚本⽂件来设置变量。这两个模块通常⽤于实现负载的赋值逻辑,如根据
请求的 headers 头部信息等进⾏动态变量设置。

/soft/openresty-1.9.3.2/nginx/conf/conf.d/luasetbylua.conf
upstream backend {
 server 10.1.106.66:8081 weight=1;
 server 10.1.106.66:8082 weight=1;
} 
server {
 listen 80;
 server_name luasetbylua.wingsredevsecops.top;
 location /hello {
 default_type text/html;
 content_by_lua_block {
 ngx.say("HelloWorld")
 }
 }
 location / {
 set $backend 'backend';
 set_by_lua_file $backend_lua_file /soft/openresty-
1.9.3.2/nginx/conf/lua/backend.lua;
 proxy_pass http://$backend;
 }
}

/soft/openresty-1.9.3.2/nginx/conf/lua/backend.lua
# cat /soft/openresty-1.9.3.2/nginx/conf/lua/backend.lua
-- backend.lua
if ngx.var.remote_addr == '127.0.0.1' then
 -- Use 10.1.106.66:8081 for local requests
 ngx.var.backend = '10.1.106.66:8081';
else
 -- Use 10.1.106.66:8082 for remote requests
 ngx.var.backend = '10.1.106.66:8082';
end

[root@nginx-php-k-1 conf.d]# cat /etc/hosts
127.0.0.1 luasetbylua.wingsredevsecops.top

# access_by_lua 和 access_by_lua_file
access_by_lua 和 access_by_lua_file :这两个模块⽤于在 Nginx 处理请求的访问阶段(access phase)执⾏ Lua
代码,⼀般⽤于请求的认证和访问控制。例如,可以使⽤ Lua 脚本从请求的 headers 中提取⽤户凭证,然后进⾏
⽤户认证并判断权限,以决定是否允许请求继续执⾏。

假设我们有⼀个 API,需要进⾏鉴权,只有拥有正确的 token 的请求才能访问。

我们可以使⽤ access_by_lua 或 access_by_lua_file 在 Nginx 的 access 阶段进⾏鉴权逻辑的实现,例如:
[root@180-143 conf.d]# cat luaaccess.conf
 upstream backend1 {
 server 10.1.106.66:8081;
 } 
server {
 listen 80;
 server_name luaaccess.wingsredevsecops.top;
 location /api {
 # 鉴权
 access_by_lua '
 local token = ngx.var.http_authorization
 if token ~= "SECRET-TOKEN" then
 return ngx.exit(ngx.HTTP_UNAUTHORIZED)
 end
 ';
 # 路由到 backend1
 set $backend "backend1";
 proxy_pass http://$backend/;
 }
 }

在这个例⼦中,我们使⽤ access_by_lua 进⾏鉴权,如果请求头中的 Authorization 值不为 "SECRETTOKEN" ,我们返回 HTTP 401 错误,不继续处理请求。
如果鉴权通过,我们设置 $backend 变量的值为 backend1 ,并将请求转发给
http://backend1.example.com 。
这样,我们就可以使⽤ access_by_lua 或 access_by_lua_file 实现访问控制和 API 鉴权的逻辑。

[root@nginx-php-k-1 conf.d]# curl 'http://luaaccess.wingsredevsecops.top/api' --header
'Authorization: SECRET-TOKEN'
<html>
 <title> Code1</title>
 <body bgcolor="red">
 <h1> Code1-8081 </h1>
 </body>
</html>

通过postman 验证测试

# content_by_lua 和 content_by_lua_file
content_by_lua 和 content_by_lua_file :这两个模块⽤于在 Nginx 处理请求的内容处理阶段(content phase)
中执⾏ Lua 代码,⼀般⽤于实现特殊的应⽤逻辑或添加数据处理扩展等。 例如,可以使⽤ Lua 脚本处理请求体中
的 JSON 数据,或通过调⽤其他服务的 API 添加⼀些附加的数据处理功能。 处理完毕后,⽤于的 Lua 脚本需要返
回数据,以便 Nginx 输出给客户端。
luacontent.conf
下⾯我们来举⼀个使⽤ content_by_lua 的例⼦,假设我们的业务流程是根据不同请求头的值返回不同的响应内
容。我们可以使⽤ content_by_lua 阶段在 Nignx 中进⾏⾃定义处理。

 server {
 listen 80;
 server_name luacontent.wingsredevsecops.top;
 location / {
 # 进⾏⾃定义处理
 content_by_lua '
 local headers = ngx.req.get_headers()
 local response = ""
 if headers["User-Agent"] == "mobile" then
 response = "Hello mobile user!"
 else
 response = "Hello desktop user!"
 end
 ngx.say(response)
 ';
 }
 }

在这个例⼦中,我们使⽤ content_by_lua 阶段根据请求头中的 User-Agent 做出不同的响应。如果 User-Agent
是 mobile,就返回 "Hello mobile user!";否则返回 "Hello desktop user!"。我们使⽤ ngx.say 输出响应内容。
类似地,我们也可以使⽤ content_by_lua_file 指令来指定⼀个 lua ⽂件进⾏处理。这种⽅式可以更好地分离
业务逻辑和 Nginx 配置⽂件,⽅便代码维护和更新。

Nginx+Lua实现代码灰度发布

使⽤ Nginx 结合 lua 实现代码灰度发布
灰度发布是⼀种将新版本的软件或功能逐步推⼴给⼀⼩部分⽤户,以进⾏测试和评估它们的反应的⽅法。实
际上,它是⼀种渐进式的部署⽅法,可以逐步将新版本或功能逐步发布给不同的⽤户群体,直到所有⽤户都
可以使⽤这个新版本或功能。
这种⽅法通常⽤于⼤规模应⽤程序和⽹站,以确保新的功能和修复⼯作的质量,并降低和减少出现故障或负
⾯反应的⻛险。在灰度发布期间,团队可以监测应⽤程序或⽹站的性能并调整它们,以便可以全⾯推⼴给所
有⽤户。

按照⼀定的关系区别,分部分的代码进⾏上线,使代码的发布能平滑过渡上线
1.⽤户的信息cookie等信息区别
2.根据⽤户的ip地址, 颗粒度更⼴

执⾏过程:
1.⽤户请求到达前端代理Nginx, 内嵌的lua模块会解析Nginx配置⽂件中Lua脚本
2.Lua脚本会获取客户端IP地址,查看Memcached缓存中是否存在该键值
3.如果存在则执⾏@java_test,否则执⾏@java_prod
4.如果是@java_test, 那么location会将请求转发⾄新版代码的集群组
5.如果是@java_prod, 那么location会将请求转发⾄原始版代码集群组
6.最后整个过程执⾏后结束

1.安装两台服务器 Tomcat ,分别启动 8080 和 9090 端⼝
jdk下载

# 10.1.106.66服务器操作
[root@tomcat-node1-20 ~]# pwd
/app/soft

[root@tomcat-node1-20 ~]# ll
-rw------- 1 root root 194151339 4⽉ 28 21:20 jdk-8u231-linux-x64.tar.gz
[root@tomcat-node1-20 ~]# tar xf jdk-8u231-linux-x64.tar.gz -C /app
[root@tomcat-node1-20 ~]# cd /app/ && mv jdk1.8.0_231 jdk1.8
[root@tomcat-node1-20 ~]#cat /etc/profile.d/jdk.sh
export JAVA_HOME=/app/jdk1.8
export PATH=$JAVA_HOME/bin:$PATH
export CLASSPATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
[root@tomcat-node1-20 ~]# chmod +x /etc/profile.d/jdk.sh
[root@tomcat-node1-20 ~]# source /etc/profile
[root@tomcat-node1-20 ~]# java -version
java version "1.8.0_231"
Java(TM) SE Runtime Environment (build 1.8.0_231-b11)
Java HotSpot(TM) 64-Bit Server VM (build 25.231-b11, mixed mode)
#安装tomcat
[root@tomcat-node1-20 ~]# mkdir /soft/src -p
[root@tomcat-node1-20 ~]# cd /soft/src
[root@nginx ~]# wget https://mirrors.tuna.tsinghua.edu.cn/apache/tomcat/tomcat-
9/v9.0.74/bin/apache-tomcat-9.0.74.tar.gz --no-check-certificate
[root@tomcat-node1-20 src]# tar xf apache-tomcat-9.0.74.tar.gz -C /soft
[root@tomcat-node1-20 src]# cd ..
[root@tomcat-node1-20 soft]# mv apache-tomcat-9.0.74/ tomcat-8080
[root@tomcat-node1-20 soft]# /soft/tomcat-8080/bin/startup.sh
#启动9090
[root@tomcat-node1-20 soft]# cp -r tomcat-8080 tomcat-9090
[root@tomcat-node1-20 soft]# cd tomcat-9090/conf/
[root@tomcat-node1-20 soft]# vim server.xml
#修改⼀下内容
 <Connector port="8080" protocol="HTTP/1.1"
 connectionTimeout="20000"
 redirectPort="8443"
 maxParameterCount="1000"
 />
#最新的内容
<Server port="8006" shutdown="SHUTDOWN">
 <Connector port="9090" protocol="HTTP/1.1"
 connectionTimeout="20000"
 redirectPort="8444"
 maxParameterCount="1000"
 />
[root@tomcat-node1-20 conf]# cd ..
[root@tomcat-node1-20 tomcat-9090]# cd bin/
[root@tomcat-node1-20 bin]# sh startup.
sh: startup.: 没有那个⽂件或⽬录
[root@I bin]# sh startup.sh
Using CATALINA_BASE: /soft/tomcat-9090
Using CATALINA_HOME: /soft/tomcat-9090
Using CATALINA_TMPDIR: /soft/tomcat-9090/temp
Using JRE_HOME: /app/jdk1.8
Using CLASSPATH: /soft/tomcat-9090/bin/bootstrap.jar:/soft/tomcat-
9090/bin/tomcat-juli.jar
Using CATALINA_OPTS: 
Tomcat started.
[root@tomcat-node1-20bin]# netstat -lntup |egrep 9090
tcp6 0 0 :::9090 :::* LISTEN 
19153/java 
//注意tomcat默认监听在8080端⼝, 如果需要启动9090端⼝需要修改server.xml配置⽂件
#修改9090站点⻚⾯
[root@tomcat-node1-20]# cd /soft/tomcat-9090/webapps/ROOT
[root@@tomcat-node1-20 ROOT]# vim index.jsp
 <title>9090-tomcat <%=request.getServletContext().getServerInfo() %></title>

访问8080 和 9090

2.配置 Memcached 并让其⽀持 Lua 调⽤
# 10.1.106.70
//安装memcached服务
[root@Nginx-Lua ~]# yum install memcached -y
//配置memcached⽀持lua
[root@Nginx-Lua ~]# cd /soft/src
[root@Nginx-Lua ~]# wget https://github.com/agentzh/lua-restymemcached/archive/v0.11.tar.gz
[root@Nginx-Lua ~]# tar xf lua-resty-memcached-0.11.tar.gz
[root@Nginx-Lua ~]# mkdir -p /soft/openresty/nginx/lua/
[root@Nginx-Lua ~]# cp -r lua-resty-memcached-0.11/lib/resty/memcached.lua
/soft/openresty/nginx/lua/
//启动memcached
[root@Nginx-Lua ~]# systemctl start memcached
[root@Nginx-Lua ~]# systemctl enable memcached
[root@Nginx-Lua ~]## systemctl status memcached
● memcached.service - Memcached
 Loaded: loaded (/usr/lib/systemd/system/memcached.service; enabled; vendor preset:
disabled)
 Active: active (running) since 六 2023-05-06 14:45:55 CST; 5s ago
 Main PID: 26515 (memcached)
 CGroup: /system.slice/memcached.service
└─26515 /usr/bin/memcached -u memcached -p 11211 -m 64 -c 1024
5⽉ 06 14:45:55 180-143 systemd[1]: Started Memcached.

3.配置负载均衡调度
/soft/openresty/nginx/conf/

#必须在http层
lua_package_path "/soft/openresty/nginx/lua/memcached.lua";
#稳定代码 8080
upstream java_prod {
 server 10.1.106.66:8080;
}
#最新代码 灰度测试
upstream java_test {
 server 10.1.106.66:9090;
}
server {
 listen 80;
 server_name www.wingsredevsecops.top;
location /hello {
 default_type 'text/plain';
 content_by_lua 'ngx.say("hello ,lua scripts")';
 }
 location /myip {
 default_type 'text/plain';
 content_by_lua '
 clientIP = ngx.req.get_headers()["x_forwarded_for"]
 ngx.say("Forwarded_IP:",clientIP)
 if clientIP == nli then
 clientIP = ngx.var.remote_addr
 ngx.say("Remote_IP:",clientIP)
 end
 ';
 }
 location / {
 default_type 'text/plain';
 content_by_lua_file /soft/openresty/nginx/lua/dep.lua;
 }
 location @java_prod {
 proxy_pass http://java_prod;
 include proxy_params;
 }
 location @java_test {
 proxy_pass http://java_test;
 include proxy_params;
 }
}
//nginx反向代理tomcat,必须配置头部信息否则返回400错误
[root@nginx-lua conf.d]# cat ../proxy_params
proxy_redirect default;
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_connect_timeout 30;
proxy_send_timeout 60;
proxy_read_timeout 60;
proxy_buffer_size 32k;
proxy_buffering on;
proxy_buffers 4 128k;
proxy_busy_buffers_size 256k;
proxy_max_temp_file_size 256k;

报错处理,将上⾯proxy_params 放在/soft/openresty-1.9.3.2/nginx/conf/
[root@180-143 conf]# /soft/openresty-1.9.3.2/nginx/sbin/nginx -t
nginx: [emerg] open() "/soft/openresty-1.9.3.2/nginx/conf/proxy_params" failed (2: No
such file or directory) in /soft/openresty-1.9.3.2/nginx/conf/nginx.conf:47
nginx: configuration file /soft/openresty-1.9.3.2/nginx/conf/nginx.conf test failed

# lua_package_path
 Nginx 中设置 Lua 模块搜索路径的指令。具体来说, lua_package_path 指定了 Lua 模块在⽂件系统中的路径,
可以让 Nginx 寻找⽤户⾃定义的 Lua 模块并加载使⽤。
在上述代码中, /soft/openresty/nginx/lua/memcached.lua 指的是⼀个 Lua 模块⽂件的完整路径,该模块
可以⽤来实现 Nginx 对 memcached 数据库的访问和操作。
需要注意的是,使⽤ lua_package_path 指令设置搜索路径时,需要遵循 Lua 模块搜索规则,并使⽤ Lua ⽂件路
径格式。通常,建议将所有 Lua 模块⽂件都放到同⼀个⽬录下,使⽤通配符 * 来指示 Lua 模块⽂件名的匹配规
则,例如:
lua_package_path "/usr/local/nginx/lua/?.lua;/usr/local/nginx/lua/?/init.lua";

该指令表示将 /usr/local/nginx/lua/ ⽬录下所有以 .lua 结尾的⽂件或者所有以 /init.lua 结尾的
⼦⽬录都作为 Lua 模块进⾏加载。

4.编写 Nginx 调⽤灰度发布 Lua 脚本
[root@nginx ~]# cat /soft/openresty/nginx/lua/dep.lua
--获取x-real-ip
clientIP = ngx.req.get_headers()["X-Real-IP"]
 --如果IP为空-取x_forwarded_for
if clientIP == nil then
 clientIP = ngx.req.get_headers()["x_forwarded_for"]
end
--如果IP为空-取remote_addr
if clientIP == nil then
 clientIP = ngx.var.remote_addr
end
--定义本地,加载memcached
 local memcached = require "resty.memcached"
--实例化对象
 local memc, err = memcached:new()
--判断连接是否存在错误
 if not memc then
 ngx.say("failed to instantiate memc: ", err)
 return
 end
--建⽴memcache连接
 local ok, err = memc:connect("127.0.0.1", 11211)
--⽆法连接往前端抛出错误信息
 if not ok then
 ngx.say("failed to connect: ", err)
 return
 end
--获取对象中的ip-存在值赋给res
 local res, flags, err = memc:get(clientIP)
--
 --ngx.say("value key: ",res,clientIP)
 if err then
 ngx.say("failed to get clientIP ", err)
 return
 end
--如果值为1则调⽤local-@java_test
 if res == "1" then
 ngx.exec("@java_test")
 return
 end
--否则调⽤local-@java_prod
 ngx.exec("@java_prod")
 return

5.使⽤ Memcache set IP , 测试灰度发布
//telnet传⼊值
[root@nginx conf.d]# telnet 127.0.0.1 11211
# set对应IP
set 192.168.178.100 0 0 1
# 输⼊1
1
get 192.168.178.100
VALUE 192.168.178.100 0 1
1
END

使⽤ telnet 命令连接到了本地运⾏的 Memcached 服务,并进⾏了⼀些操作。
在第⼀条命令 set 192.168.178.100 0 0 1 中,设置 "192.168.178.100" 为键值,后⾯⼀堆数字分别表示过
期时间、存储的数据⻓度、以及存储的数据内容,最后的 "STORED" 表示设置成功。
在第⼆条命令 get 192.168.178.100 中,查询键值为 "192.168.178.100" 的值,最后的 "VALUE
192.168.178.100 0 1 " 表示查询成功,后⾯的 "1" 是数据⻓度,接着就是存储的数据内容。
该命令序列的作⽤是向 Memcached 存储了以 "192.168.178.100" 为键值的数据,并从 Memcached 中查询该
键值对应的数据。

Nginx+Lua实现WAF应⽤防⽕墙

1.常⻅的恶意⾏为
爬⾍⾏为和恶意抓取,资源盗取
防护⼿段
1.基础防盗链功能不让恶意⽤户能够轻易的爬取⽹站对外数据
2.access_moudle->对后台,部分⽤户服务的数据提供IP防护

解决⽅法
[root@180-143 conf.d]# cat luawaf.conf
server {
 listen 80;
 server_name luawaf.wingsredevsecops.top;
 set $ip 0;
 if ($http_x_forward_for = "192.168.178.100"){
 set $ip 1;
 }
 if ($remote_addr = "192.168.178.100"){
 set $ip 1;
 }
 if ($ip = 0){
 return 403;
 }
 location /hello {
 default_type application/json;
 return 200 '{"status":"success"}';
 }
}

2.常⻅的攻击⼿段
后台密码撞库,通过猜测密码字典不断对后台系统登陆性尝试,获取后台登陆密码
防护⼿段
1.后台登陆密码复杂度
2.使⽤access_module-对后台提供IP防控
3.预警机制
⽂件上传漏洞,利⽤上传接⼝将恶意代码植⼊到服务器中,再通过url去访问执⾏代码
执⾏⽅式 luawaf.wingsredevsecops.top/1.jpg/1.php

解决办法
location ^~ /upload {
 root /soft/code/upload;
 if ($request_filename ~* (.*)\.php){
 return 403;
 }
}

3.常⻅的攻击⼿段
利⽤未过滤/未审核的⽤户输⼊进⾏Sql注⼊的攻击⽅法, 让应⽤运⾏本不应该运⾏的SQL代码
防护⼿段
1.php配置开启安全相关限制
2.开发⼈员对sql提交进⾏审核,屏蔽常⻅的注⼊⼿段
3.Nginx+Lua构建WAF应⽤层防⽕墙, 防⽌Sql注⼊

1.快速安装 lnmp 架构
[root@nginx ~]# yum install mariadb mariadb-server php php-fpm php-mysql -y

2.配置 Nginx + php
[root@nginx conf.d]# cat lnmp.conf
server {
 server_name lnmp.wingsredevsecops.top;
 root /soft/code/lnmp/;
 index index.html index.php;
location ~ \.php$ {
 fastcgi_pass 127.0.0.1:9000;
 fastcgi_index index.php;
 include fastcgi_params;
 fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
 }
}

3.配置 MySQL
[root@nginx ~]# systemctl start mariadb
[root@nginx ~]# # mysql -uroot -p'Wing@123'
MariaDB [(none)]> create database info;
MariaDB [(none)]> use info;
MariaDB [info]> create table user(id int(11),username varchar(64), password
varchar(64), email varchar(64));
MariaDB [info]> desc user;
+----------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+----------+-------------+------+-----+---------+-------+
| id | int(11) | YES | | NULL | |
| username | varchar(64) | YES | | NULL | |
| password | varchar(64) | YES | | NULL | |
| email | varchar(64) | YES | | NULL | |
+----------+-------------+------+-----+---------+-------+
//插⼊数据
MariaDB [info]> insert into user (id,username,password,email) values(1,'wing',
('123'),'wing@foxmail.com');
MariaDB [info]> select * from info.user;
+------+----------+----------------------------------+-----------------+
| id | username | password | email |
+------+----------+----------------------------------+-----------------+
| 1 | wing | 123 | wing@foxmail.com |
+------+----------+----------------------------------+-----------------+
1 row in set (0.00 sec)

5.配置php代码
[root@nginx conf.d]# cat /soft/code/lnmp/login.html
<html>
<head>
 <title> Sql注⼊演示场景 </title>
 <meta http-equiv="content-type"content="text/html;charset=utf-8">
</head>
<body>
<form action="sql.php" method="post">
<table>
 <tr>
 <td> ⽤ 户: </td>
 <td><input type="text" name="username"></td>
 </tr>
 <tr>
 <td> 密 码: </td>
 <td><input type="text" name="password"></td>
 </tr>
 <tr>
 <td><input type="submit" value="提交"></td>
 <td><input type="reset" value="重置"></td>
 </tr>
 </table>
 </form>
</body>
</html>

被html调⽤的sql.php⽂件
[root@nginx conf.d]# cat /soft/code/lnmp/sql.php
<?php
$conn = mysqli_connect("localhost", 'root', 'Wing@123', "info") or die("数据库连接失
败!");
$name = $_POST['username'];
$pwd = $_POST['password'];
// # sql注⼊核⼼问题
$sql = "select * from user where username='$name' and password='$pwd'";
echo $sql . "<br />";
$query = mysqli_query($conn, $sql);
$arr = mysqli_fetch_array($query);
if ($arr) {
 echo "login success!<br />";
 echo $arr[1];
 echo $arr[3] . "<br /><br />";
} else {
 echo "login failed!";
}
mysqli_close($conn);
?>

部署 Waf 相关防护代码
[root@nginx ~]# cd /soft/src/
[root@nginx src]# git clone https://github.com/loveshell/ngx_lua_waf.git
#克隆不下了直接从github上⼿动下载上传解压
[root@nginx src]# rz ngx_lua_waf-master.zip
[root@nginx src]# unzip ngx_lua_waf-master.zip
Archive: ngx_lua_waf-master.zip
314a2f62ec350eba9b5d25b55b5b0a723e20a8d0
 creating: ngx_lua_waf-master/
 inflating: ngx_lua_waf-master/.gitattributes 
 inflating: ngx_lua_waf-master/.gitignore 
 inflating: ngx_lua_waf-master/README.md 
 inflating: ngx_lua_waf-master/config.lua 
 inflating: ngx_lua_waf-master/init.lua 
 inflating: ngx_lua_waf-master/install.sh 
 inflating: ngx_lua_waf-master/waf.lua 
 creating: ngx_lua_waf-master/wafconf/
 inflating: ngx_lua_waf-master/wafconf/args 
 inflating: ngx_lua_waf-master/wafconf/cookie 
 inflating: ngx_lua_waf-master/wafconf/post
inflating: ngx_lua_waf-master/wafconf/url 
 inflating: ngx_lua_waf-master/wafconf/user-agent 
 extracting: ngx_lua_waf-master/wafconf/whiteurl

 # mkdir -p /soft/openresty/nginx/logs/waf/
//把ngx_lua_waf复制到nginx的⽬录下,解压命名为waf
[root@nginx ~]# cp -r ngx_lua_waf-master /soft/openresty/nginx/lua/waf

//在nginx.conf的http段添加(注意路径)
lua_package_path "/soft/openresty/nginx/lua/waf/?.lua";
lua_shared_dict limit 10m;
init_by_lua_file /soft/openresty/nginx/lua/waf/init.lua;
access_by_lua_file /soft/openresty/nginx/lua/waf/waf.lua;

//配置config.lua⾥的waf规则⽬录(⼀般在waf/wafconf/⽬录下)
RulePath = "/soft/openresty/nginx/lua/waf/wafconf/"
logdir = "/soft/openresty/nginx/logs/waf/"
#绝对路径如有变动,需对应修改, 然后重启nginx即可

5. Nginx + lua 防⽌ Sql 注⼊
[root@nginx ~]# vim /soft/openresty/nginx/lua/waf/wafconf/post
\sor\s+
这个正则表达式有两部分:
1. \s: 表示匹配任意空⽩字符,包括空格、制表符、换⾏符等。
2. or: 表示匹配这三个字⺟的顺序,即 or。
3. \s+: 表示匹配⼀个或多个任意空⽩字符,即与\s类似,但⽐\s更加宽松,可以匹配多个连续的空⽩字符。
整个正则表达式的含义是匹配字符串中的⼀个空⽩字符或多个空⽩字符,后跟or,再后跟⼀个或多个空⽩字
符。这个正则表达式通常⽤于匹配字符串中的特定分隔符。

6.防⽌ CC 攻击
[root@nginx ~]# vim /soft/openresty/nginx/lua/waf/config.lua
CCrate="100/60"

这个 waf 配置⽂件中, CCrate 参数代表着 IP 的访问频率限制。其中 100 表示限制的请求数量, 60 表示时间窗
⼝(单位为秒),即在 60 秒内,相同的 IP 地址只能发送 100 次请求。
posted @ 2025-03-15 16:43  basickill  阅读(295)  评论(0)    收藏  举报