一. 再谈WAF

我们上一篇安装的WAF来自另一位技术大神 赵舜东,花名 赵班长,一直从事自动化运维方面的架构设计工作。阿里云MVP、华为云MVP、中国SaltStack用户组发起人 、新运维社区发起人。

虽然并非安全专业出身,但根据他的自述,边学边写,只用了几天的时间就将WAF写出来了,并于2016年正式发布到GitHub。

赵班长的WAF参考了Kindle大神写的 ngx_lua_waf ,另一款基于 OpenResty 的非常优秀的开源WAF。

不得不向 章亦春(agentzh)、赵舜东(赵班长)和 Kindle 等所有开源前辈们致以最高的敬意,让我等能有这么多的学习和实践资源,respect!

二. 了解撸啊(Lua)

在真正走近WAF之前,还是有必要对 Lua 这个脚本语言进行一番了解,因为所有的业务逻辑都是基于 Lua 实现的。

推荐两个关于Lua的学习资源:

  1. Lua基础教程与实践
  2. 菜鸟Lua教程

顺便分享本人正在使用的Lua调试工具:网盘链接

解压后其中有两个文件:

  1. LuaForWindows_v5.1.4-46.exe:适用于windows环境的Lua编译器。
  2. lua51.stx:适用于EditPlus环境的Lua语法高亮模板文件。

     

    配置完成后,在EditPlus中进行Lua的编写和测试还是很方便的:

三. 配置入口

我们回过头,再来看看上一篇Nginx的配置文件中关于WAF引用的几行关键代码:

lua_shared_dict    limit 50m;
lua_package_path "/home/my/tools/waflib/?.lua";
init_by_lua_file "/home/my/tools/waflib/init.lua";
access_by_lua_file "/home/my/tools/waflib/access.lua";

这四个指令都来自 lua-nginx-module,用来实现对 Nginx 的每个 Worker 线程中 Lua 环境的配置和定义。

1. lua_shared_dict

作用:声明一个共享内存区域

层级:http

格式:lua_shared_dict <name> <size>

由于各 Worker 线程中的 Lua 环境相对是独立的,无法共享数据,但在很多情况下,需要在不同的 Worker 之间共享数据,此时就可以通过该指令进行声明。

此例中的 limit 就是声明出来的一个共享变量,在 WAF 中的作用就是在 CC 攻击检测时判断当前用户的请求频次是否超限进行拦截。

2. lua_package_path

作用:设置 Lua 脚本文件的搜索路径。;; 表示原始搜索路径。

层级:http

格式:lua_package_path <lua-style-path-str>

官网描述:设置由 set_by_Lua、content_by_Lua 等指定的脚本使用的 Lua 模块搜索路径,它的默认值是LUA_PATH环境变量的内容或LUA的编译默认值。

个人理解:在 Lua 中引用其他文件时,比如 require 'config',就会将 config 替换掉路径中的问号并尝试查找这个文件并引入进来。

配置搜索路径参数时,还可以使用 $prefix 变量来表示当前 Nginx 的工作目录,该目录一般在启动时通过 -p PATH 参数进行定义。

如果有多个搜索路径,可用 ; 分割。

3. init_by_lua_file

作用:指定初始化配置文件。

层级:http

格式:init_by_lua_file <path-to-lua-script-file>

个人理解:该初始化配置文件仅在 Nginx 启动时运行一次,主要用于对全局变量进行预加载或预处理。

但经过实践,在对本篇的 WAF 进行配置时,删除该指令并未产生任何影响。

4. access_by_lua_file

作用:请求访问阶段处理。

层级:http, server, location, location if

格式:access_by_lua_file <path-to-lua-script-file>

个人理解:每个请求接入时,都会经过该文件的处理,其作用类似于前置拦截器。

本篇的 WAF 在对请求进行检查时,主要就是从这个文件切入的。

四. 官方文档支持

lua-nginx-module 模块的官方文档:https://github.com/openresty/lua-nginx-module

 

其中最重要的两个部分:

  1. 指令(Directives):https://github.com/openresty/lua-nginx-module#directives
  2. API(Nginx API for Lua):https://github.com/openresty/lua-nginx-module#nginx-api-for-lua

     

    在学习 OpenResty 之前,还是需要对指令和API进行详细了解的。

五. 文件说明

再来看一下 waflib 的目录清单:

  1. access.lua:请求入口文件;
  2. config.lua:WAF详细配置文件;
  3. init.lua:WAF初始化文件,包含IP白名单、黑名单、URL注入、CC攻击等各种检测函数;
  4. lib.lua:WAF函数库文件,包含获取IP、获取规则、写入日志等各种通用函数;
  5. resty:一个来自 /usr/local/openresty/lualib/resty/ 的软连接;
  6. rule-config:存放规则文件目录。

再进入到 rule-config 目录,查看其中的文件清单:



 

以第一个 args.rule 规则文件为例,我们查看一下具体内容:

\.\./
\:\$
\$\{
select.+(from|limit)
(?:(union(.*?)select))
having|rongjitest
sleep\((\s*)(\d*)(\s*)\)
benchmark\((.*)\,(.*)\)
base64_decode\(
(?:from\W+information_schema\W)
(?:(?:current_)user|database|schema|connection_id)\s*\(
(?:etc\/\W*passwd)
into(\s+)+(?:dump|out)file\s*
group\s+by.+\(
xwork.MethodAccessor
(?:define|eval|file_get_contents|include|require|require_once|shell_exec|phpinfo|system|passthru|preg_\w+|execute|echo|print|print_r|var_dump|(fp)open|alert|showmodaldialog)\(
xwork\.MethodAccessor
(gopher|doc|php|glob|file|phar|zlib|ftp|ldap|dict|ogg|data)\:\/
java\.lang
\$_(GET|post|cookie|files|session|env|phplib|GLOBALS|SERVER)\[
\<(iframe|script|body|img|layer|div|meta|style|base|object|input)
(onmouseover|onerror|onload)\=

该文件定义了 22 条检测规则,一行一个,熟悉正则的话会很容易看懂。

我们也可以根据实际情况添加新的规则。

六. 引用关系



 

4 个Lua文件和 8 个规则文件,这12个文件就是这个WAF的全部,你就说巧妙不巧妙!

七. 简单优化

赵班长向我们展示了一个迷你WAF应该具备的基本能力,从代码上也能看出来,都是点到为止。

所以有必要进行一些简单的优化。

本人优化之后的代码:点此下载

 

优化说明:

  1. 一些空值的判断逻辑;
  2. 各检测函数的跳出逻辑;
  3. 补全POST参数注入的检测逻辑;
  4. 在lib.lua中增加了get_content_type函数,用来判断请求类型;

八. 本篇总结

到这里,就已经对 OpenResty 下的 WAF 从部署到使用有了全面了解了。

如果时间允许的话,真想继续对 WAF 进行深层次的学习和定制。

OpenResty学习笔记03:再探WAF的更多相关文章

  1. C++ GUI Qt4学习笔记03

    C++ GUI Qt4学习笔记03   qtc++spreadsheet文档工具resources 本章介绍创建Spreadsheet应用程序的主窗口 1.子类化QMainWindow 通过子类化QM ...

  2. openresty 学习笔记小结:综合应用实例

    openresty 学习笔记小结:综合应用实例 这个综合实验实现的功能其实很简单,用户访问一个页面,显示一个默认页面.输入参数(post或者get都可以),如果参数在数据库查询得到并满足一定条件,根据 ...

  3. openresty 学习笔记四:连接mysql和进行相关操作

    openresty 学习笔记四:连接mysql和进行相关操作 毕竟redis是作为缓存,供程序的快速读写,虽然reidis也可以做持久化保存,但还是需要一个做数据存储的数据库.比如首次查询数据在red ...

  4. openresty 学习笔记三:连接redis和进行相关操作

    openresty 学习笔记三:连接redis和进行相关操作 openresty 因其非阻塞的调用,令服务器拥有高性能高并发,当涉及到数据库操作时,更应该选择有高速读写速度的redis进行数据处理.避 ...

  5. SaToken学习笔记-03

    SaToken学习笔记-03 如果排版有问题,请点击:传送门 核心思想 所谓权限验证,验证的核心就是一个账号是否拥有一个权限码 有,就让你通过.没有?那么禁止访问! 再往底了说,就是每个账号都会拥有一 ...

  6. Redis:学习笔记-03

    Redis:学习笔记-03 该部分内容,参考了 bilibili 上讲解 Redis 中,观看数最多的课程 Redis最新超详细版教程通俗易懂,来自 UP主 遇见狂神说 7. Redis配置文件 启动 ...

  7. 机器学习实战(Machine Learning in Action)学习笔记————03.决策树原理、源码解析及测试

    机器学习实战(Machine Learning in Action)学习笔记————03.决策树原理.源码解析及测试 关键字:决策树.python.源码解析.测试作者:米仓山下时间:2018-10-2 ...

  8. OpenCV 学习笔记03 边界框、最小矩形区域和最小闭圆的轮廓

    本节代码使用的opencv-python 4.0.1,numpy 1.15.4 + mkl 使用图片为 Mjolnir_Round_Car_Magnet_300x300.jpg 代码如下: impor ...

  9. OpenCV 学习笔记03 findContours函数

    opencv-python   4.0.1 1 函数释义 词义:发现轮廓! 从二进制图像中查找轮廓(Finds contours in a binary image):轮廓是形状分析和物体检测和识别的 ...

  10. openresty 学习笔记六:使用session库

    openresty 学习笔记六:使用session库 lua-resty-session 是一个面向 OpenResty 的安全和灵活的 session 库,它实现了 Secure Cookie Pr ...

随机推荐

  1. egret 当前运行环境

    if(egret.Capabilities.runtimeType == egret.RuntimeType.WXGAME){}

  2. 制作可以显示GIF动图的activeX 控件

    因为工作需要,我需要一个可以显示gif 动图的控件,用来在VBS中显示动图,结果找了半天发现根本没有这样的控件,所以只能搜集资料自己来制作一个. 下面记录一下步骤: 1. 下载 PictureEx.h ...

  3. 关于 Android sdk manager 的安装问题

    最近刚刚接触小程序测试,故此需要搭建环境 我用的是python3.6+appium1.8.2+Android sdk manager 关于应用程序,大家有需要的话,可以找我要. 1.关于安装Andro ...

  4. Qt开发技术:Q3D图表开发笔记(一):Q3DScatter三维散点图介绍、Demo以及代码详解

    前言   qt提供了q3d进行三维开发,虽然这个框架没有得到大量运用也不是那么成功,性能上也有很大的欠缺,但是普通的点到为止的应用展示还是可以的.  其中就包括华丽绚烂的三维图表,数据量不大的时候是可 ...

  5. hdu 4870 Rating(概率dp)

    题意:给你两个初始分数为0的账号让你去打比赛,每场比赛赢的概率为p,赢了加50分,输了-100分,当然你不会负分,每次你会用分低的账号去打比赛,问你把一个账号打到1000分的需要参加比赛次数的期望值. ...

  6. BeautifulSoup模块的使用方法

    本篇文章主要讲bs4模块(BeautifulSoup),这个模块能做么呢?用一句话来概括的话:beautifulsoup4 从HTML或XML文件中提取数据的Python库,用它来解析爬取回来的xml ...

  7. 【绘制分形图案】多重收缩打印机(MRCM)举例

    note 2020-08-05搬运 下面的内容来自我的CSDN博客 多重收缩打印机(MRCM)是生成分形图案的一种方法.主要思想还是多次迭代.   每次都是将上一次的输出拿来做线性仿射变换后重新组合在 ...

  8. Django笔记二之连接数据库、执行migrate数据结构更改操作

    本篇笔记目录索引如下: Django 连接mysql,执行数据库表结构迁移步骤介绍 操作数据库,对数据进行简单操作 接下来几篇笔记都会介绍和数据库相关,包括数据库的连接.操作(包括增删改查).对应的字 ...

  9. java数组排序及查找方法

    前言 在上一篇文章中,壹哥给大家讲解了数组的扩容.缩容及拷贝方式.接下来在今天的文章中,会给大家讲解更重要的数组排序及查找方法.今天的内容会有点难,希望你不要因此而退缩,挺过这一关,你会向上突破的! ...

  10. android使用---->常用组件1

    在TextView中创建空心文字 <TextView android:layout_width="wrap_content" android:layout_height=&q ...