当前位置: 首页 > article >正文

Web安全 - 使用 Nginx + Lua 防御 NoSQL 注入攻击

文章目录

  • Pre
  • Nginx 下载
  • `content_by_lua_file`
  • 实战
    • 漏洞分析
    • 借助 Nginx + Lua 修复
      • 1. 环境准备
      • 2. Nginx 配置
      • 3. Lua 脚本实现
        • `business_handler.lua`
        • `mongo_inject_check.lua`
    • 测试与验证
  • 小结

在这里插入图片描述


Pre

在这里插入图片描述

指令所处处理阶段使用范围解释
init_by_lua / init_by_lua_fileloading-confighttpNginx Master进程加载配置时执行;通常用于初始化全局配置/预加载Lua模块
init_worker_by_lua / init_worker_by_lua_filestarting-workerhttp每个Nginx Worker进程启动时调用的计时器,如果Master进程不允许则只会在init_by_lua之后调用;通常用于定时拉取配置/数据,或者后端服务的健康检查
set_by_lua / set_by_lua_filerewriteserver, server if, location, location if设置Nginx变量,可以实现复杂的赋值逻辑;此处是阻塞的,Lua代码要做到非常快。
rewrite_by_lua / rewrite_by_lua_filerewritehttp, server, location, location ifrewrite阶段处理,可以实现复杂的转发/重定向逻辑。
access_by_lua / access_by_lua_fileaccesshttp, server, location, location if请求访问阶段处理,用于访问控制。
content_by_lua / content_by_lua_filecontentlocation, location if内容处理器,接收请求处理并输出响应。
header_filter_by_lua / header_filter_by_lua_fileoutput-header-filterhttp, server, location, location if设置header和cookie。
body_filter_by_lua / body_filter_by_lua_fileoutput-body-filterhttp, server, location, location if对响应数据进行过滤,比如截断、替换。
log_by_lua / log_by_lua_fileloghttp, server, location, location iflog阶段处理,比如记录访问量/统计平均响应时间。

Nginx - 整合lua 实现对POST请求的参数拦截校验(不使用Openresty) 中我们不仅要修改lua脚本,nginx.cnf也需要跟着调整,比较繁琐,这里我们借助 content_by_lua_file 来优化一下,达到仅修改lua脚本就可以完成业务校验的目的


Nginx 下载

Nginx 1.27.1 + x86 + lua + gmssl

配置lua_package_path
nginx/x86/lua_package_path 目录下
	cd lua-resty-core-master/ && make install PREFIX=/opt/nginx
	cd lua-resty-lrucache-master/ && make install PREFIX=/opt/nginx

配置nginx.conf
nginx.conf
	http {
		lua_package_path "/opt/nginx/lib/lua/?.lua;;";
		lua_package_cpath "/root/nginx/sbin/lib/lua/5.1/?.so;/root/nginx/sbin/lib/?.so;;";
	}

启动nginx	
export LD_LIBRARY_PATH=./lib/
./nginx -p ../ -c conf/nginx.conf

content_by_lua_file

content_by_lua_file 是 Nginx 的 ngx_http_lua_module 模块提供的一条指令,它允许 Nginx 在处理请求时,执行一个外部的 Lua 脚本文件。此指令通常用于在请求处理的 content phase(内容阶段)中,执行自定义的 Lua 代码,从而动态生成响应内容。

当请求到达 Nginx 配置中定义的 location 或其他处理块时,Nginx 会加载并执行指定路径的 Lua 文件,这样你可以用 Lua 脚本来完成诸如内容生成、响应修改、请求处理等操作。

使用场景

  • 动态内容生成:在不依赖外部应用程序的情况下,生成动态响应内容(如 JSON、HTML、XML 等)。
  • 数据校验与处理:通过 Lua 脚本对请求进行复杂的数据处理、验证和修改。
  • 高级请求路由与控制:可以基于请求的参数或其他条件来控制请求的处理逻辑,甚至实现负载均衡或重定向。
  • 缓存与优化:在 Lua 脚本中操作 Nginx 的缓存、共享内存等机制,做一些高级的缓存策略或优化工作。

基本语法

location /some/path {
    content_by_lua_file /path/to/your/lua/script.lua;
}

content_by_lua_file 指令指定了一个外部 Lua 文件的路径,当请求匹配这个 location 时,Nginx 会执行该 Lua 文件中的代码,并生成响应内容。

详细说明

  • Nginx Content Phasecontent_by_lua_file 指令属于 content phase,这意味着它会在请求处理的最后阶段执行,也就是当请求已经匹配到某个 location 时,Nginx 会处理响应内容。
  • 外部 Lua 文件:指定的是 Lua 脚本文件的路径,通常需要提供绝对路径或者相对路径,确保 Nginx 能找到这个文件。
  • Lua 解释器ngx_http_lua_module 会自动启动 Lua 解释器来执行该脚本,执行过程通常是非阻塞的,因此适合高并发环境。

工作原理

  1. 请求到达 Nginx 时,Nginx 根据配置的 location 查找匹配的路径。
  2. 如果请求的 location 配置了 content_by_lua_file,则 Nginx 会在 content phase 加载并执行指定的 Lua 文件。
  3. Lua 文件中的代码执行后会返回生成的响应内容,Nginx 会把该内容作为 HTTP 响应返回给客户端。

示例

假设有一个 Lua 文件 validate_post.lua,需要对 POST 请求进行校验并生成相应的响应。

  1. 配置 Nginx
server {
    listen 80;

    location /submit {
        content_by_lua_file /path/to/your/lua/validate_post.lua;
    }
}
  1. Lua 文件 validate_post.lua
-- validate_post.lua

-- 读取请求体
ngx.req.read_body()
local args = ngx.req.get_post_args()

-- 校验必填参数
if not args.name or not args.email then
    ngx.status = ngx.HTTP_BAD_REQUEST
    ngx.say("Missing required parameters: name or email")
    return
end

-- 校验邮箱格式
if not string.match(args.email, "^[a-zA-Z0-9_+&*-]+%.[a-zA-Z0-9_+&*-]+@([a-zA-Z0-9-]+%.)+[a-zA-Z]{2,7}$") then
    ngx.status = ngx.HTTP_BAD_REQUEST
    ngx.say("Invalid email format")
    return
end

-- 校验通过
ngx.say("Request is valid!")
  • content_by_lua_file 指令会加载 validate_post.lua 文件并执行其中的代码。
  • Lua 脚本中会校验请求的 POST 参数 nameemail,如果校验失败,则返回 400 错误和相应的错误消息;如果校验通过,则返回 “Request is valid!”。

优点

  1. 高性能:Lua 脚本在 Nginx 内部运行,性能非常高,适合高并发环境。
  2. 灵活性:通过 Lua 脚本可以实现复杂的逻辑,而无需依赖外部应用服务器。
  3. 易于管理:将 Lua 脚本分离成独立的文件,便于管理和维护。
  4. 无缝集成:可以与现有的 Nginx 配置结合,避免了额外的服务或依赖。

注意事项

  1. 错误处理:需要确保 Lua 脚本中有适当的错误处理机制。由于 Lua 脚本的执行可能会出现错误(例如参数解析失败),应该使用 ngx.statusngx.say 返回清晰的错误信息。
  2. 性能影响:尽管 Lua 本身非常高效,但如果 Lua 脚本过于复杂,或者需要频繁的 I/O 操作,可能会影响 Nginx 的性能。在设计时应考虑性能瓶颈。
  3. 依赖 Lua 模块:需要在编译 Nginx 时加入 ngx_http_lua_module 模块,或者通过 OpenResty 来使用这个功能。

实战

漏洞分析

在这里插入图片描述

从描述中可以看出,这是一个典型的 NoSQL 注入漏洞,攻击者通过构造恶意输入,试图绕过应用程序的逻辑,直接操作数据库。

NoSQL 注入是一种利用应用程序对用户输入处理不当,向 NoSQL 数据库注入恶意操作符(如 $ne$gt 等)的攻击方式。攻击者可以通过这种方式绕过应用程序的逻辑,直接操作数据库,导致数据泄露、篡改或删除。

攻击者通过构造恶意 JSON 数据,将 pagestartDateendDate 参数的值替换为 NoSQL 操作符(如 $ne),试图绕过应用程序的逻辑校验。

恶意请求示例

{
  "page": { "$ne": "1" },
   ......
   ......
  "startDate": "2024-06-{ \"$ne\": \"1\" }9",
  "endDate": "2024-{ \"$ne\": \"1\" }2-{ \"$ne\": \"1\" }9"
}

响应结果

  • 服务器返回了 500 错误,并提示 JSON 解析失败。
  • 虽然本次攻击未成功,但暴露了应用程序对输入参数的处理存在安全隐患。

借助 Nginx + Lua 修复

Nginx 是一个高性能的 Web 服务器和反向代理服务器,而 Lua 是一种轻量级、高效的脚本语言。通过将 Lua 嵌入到 Nginx 中,我们可以在请求到达后端应用之前,对用户输入进行实时检测和过滤,从而有效防御 NoSQL 注入攻击。

1. 环境准备

确保 Nginx 已安装并支持 Lua 模块。
在这里插入图片描述

2. Nginx 配置

在 Nginx 配置文件中,添加 Lua 脚本的路径和共享内存区域,并配置 Lua 脚本处理请求。

user root;
worker_processes 1;

events {
    worker_connections 1024;
}

http {
    include mime.types;
    default_type application/octet-stream;

    # 定义共享内存区域,用于 Lua 脚本缓存
    lua_shared_dict my_cache 10m;

    # 设置 Lua 模块搜索路径
    lua_package_path "/opt/nginx/lib/lua/?.lua;;";
    lua_package_cpath "/root/nginx/sbin/lib/lua/5.1/?.so;/root/nginx/sbin/lib/?.so;;";

    # 启用请求体读取
    lua_need_request_body on;

    server {
        listen 8989;
        server_name localhost;

        location /api {
            # 使用 Lua 脚本处理请求
            content_by_lua_file /opt/nginx/lib/lua/business_handler.lua;
        }
    }
}

3. Lua 脚本实现

在 Lua 脚本中,实现对请求体的解析和 NoSQL 注入检测。

business_handler.lua
local inject_check = require "mongo_inject_check"

-- 业务处理主函数
local function handle_request()
    -- 记录请求日志
    inject_check.log_request()

    -- 进行注入检查
    if not inject_check.validate_request_body() then
        return ngx.exit(ngx.HTTP_BAD_REQUEST)
    end

    -- 正常处理请求
    ngx.status = ngx.HTTP_OK
    ngx.header.content_type = "application/json"
    ngx.say('{"status": "OK"}')
end

-- 执行请求处理
handle_request()
mongo_inject_check.lua
local json = require("cjson")
local _M = {}

-- 检查是否包含 MongoDB 操作符
local function check_mongo_operators(str)
    local operators = {
        "$ne", "$gt", "$lt", "$gte", "$lte", 
        "$in", "$nin", "$regex", "$where", "$exist"
    }

    str = string.lower(str)
    
    for _, op in ipairs(operators) do
        if string.find(str, op, 1, true) then
            ngx.log(ngx.WARN, "Operator injection detected: " .. op)
            return false
        end
    end
    
    return true
end

-- 主验证函数
function _M.validate_request_body()
    -- 读取请求体
    ngx.req.read_body()
    local body = ngx.req.get_body_data()
    
    if not body then
        ngx.log(ngx.ERR, "Empty request body")
        ngx.status = ngx.HTTP_BAD_REQUEST
        ngx.header.content_type = "application/json"
        ngx.say(json.encode({
            status = ngx.HTTP_BAD_REQUEST,
            message = "Empty request body"
        }))
        return false
    end

    -- 检查请求体中是否包含 MongoDB 操作符
    local is_valid = check_mongo_operators(body)
    if not is_valid then
        ngx.log(ngx.ERR, "Potential injection detected")
        ngx.status = ngx.HTTP_BAD_REQUEST
        ngx.header.content_type = "application/json"
        ngx.say(json.encode({
            status = ngx.HTTP_BAD_REQUEST,
            message = "Potential injection detected"
        }))
        return false
    end

    return true
end

-- 记录请求日志
function _M.log_request()
    local request_method = ngx.var.request_method
    local request_uri = ngx.var.request_uri
    local client_ip = ngx.var.remote_addr

    ngx.log(ngx.INFO, string.format(
        "Request - Method: %s, URI: %s, IP: %s", 
        request_method, request_uri, client_ip
    ))
end

return _M

测试与验证

恶意请求
在这里插入图片描述NGINX ERROR日志如下

在这里插入图片描述


小结

通过 Nginx + Lua 的组合,我们可以在网关层实现对 NoSQL 注入攻击的有效防御。这种方案具有以下优势:

  1. 高性能:Lua 脚本轻量高效,对请求处理性能影响极小。
  2. 灵活性:可以根据具体需求扩展检测逻辑。
  3. 安全性:在请求到达后端应用之前完成检测,有效降低攻击风险。

在这里插入图片描述


http://www.kler.cn/a/462983.html

相关文章:

  • ESP32 I2S音频总线学习笔记(一):初识I2S通信与配置基础
  • redux react-redux @reduxjs/toolkit
  • 《Vue3实战教程》37:Vue3生产部署
  • 2025-1-2-sklearn学习(30)模型选择与评估-验证曲线: 绘制分数以评估模型 真珠帘卷玉楼空,天淡银河垂地。
  • C++ 设计模式:备忘录模式(Memento Pattern)
  • 【Java设计模式-1】单例模式,Java世界的“独苗”
  • 【TensorFlow】Keras介绍与入门
  • redis zset底层实现
  • react相关报错--持续更新中
  • Android studio 将项目打包apk
  • 新年算法题:矩阵对称性检测
  • Linux 内核学习(3) --- 内核中断机制
  • 单片机-- 51-keil使用查看空间占用
  • C++ 设计模式:状态模式(State Pattern)
  • FristiLeaks_1.3靶场渗透
  • [羊城杯 2024]1z_misc
  • [创业之路-230]:《华为闭环战略管理》-5-华为的组织架构与业务架构是不同的,组织架构是为业务架构服务
  • Docker网络与数据卷持久化
  • 三、AI知识(自然语言处理)
  • 记录uniapp组件swiper自适应高度
  • 期权懂|个股期权的流动性如何?
  • 生成埃里克卡特曼人工智能语音听起来像他或配音视频
  • PyTorch transpose、permute、view和einops.rearrange
  • LeetCode 热题 100_二叉树的直径(40_543_简单_C++)(二叉树;递归)
  • pip安装paddle失败
  • 【AIGC篇】“智” 造元宇宙新境:AIGC 于虚拟现实的奇幻征途