赞
踩
某次安全扫描通过Dirsearch工具发现,nginx代理访问某后端业务时,发现:Springboot未授权漏洞,存在信息泄露风险,危险等级:中危;
相关资源:openresty官网、/lua-nginx-module模块地址、Nginx lua模块说明、lua-nignx与Nginx兼容性、lua-ngx配置说明、/lua-nginx模块安装
1)经分析,只需要再nginx代理侧增加鉴权控制接口,无需修改代码;这里我们通过该Nginx+Lua模块来实现基于lua规则的自定义访问控制和鉴权逻辑。
2)安装 lua-nginx-module模块
ngx_lua_module 是一个nginx http模块,它把 lua 解析器内嵌到 nginx,是异步非阻塞的方式,运行时占用内存特别少,它可解析并执行lua 语言编写的网页后台脚本;它依赖LuaJIT,因此我们需要首先安装LuaJIT,对于LuaJIT,强烈推荐使用:OpenResty发行版,LuaJIT 2.0 or 2.1,它自集成了 integrate Nginx, ngx_lua,有更好的兼容性,否则后期会报兼容性错误(见下文);
OpenResty® 是一个结合了 Nginx 与 Lua 的高性能 Web 平台,其内部集成了大量精良的 Lua 库、第三方模块以及大多数的依赖项。用于方便地搭建能够处理超高并发、扩展性极高的动态 Web 应用、Web 服务和动态网关。
OpenResty® 通过汇聚各种设计精良的 Nginx 模块(主要由 OpenResty 团队自主开发),从而将 Nginx 有效地变成一个强大的通用 Web 应用平台。这样,Web 开发人员和系统工程师可以使用 Lua 脚本语言调动 Nginx 支持的各种 C 以及 Lua 模块,快速构造出足以胜任 10K 乃至 1000K 以上单机并发连接的高性能 Web 应用系统。
OpenResty® 的目标是让你的Web服务直接跑在 Nginx 服务内部,充分利用 Nginx 的非阻塞 I/O 模型,不仅仅对 HTTP 客户端请求,甚至于对远程后端诸如 MySQL、PostgreSQL、Memcached 以及 Redis 等都进行一致的高性能响应。OpenResty包括了它自己的LuaJIT版本,该版本专门针对OpenResty环境进行了优化和增强。安装完成后,可以使用Lua编写Nginx配置文件中的各种指令和处理逻辑。兼容性如下:
#环境准备:依赖
#pcre-devel: 扩展的正则表达式引擎,为了使Nginx处理更复杂的正则表达式机制
#openssl-devel:–with-http_ssl_module使用该模块必需装openssl库,来实现http支持https协议
#zlib-devel:zlib库是网络通信压缩库,ngx_http_gzip_module(gzip压缩模块)所必需的
#readline-devel:readline是安装Openresty所必须的依赖包
yum install gcc-c++ libtool gmake make -y
yum install pcre pcre-devel openssl openssl-devel zlib zlib-devel readline readline-devel-y
#
wget https://openresty.org/download/openresty-1.25.3.1.tar.gz
tar xzf openresty-1.25.3.1.tar.gz
cd openresty-1.25.3.1
#安全相关,注释如下
cd ./bundle/nginx-1.21.4
# - 1.隐藏版本
vim src/core/nginx.h
#define NGINX_VERSION "6666"
#define NGINX_VER "FW/" NGINX_VERSION ".6"
#define NGINX_VAR "FW"
# - 2.修改头部
vim src/http/ngx_http_header_filter_module.c
# 49 static u_char ngx_http_server_string[] = "Server: FW" CRLF;
# - 3.修改错误页响应头部(response header)
vim src/http/ngx_http_special_response.c
# 22 "<hr><center>FW</center>" CRLF
# ...
# 29 "<hr><center>FW</center>" CRLF
# ...
# 36 "<hr><center>FW</center>" CRLF
#如果不需要可跳过,编译检查
./configure -j4
make all test
#编译
gmake -j4
sudo gmake install
#下载 ngx_devel_kit (NDK) module
wget --no-check-certificate https://github.com/vision5/ngx_devel_kit/archive/refs/tags/v0.3.3.tar.gz
#下载lua-nginx-module
wget --no-check-certificate https://github.com/openresty/lua-nginx-module/archive/refs/tags/v0.10.26.tar.gz
#下载lua-resty-core,nginx_lua 0.10.16版后需要
wget --no-check-certificate https://github.com/openresty/lua-resty-core/archive/refs/tags/v0.1.22.tar.gz
#下载lua-resty-lrucache,nginx_lua 0.10.16版后需要
wget --no-check-certificate https://github.com/openresty/lua-resty-lrucache/archive/refs/tags/v0.11.tar.gz
#安装Lua核心库:lua-resty-core和lua-resty-lrucache,现场未执行这一步
make install PREFIX= /etc/profile/lua_core
ln -s /u_path/lua_core/lib/lua/resty /u_path/LuaJIT/share/luajit-2.1.0/resty
#现场默认
ln -s /usr/local/openresty/lualib/resty /usr/local/openresty/luajit/share/luajit-2.1/
ll /usr/local/openresty/luajit/share/luajit-2.1/
total 4
drwxr-x--- 2 root root 4096 May 14 14:26 jit
lrwxrwxrwx 1 root root 33 May 14 14:36 resty -> /usr/local/openresty/lualib/resty
#接口授权认证相关依赖安装(可选)
#下载lua-cjson库
wget https://www.kyne.com.au/~mark/software/download/lua-cjson-2.1.0.tar.gz
tar xf lua-cjson-2.1.0.tar.gz
cd /lua-cjson-2.1.0
#修改/root/lua-cjson-2.1.0/Makefile文件
PREFIX = /usr/local/LuaJIT
LUA_INCLUDE_DIR = $(PREFIX)/include/luajit-2.0 (安装luajit的路径)
LUA_CMODULE_DIR = $(PREFIX)/lib/lua/$(LUA_VERSION)
LUA_MODULE_DIR = $(PREFIX)/share/lua/$(LUA_VERSION)
LUA_BIN_DIR = $(PREFIX)/bin
#安装
make && make install
#Nginx添加以上模块
./configure --prefix=/usr/local/nginx \
--with-ld-opt="-Wl,-rpath,/usr/local/LuaJIT/luajit-or-lua/lib" \
--with-http_addition_module
--add-module=/path/to/ngx_devel_kit \
--add-module=/path/to/lua-nginx-module
make -j2
cd objs #替换Nginx即可
如果不用OpenResty的版本会报如下错误:
nginx: [alert] detected a LuaJIT version which is not OpenResty's; many optimizations will be disabled and performance will be compromised (see https://github.com/openresty/luajit2 for OpenResty's LuaJIT or, even better, consider using the OpenResty releases from https://openresty.org/en/download.html)
nginx: [alert] failed to load the 'resty.core' module (https://github.com/openresty/lua-resty-core); ensure you are using an OpenResty release from https://openresty.org/en/download.html (reason: module 'resty.core' not found:
no field package.preload['resty.core']
no file './resty/core.lua'
no file '/usr/local/share/luajit-2.0.5/resty/core.lua'
no file '/usr/local/share/lua/5.1/resty/core.lua'
no file '/usr/local/share/lua/5.1/resty/core/init.lua'
no file './resty/core.so'
no file '/usr/local/lib/lua/5.1/resty/core.so'
no file '/usr/local/lib/lua/5.1/loadall.so'
no file './resty.so'
no file '/usr/local/lib/lua/5.1/resty.so'
no file '/usr/local/lib/lua/5.1/loadall.so') in /usr/local/nginx/conf/nginx.conf:218
卸载从github上安装的luajit:
make uninstall
==== Uninstalling LuaJIT 2.1. from /usr/local ====
rm -f /usr/local/bin/luajit-2.1. /usr/local/lib/libluajit-5.1.a /usr/local/lib/libluajit-5.1.so.2.1. /usr/local/lib/libluajit-5.1.so /usr/local/lib/libluajit-5.1.so.2 /usr/local/share/man/man1/luajit.1 /usr/local/lib/pkgconfig/luajit.pc
for file in bc.lua bcsave.lua dump.lua p.lua v.lua zone.lua dis_x86.lua dis_x64.lua dis_arm.lua dis_arm64.lua dis_arm64be.lua dis_ppc.lua dis_mips.lua dis_mipsel.lua dis_mips64.lua dis_mips64el.lua dis_mips64r6.lua dis_mips64r6el.lua vmdef.lua; do \
rm -f /usr/local/share/luajit-2.1/jit/$file; \
done
for file in lua.h lualib.h lauxlib.h luaconf.h lua.hpp luajit.h; do \
rm -f /usr/local/include/luajit-2.1/$file; \
done
ldconfig -n 2>/dev/null /usr/local/lib
rmdir 2>/dev/null /usr/local/share/luajit-2.1/jit /usr/local/share/luajit-2.1 /usr/local/include/luajit-2.1 /usr/local/share/lua/5.1 /usr/local/share/lua /usr/local/lib/lua/5.1 /usr/local/lib/lua || :
==== Successfully uninstalled LuaJIT 2.1. from /usr/local ====
#重新安装
wget https://github.com/openresty/luajit2/archive/refs/tags/v2.0.4.zip
unzip luajit2-2.0.4.zip
/data1/mysoftware/luajit2-2.0.4
#安装
make install PREFIX=/usr/local/LuaJIT
……
LINK luajit
OK Successfully built LuaJIT
make[1]: Leaving directory '/data1/mysoftware/luajit2-2.0.4/src'
==== Successfully built LuaJIT 2.0.4 ====
==== Installing LuaJIT 2.0.4 to /usr/local/LuaJIT ====
mkdir -p /usr/local/LuaJIT/bin /usr/local/LuaJIT/lib /usr/local/LuaJIT/include/luajit-2.0 /usr/local/LuaJIT/share/man/man1 /usr/local/LuaJIT/lib/pkgconfig /usr/local/LuaJIT/share/luajit-2.0.4/jit /usr/local/LuaJIT/share/lua/5.1 /usr/local/LuaJIT/lib/lua/5.1
cd src && install -m 0755 luajit /usr/local/LuaJIT/bin/luajit-2.0.4
cd src && test -f libluajit.a && install -m 0644 libluajit.a /usr/local/LuaJIT/lib/libluajit-5.1.a || :
rm -f /usr/local/LuaJIT/bin/luajit /usr/local/LuaJIT/lib/libluajit-5.1.so.2.0.4 /usr/local/LuaJIT/lib/libluajit-5.1.so /usr/local/LuaJIT/lib/libluajit-5.1.so
cd src && test -f libluajit.so && \
install -m 0755 libluajit.so /usr/local/LuaJIT/lib/libluajit-5.1.so.2.0.4 && \
ldconfig -n /usr/local/LuaJIT/lib && \
ln -sf libluajit-5.1.so.2.0.4 /usr/local/LuaJIT/lib/libluajit-5.1.so && \
ln -sf libluajit-5.1.so.2.0.4 /usr/local/LuaJIT/lib/libluajit-5.1.so || :
cd etc && install -m 0644 luajit.1 /usr/local/LuaJIT/share/man/man1
cd etc && sed -e "s|^prefix=.*|prefix=/usr/local/LuaJIT|" -e "s|^multilib=.*|multilib=lib|" luajit.pc > luajit.pc.tmp && \
install -m 0644 luajit.pc.tmp /usr/local/LuaJIT/lib/pkgconfig/luajit.pc && \
rm -f luajit.pc.tmp
cd src && install -m 0644 lua.h lualib.h lauxlib.h luaconf.h lua.hpp luajit.h /usr/local/LuaJIT/include/luajit-2.0
cd src/jit && install -m 0644 bc.lua v.lua dump.lua dis_x86.lua dis_x64.lua dis_arm.lua dis_ppc.lua dis_mips.lua dis_mipsel.lua bcsave.lua vmdef.lua /usr/local/LuaJIT/share/luajit-2.0.4/jit
ln -sf luajit-2.0.4 /usr/local/LuaJIT/bin/luajit
==== Successfully installed LuaJIT 2.0.4 to /usr/local/LuaJIT ====
#编译安装
gmake[2]: Leaving directory '/data1/mysoftware/openresty-1.25.3.1/build/nginx-1.25.3'
gmake[1]: Leaving directory '/data1/mysoftware/openresty-1.25.3.1/build/nginx-1.25.3'
mkdir -p /usr/local/openresty/site/lualib /usr/local/openresty/site/pod /usr/local/openresty/site/manifest
ln -sf /usr/local/openresty/nginx/sbin/nginx /usr/local/openresty/bin/openresty
#配置环境变量
vi /etc/profile
export LUAJIT_LIB=/usr/local/openresty/luajit/lib
export LUAJIT_INC=/usr/local/openresty/luajit/include/luajit-2.1
export LUA_LIB_DIR=/usr/local/openresty/lualib
export LD_LIBRARY_PATH=$LUAJIT_LIBB:$LD_LIBRARY_PATH
vi /etc/ld.so.conf.d/libc.conf
/usr/local/openresty/luajit/lib
/usr/local/openresty/luajit/include/luajit-2.1
#验证
lua -v #输出
Lua 5.4.3 Copyright (C) 1994-2021 Lua.org, PUC-Rio
ln -s /usr/local/openresty/lualib/resty/core/
重新编译Nginx后启动依然报错:
nginx: [alert] failed to load the 'resty.core' module (https://github.com/openresty/lua-resty-core); ensure you are using an OpenResty release from https://openresty.org/en/download.html (reason: module 'resty.core' not found:
no field package.preload['resty.core']
no file './resty/core.lua'
no file '/usr/local/openresty/luajit/share/luajit-2.1/resty/core.lua'
no file '/usr/local/share/lua/5.1/resty/core.lua'
no file '/usr/local/share/lua/5.1/resty/core/init.lua'
no file '/usr/local/openresty/luajit/share/lua/5.1/resty/core.lua'
no file '/usr/local/openresty/luajit/share/lua/5.1/resty/core/init.lua'
no file './resty/core.so'
no file '/usr/local/lib/lua/5.1/resty/core.so'
no file '/usr/local/openresty/luajit/lib/lua/5.1/resty/core.so'
no file '/usr/local/lib/lua/5.1/loadall.so'
no file './resty.so'
no file '/usr/local/lib/lua/5.1/resty.so'
no file '/usr/local/openresty/luajit/lib/lua/5.1/resty.so'
no file '/usr/local/lib/lua/5.1/loadall.so') in /usr/local/nginx/conf/nginx.conf:217
#查找文件core.lua
find / -name core.lua
ln -s /usr/local/openresty/lualib/resty /usr/local/nginx/sbin/ #然后再启动就好了
#验证
ldconfig -v|grep libluajit-
……
ldconfig: Cannot stat /usr/lib64/libebtc.so: No such file or directory
libluajit-5.1.so.2 -> libluajit-5.1.so.2.1.ROLLING
nginx -V
nginx version: nginx/1.20.2
built by gcc 10.3.1 (GCC)
built with OpenSSL 1.1.1m 14 Dec 2021
TLS SNI support enabled
configure arguments: --user=nginx --group=nginx --with-http_ssl_module --with-http_gzip_static_module --with-http_realip_module --with-http_stub_status_module --with-http_flv_module --with-http_mp4_module --with-http_sub_module --with-http_v2_module --with-http_slice_module --with-pcre-jit --with-pcre --with-http_dav_module --with-http_addition_module --with-stream --with-stream_ssl_module --with-stream_realip_module --add-module=/data1/mysoftware/lua-nginx-module-0.10.26 --add-module=/data1/mysoftware/ngx_devel_kit-0.3.3
#验证示例
#Nginx.conf新增如下,然后测试http://ip//hello_lua会出现”hello, lua”表示安装成功
location /hello_lua {
default_type 'text/plain';
content_by_lua 'ngx.say("hello, lua")'; ##通过调用lua来打印HelloWorld
}
3)配置Nginx lua:
location /api/ {
# 禁止 Access-Control-Allow-Origin 为 "*" 和 "null",严格校验 Origin 值
if ($request_method = 'OPTIONS') {
return 204;
}
if ( $http_origin ~* "^https://www.") {
return 403 ;
}
proxy_set_header X-Real-IP $remote_addr;
if ($request_method = GET) {
access_by_lua_block{
local args = ngx.req.get_uri_args()
local value_not_found = true
for key, val in pairs(args) do
if val == "x54972dsdjrfdjskd" then
value_not_found = false
break
end
end
if value_not_found then
ngx.status = 403
ngx.say("Access denied. Token not found in request args.")
ngx.exit(ngx.HTTP_FORBIDDEN)
end
}
proxy_pass http://blue.com;
}
if ($request_method = POST) {
access_by_lua_block{
ngx.req.read_body()
local token = "x54972dsdjrfdjskd"
local req_body = ngx.req.get_body_data()
if not req_body or string.find(req_body, token) == nil then
ngx.status = 403
ngx.say("Access denied. Token not found in request body.")
ngx.exit(ngx.HTTP_FORBIDDEN)
end
}
}
proxy_pass http://blue.com;
}
1)Nginx打补丁
yum install git -y
cd /appdata/nginx
git clone https://github.com/yzprofile/ngx_http_dyups_module.git
git clone https://github.com/yaoweibin/nginx_upstream_check_module.git
git clone https://github.com/vozlt/nginx-module-vts.git
yum install patch -y
yum install gd gd-devel -y
# nginx_upstream_check_module 补丁
cd /appdata/nginx/openresty-1.21.4.1/bundle/nginx-1.21.4
patch -p1 < /appdata/nginx/nginx_upstream_check_module/check_1.20.1+.patch
#重新编译
./configure --prefix=/appdata/nginx/nginx-1.21.4 \
--with-luajit \
--with-pcre \
--with-pcre-jit \
--with-http_realip_module \
--with-http_v2_module \
--with-http_image_filter_module \
--with-http_iconv_module \
--with-stream_realip_module \
--with-stream \
--with-stream_ssl_module \
--with-http_slice_module \
--with-http_sub_module \
--with-http_stub_status_module \
--with-http_gzip_static_module \
--add-module=../nginx-module-vts \
--add-module=../ngx_log_if-master \
--add-module=../ngx_http_dyups_module \
--add-module=../nginx_upstream_check_module \
--without-http_autoindex_module
2)WAF实现
还可使用nginx+lua来实现WAF,即在编译nginx的时候配置上lua。实现:
支持IP白名单和黑名单功能,直接将黑名单的IP访问拒绝。
支持URL白名单,将不需要过滤的URL进行定义。
支持User-Agent的过滤,匹配自定义规则中的条目,然后进行处理(返回403)。
支持CC攻击防护,单个URL指定时间的访问次数,超过设定值,直接返回403。
支持Cookie过滤,匹配自定义规则中的条目,然后进行处理(返回403)。
支持URL过滤,匹配自定义规则中的条目,如果用户请求的URL包含这些,返回403。
支持URL参数过滤,原理同上。
支持日志记录,将所有拒绝的操作,记录到日志中去。
日志记录为JSON格式,便于日志分析,例如使用ELKStack进行攻击日志收集、存储、搜索和展示。
在这里插入代码片
3)content_by_lua_block语法
语法格式:content_by_lua_block { lua-script };
放在location或 location if中,第一次在v0.9.17版中开始推广;
说明:该函数充当“内容处理程序”,并为每个请求执行{Lua-script}中指定的Lua代码字符串。Lua代码可以进行API调用,并在独立的全局环境(即沙箱)中作为新的派生协程执行。不要在同一位置使用此指令和其他内容处理程序指令。例如,此指令和proxy_pass指令不应在同一位置使用。
类似的还有:content_by_lua_file,等效于content_by_lua_block;
语法: content_by_lua_file <path-to-lua-script-file>
,同上也放在location或 location if中。如果lua脚本文件不存在,则会报404 错误和503 Service Temporarily Unavailable; Lua code cach默认是开启的,会随nginx的启动一次性载入和cache,如果是lua脚本文件,则需要每次脚本文件修改后续重新载入内存;
4)access_by_lua_block
语法:access_by_lua_block { lua-script };
可用在http, server, location, location if区块中;
作用:充当访问阶段处理程序,并为每个请求执行{<Lua-script}中指定的Lua代码字符串,它在ngx_http_access_module模块处理后继续处理。
location / {
deny 192.168.1.1;
allow 192.168.1.0/24;
allow 10.1.1.0/16;
deny all;
access_by_lua_block {
local res = ngx.location.capture("/mysql", { ... })
#
...
}
# proxy_pass/fastcgi_pass/...
}
另外,ngx_auth_request模块可以使用access_by_lua_block来近似实现:
location / {
auth_request /auth;
# proxy_pass/fastcgi_pass/postgres_pass/...
}
#等效于
location / {
access_by_lua_block {
local res = ngx.location.capture("/auth")
if res.status == ngx.HTTP_OK then
return
end
if res.status == ngx.HTTP_FORBIDDEN then
ngx.exit(res.status)
end
ngx.exit(ngx.HTTP_INTERNAL_SERVER_ERROR)
}
# proxy_pass/fastcgi_pass/postgres_pass/...
}
注:上述代码中,请注意,当在access_by_lua_block处理程序中调用ngx.exit(ngx.OK)时,Nginx请求处理控制流仍将继续到内容处理程序。要从access_by_lua_block处理程序中终止当前请求,请调用ngx.exit(状态>=200(ngx.HTTP_OK)和状态<300(ngx.HTTP_SPECIAL_RESPONSE)以成功退出,调用ngx.exit(ngx.HTTP_INTERNAL_SERVER_ERROR)(或其朋友)以失败。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。