安全开发设计一个简单的waf(一)

admin 2025-12-25 02:38:15 网络安全文章 来源:ZONE.CI 全球网 0 阅读模式

文章总结: 本文阐述基于OpenResty与Lua设计简单WAF的架构,涵盖项目目录结构及Nginx核心配置详解。重点分析worker进程、MIME类型、Lua脚本挂载点及共享内存字典配置,深入解析access、body_filter等阶段实现请求检查与响应过滤。同时说明反向代理设置及常用Nginx指令含义,为后续Lua规则引擎开发与测试奠定基础,指导开发者构建基础Web应用防护系统。 综合评分: 84 文章分类: 安全开发,安全工具,WEB安全


cover_image

安全开发设计一个简单的waf(一)

原创

pr0phet

千兆安全

2025年12月24日 19:22 山西

在看文章前,建议先得有点预备知识,以下三点必须学会初步运用

  • lua
  • openresty
  • nginx

项目结构

simplewaf/├── conf/│   ├── nginx.conf                    # OpenResty主配置│   ├── waf-config.json              # WAF主配置│   ├── mime.types                   # MIME类型配置│   └── rules/│       ├── sql-injection.json       # SQL注入规则│       ├── xss.json                 # XSS规则│       ├── path-traversal.json      # 路径遍历规则│       ├── command-injection.json   # 命令注入规则│       └── bad-bots.json            # 恶意爬虫规则├── lua/│   ├── simplewaf.lua               # 主入口模块│   ├── simplewaf-admin.lua         # 管理接口模块(新增)│   ├── rule-engine.lua             # 规则引擎│   ├── request-processor.lua       # 请求处理器│   ├── response-processor.lua      # 响应处理器│   ├── logging.lua                 # 日志模块│   ├── ip-blacklist.lua            # IP黑名单│   ├── utils.lua                   # 工具函数│   └── resty/                      # 第三方库目录│       └── README.md               # 库说明├── html/│   ├── block.html                  # 拦截页面│   └── index.html                  # 测试页面├── logs/                           # 日志目录(运行时生成)├── docker/│   ├── Dockerfile                  # Docker容器配置│   └── docker-compose.yml          # Docker Compose配置├── test/│   ├── test-attacks.lua            # 攻击测试脚本│   ├── test-waf.lua                # WAF功能测试│   └── test-data/│       └── sample-attacks.txt      # 测试攻击载荷└── README.md                       # 项目说明文档

首先看openresty的主配置–nginx.conf

worker_processes auto;error_log logs/error.log warn;pid logs/nginx.pid;events {    worker_connections 1024;}http {    # 基础配置    include mime.types;    default_type application/octet-stream;    sendfile on;    keepalive_timeout 65;        # Lua包路径    lua_package_path "$prefix/lua/?.lua;;";    lua_package_cpath "$prefix/lib/?.so;;";        # 共享内存字典(用于IP黑名单等)    lua_shared_dict waf_ip_blacklist 10m;    lua_shared_dict waf_request_counter 10m;        # 初始化阶段    init_by_lua_block {        -- 加载WAF主模块        require("simplewaf").init()    }        # 初始化worker    init_worker_by_lua_block {        require("simplewaf").init_worker()    }        # 主服务器配置    server {        listen 80;        server_name localhost;                # WAF检查阶段        access_by_lua_block {            local waf = require("simplewaf")            waf.check_request()        }                # 内容处理阶段(可选响应检查)        body_filter_by_lua_block {            local waf = require("simplewaf")            waf.check_response()        }                # 日志阶段        log_by_lua_block {            local waf = require("simplewaf")            waf.log_request()        }                # 默认后端应用(模拟被保护的应用)        location / {            proxy_pass http://backend_app;            proxy_set_header Host $host;            proxy_set_header X-Real-IP $remote_addr;        }                # WAF管理接口        location /waf-admin {            access_by_lua_block {                -- 简单的管理认证                local auth = ngx.req.get_headers()["X-WAF-Admin-Token"]                if auth ~= "your-secret-token" then                    ngx.exit(403)                end            }            content_by_lua_block {                require("simplewaf.admin").handle_request()            }        }                # 拦截页面        location /waf-block {            internal;            default_type text/html;            content_by_lua_block {                ngx.say(require("simplewaf").get_block_page())            }        }    }        # 后端应用(模拟)    upstream backend_app {        server 127.0.0.1:8080;    }}

这里就设计到nginx的配置,这里简单说下都是什么意思

worker_processes auto;设置值为auto,表示设置 Nginx 工作进程数根据cpu核心数来自动设置
error_log logs/error.log warn;错误日志为 logs/error.log,日志告警级别为warn
pid logs/nginx.pid;指定 Nginx 的进程 ID 文件路径为 logs/nginx.pid
events {    worker_connections 1024;}每个进程设置连接数最大为1024

再看http模块

首先设置mime类型,根据文件后缀设置对应的Content-type,默认的mime类型为application/octet-stream

types {    text/html                             html htm shtml;    text/css                              css;    text/xml                              xml;    image/gif                             gif;    image/jpeg                            jpeg jpg;    application/javascript                js;    application/atom+xml                  atom;    application/rss+xml                   rss;
    text/mathml                           mml;    text/plain                            txt;    text/vnd.sun.j2me.app-descriptor      jad;    text/vnd.wap.wml                      wml;    text/x-component                      htc;
    image/png                             png;    image/svg+xml                         svg svgz;    image/tiff                            tif tiff;    image/vnd.wap.wbmp                    wbmp;    image/webp                            webp;    image/x-icon                          ico;    image/x-jng                           jng;    image/x-ms-bmp                        bmp;
    font/woff                             woff;    font/woff2                            woff2;
    application/java-archive              jar war ear;    application/json                      json;    application/mac-binhex40              hqx;    application/msword                    doc;    application/pdf                       pdf;    application/postscript                ps eps ai;    application/rtf                       rtf;    application/vnd.apple.mpegurl         m3u8;    application/vnd.ms-excel              xls;    application/vnd.ms-fontobject         eot;    application/vnd.ms-powerpoint         ppt;    application/vnd.wap.wmlc              wmlc;    application/vnd.google-earth.kml+xml  kml;    application/vnd.google-earth.kmz      kmz;    application/x-7z-compressed           7z;    application/x-cocoa                   cco;    application/x-java-archive-diff       jardiff;    application/x-java-jnlp-file          jnlp;    application/x-makeself                run;    application/x-perl                    pl pm;    application/x-pilot                   prc pdb;    application/x-rar-compressed          rar;    application/x-redhat-package-manager  rpm;    application/x-sea                     sea;    application/x-shockwave-flash         swf;    application/x-stuffit                 sit;    application/x-tcl                     tcl tk;    application/x-x509-ca-cert            der pem crt;    application/x-xpinstall               xpi;    application/xhtml+xml                 xhtml;    application/xspf+xml                  xspf;    application/zip                       zip;
    application/octet-stream              bin exe dll;    application/octet-stream              deb;    application/octet-stream              dmg;    application/octet-stream              iso img;    application/octet-stream              msi msp msm;
    audio/midi                            mid midi kar;    audio/mpeg                            mp3;    audio/ogg                             ogg;    audio/x-m4a                           m4a;    audio/x-realaudio                     ra;
    video/3gpp                            3gpp 3gp;    video/mp2t                            ts;    video/mp4                             mp4;    video/mpeg                            mpeg mpg;    video/quicktime                       mov;    video/webm                            webm;    video/x-flv                           flv;    video/x-m4v                           m4v;    video/x-mng                           mng;    video/x-ms-asf                        asx asf;    video/x-ms-wmv                        wmv;    video/x-msvideo                       avi;}

sendfile开启,允许操作系统直接从文件系统将文件内容传输到网络缓冲区keepalive_timeout长连接超时时间

server模块大部分我都写了注解,重点说一下代理方面的

location / {            proxy_pass http://backend_app;            proxy_set_header Host $host;            proxy_set_header X-Real-IP $remote_addr;        }

这段配置的作用是:

  1. 将所有对 Nginx 服务器的请求(路径为 /)代理到后端应用服务器 backend_app。
  2. 在代理请求时,设置请求头 Host 为客户端请求的主机名,确保后端服务器能够正确识别请求的主机名。
  3. 设置请求头  X-Real-IP 为客户端的真实 IP 地址,确保后端服务器能够获取客户端的真实 IP 地址。
 upstream backend_app {        server 127.0.0.1:8080; }

后端应用组一般搭配proxy_pass一起用,常用于负载均衡

配置中还有设置的一些模块如下

set_by_lua:设置变量; rewrite_by_lua:转发、重定向等; access_by_lua:准入、权限等; content_by_lua:生成返回内容; header_filter_by_lua:应答头过滤处理; body_filter_by_lua:应答体过滤处理; log_by_lua:日志记录。

这些主要搭配lua脚本执行

下期将开始讲解lua脚本,把核心处理逻辑脚本过一遍,最后一期编写测试用例和规则


免责声明:

本文所载程序、技术方法仅面向合法合规的安全研究与教学场景,旨在提升网络安全防护能力,具有明确的技术研究属性。

任何单位或个人未经授权,将本文内容用于攻击、破坏等非法用途的,由此引发的全部法律责任、民事赔偿及连带责任,均由行为人独立承担,本站不承担任何连带责任。

本站内容均为技术交流与知识分享目的发布,若存在版权侵权或其他异议,请通过邮件联系处理,具体联系方式可点击页面上方的联系我

本文转载自:千兆安全 pr0phet《安全开发设计一个简单的waf(一)》

评论:0   参与:  5