服务部署
经过本地测试,通过Nginx直接编译安装Lua,在脚本实际执行过程中,很多方法不支持,无法达到预期结果。本文通过编译安装Tengine来实现。
Tengine是由淘宝发起的Web服务器项目。它在Nginx的基础上,针对大访问量网站的需求,添加了很多高级功能和特性,使用上与Nginx并无区别,而且对Lua的兼容性比较好。
本文所使用版本如下:
luajit2-2.1-20230911.tar.gz
tengine-3.0.0.tar.gz
lua-resty-core-0.1.28.tar.gz
lua-resty-lrucache-0.13.tar.gz
ngx_devel_kit-0.3.2.tar.gz
lua-cjson-2.1.0.13.tar.gz
lua-nginx-module-0.10.26.tar.gz
ngx_security_headers-0.0.11.tar.gz
1、解压各资源
tar -zxvf luajit2-2.1-20230911.tar.gz
tar -zxvf tengine-3.0.0.tar.gz
tar -zxvf ngx_devel_kit-0.3.2.tar.gz
tar -zxvf lua-resty-core-0.1.28.tar.gz
tar -zxvf lua-resty-lrucache-0.13.tar.gz
tar -zxvf lua-cjson-2.1.0.13.tar.gz
tar -zxvf lua-nginx-module-0.10.26.tar.gz
tar -zxvf ngx_security_headers-0.0.11.tar.gz
2、安装luajit
cd luajit2-2.1-20230911
make && make install
#导入环境变量
export LUAJIT_LIB=/usr/local/lib
export LUAJIT_INC=/usr/local/include/luajit-2.1
3、安装lua-resty-core、lua-resty-lrucache
cd lua-resty-core-0.1.28
make install LUA_LIB_DIR=/usr/local/share/lua/5.1
cd lua-resty-lrucache-0.13
make install LUA_LIB_DIR=/usr/local/share/lua/5.1
4、安装Tengine
cd tengine-3.0.0
./configure --prefix=/usr/local/tengine --add-module=../ngx_security_headers-0.0.11 --add-module=../ngx_devel_kit-0.3.2 --add-module=../lua-nginx-module-0.10.26
make && make install
5、访问测试
- 进入
/usr/local/tengine/conf
目录下找到配置文件,更改nginx.conf
配置文件。 - 进入
/usr/local/tengine/sbin
目录,执行./nginx
命令,启动服务。 - 浏览器访问端口,查看是否启动成功。如果开启防火墙,记得打开端口。
6、安装cjson库
cd lua-cjson-2.1.0.13
vi Makefile
#修改路径为luajit安装路径
LUA_INCLUDE_DIR ?= $(PREFIX)/include/luajit-2.1
make && make install
7、编写脚本
#user nobody;
worker_processes 1;
#error_log logs/error.log;
#error_log logs/error.log notice;
#error_log logs/error.log info;
#pid logs/nginx.pid;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
#access_log logs/access.log main;
sendfile on;
#tcp_nopush on;
keepalive_timeout 65;
#gzip on;
server_tokens off;
security_headers on;
hide_server_tokens on;
server {
listen 8080;
server_name localhost;
#charset koi8-r;
#access_log logs/host.access.log main;
#add_header Set-Cookie "Path=/; HttpOnly; Secure;SameSite=Strict";
add_header X-Download-Options "value";
add_header X-Permitted-Cross-Domain-Policies "value";
add_header Pragma no-store;
add_header Cache-Control "no-store";
add_header Referrer-Policy strict-origin-when-cross-origin;
add_header Strict-Transport-Security "max-age=63072000" always;
add_header X-Content-Type-Options nosniff;
location ~ ^/.+/$ {
return 403;
}
if ($request_uri ~* "\.\.") {
return 403;
}
location / {
lua_need_request_body on;
default_type 'text/html';
access_by_lua_block {
local cjson = require "cjson";
-- 校验referer
local referer = ngx.var.http_referer;
if refer then
local _, _, host = string.find(referer, "^(https?://[^/]+)");
local oldReferer = 'http://127.0.0.1:8080';
if oldRefererHttps ~= host then
ngx.status = 401;
ngx.exit(ngx.HTTP_UNAUTHORIZED);
end
end
local request_method = ngx.req.get_method();
-- 禁用delete请求
if request_method == "DELETE" then
ngx.status = 401;
ngx.exit(ngx.HTTP_UNAUTHORIZED);
end
-- 校验get请求
if request_method == "GET" then
-- 获取get请求中参数名
local args = ngx.req.get_uri_args();
-- 检验参数中是否包含_
if args["_"] then
ngx.status = 401;
ngx.exit(ngx.HTTP_UNAUTHORIZED);
end
-- 遍历参数值中是否包含sql关键字
for index,value in pairs(args) do
if type(value) == "string" and (value:find("and") or value:find("or")) then
ngx.status = 401;
ngx.exit(ngx.HTTP_UNAUTHORIZED);
end
end
end
-- 校验post请求
if request_method == "POST" then
-- 定义不允许的参数名列表
local forbidden_params = {"isadmin","is_admin","_isadmin","isadmin_","issso","is_sso"};
-- 读取 POST 请求体
ngx.req.read_body();
local data = ngx.req.get_body_data();
local jsonData = cjson.decode(data);
for index,value in pairs(jsonData) do
-- 检验参数名
for i,v in ipairs(forbidden_params) do
if v == index then
ngx.status = 401;
ngx.exit(ngx.HTTP_UNAUTHORIZED);
end
end
--检验参数值
if type(value) == "string" and (value:find("and") or value:find("or")) then
ngx.status = 401;
ngx.exit(ngx.HTTP_UNAUTHORIZED);
end
end
end
}
proxy_cookie_path / "/; Secure;HttpOnly;SameSite=Strict";
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $http_host;
proxy_set_header X-Forwarded-Proto https;
proxy_set_header REMOTE-HOST $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_pass http://127.0.0.1:8081;
}
#error_page 404 /404.html;
# redirect server error pages to the static page /50x.html
#error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
}
8、脚本测试
- 重启Nginx,进入
/usr/local/tengine/sbin
目录,执行./nginx -s reload
命令。 - 发起请求添加参数测试,只有脚本校验通过后请求才会到实际后端。