基于lua的DDoS攻击防护应用实践

一、背景

当前,业界DDoS攻击防护规则都是基于预置的规则进行配置,产品提前定义了什么规则选项,用户就只能配置对应的规则选项,这样就存在一些局限,如:

  • 对于某些攻击特征的报文(如非常规的TCP/UDP等协议,或跨层多重攻击特征联合),预置的防护规则不能有效地防护;
  • 不能对报文的任意数据(包括比特位级别)内容进行算术、关系或逻辑运算等防护处理,如:payload[16] = (payload[14] &0xf0) | (payload[15] & 0xf)运算匹配;
  • 对于集采或外测等可能存在未知攻击报文的防护场景时,需要较长的时间针对攻击报文特征开发补丁升级包;

针对上述局限,本文研究一种基于lua语言的插件机制并将其应用到DDoS防护引擎,使得DDoS攻击防护功能具有二次开发能力,实现用户可以根据业务的实际需求场景灵活自定义DDoS攻击防护策略。实际测试表明:基于lua语言插件技术的防护引擎性能与攻击报文流量大小、报文类型、攻击特征类型、攻击特征数据长度、用户自定义的lua防护脚本编程逻辑及其算法复杂度等因素相关,对于100字节长度以内、位置固定特征固定的攻击特征数据应用场景,高效简约的lua脚本防护策略可保持与现有群组防护策略基本相当的防护性能。在性能要求不苛刻或非极端性能业务场景,基于lua的DDoS攻击防护机制可以大大提高DDoS防护规则的配置灵活性和其业务场景的适应能力。

二、插件机制

Lua语言是一门嵌入式脚本语言,它以小巧、高效和易扩展而闻名,它作为一个扩展库加载到应用程序中,实现将Lua的功能融入到应用程序。应用程序可以在Lua环境中注册新的函数,这些函数由C语言实现,这样可以增加一些Lua不容易实现的功能,从而扩展Lua应用场景。C语言与Lua之间的交互包含如下两种方式:

  • C语言具有控制权而Lua为其提供扩展库,这种方式下的C代码被称为应用代码。
  • Lua具有控制权而C语言为其提供扩展库,这种方式下的C代码被称为扩展库代码。

两种方式下,作为应用代码或扩展库代码的C语言都使用了相同的API(称为C-API)与Lua进行通信,C-API是一个允许C代码与Lua交互的函数集合,它由以下几类函数或宏构成:

  • 读写Lua全局变量的函数;
  • 调用Lua函数的函数;
  • 运行Lua代码片段的函数;
  • 注册C函数到Lua的函数;

如图1所示,C语言与Lua之间通信依赖于一个虚拟的栈,几乎所有的C-API函数调用都是对栈上的值进行操作,所有C与Lua之间的数据交互也通过这个虚拟栈完成。

图1 C语言与Lua虚拟机C-API通信栈

C-API通过索引访问栈中的数据,有两种索引计数方式:

  • 从栈底开始计数1,向栈顶方向计数值增加;
  • 从栈顶开始计数-1,向栈底方向计数值减少。

通常情况下,选择栈顶开始计数相较于栈底开始计数的方式更加便捷。

三、设计模型

图2 lua插件在DDoS攻击防护引擎中的设计模型及逻辑架构

如图2所示,从控制平面和数据平面两个维度描述基于lua语言的插件机制在DDoS防护引擎中的设计模型及逻辑架构,具体如下:

  • 控制平面
    • luaman下发自定义DDoS攻击防护规则lua脚本文件名称及优先级到防护引擎;
    • 防护引擎动态加载自定义DDoS攻击防护规则脚本到LuaJIT虚拟机,解释并编译lua脚本为字节码,将缓存字节码到高速缓存;
    • 更新自定义DDoS攻击防护规则到工作线程;
  • 数据平面
    • 工作线程遍历自定义DDoS攻击防护规则表,根据自定义DDoS攻击防护规则优先级从高速缓存中获取自定义的DDoS攻击防护脚本字节码;
    • LuaJIT虚拟机执行自定义DDoS攻击防护规则脚本字节码,并返回防护决策到工作线程;
    • 工作线程根据自定义DDoS攻击防护lua脚本返回的决策对报文采取“丢弃”、“放行”或“忽略”等决策。
图3 防护引擎与内嵌LuaJIT虚拟机交互关系图

在防护引擎中,每个工作线程各自独立地对应一个LuaJIT虚拟机,并绑定到独立的CPU;所有LuaJIT虚拟机共享所有的自定义DDoS攻击防护规则,从以下几个方面实现:

  • 防护引擎初始化时为每个CPU创建两个以数据结构lua_State表示的LuaJIT虚拟机,其中,一个虚拟机处于数据平面管理的Working列表,另一个则处于配置平面管理的Standby列表;
  • 配置线程接收用户下发的自定义DDoS攻击防护规则(包括lua防护脚本文件名称及对应的优先级等信息),每个CPU对应在Standby列表中的LuaJIT虚拟机根据自定义DDoS攻击防护规则优先级加载lua防护脚本,解释并编译lua防护脚本为字节码,并将lua防护脚本字节码缓存到高速缓存;
  • 防护引擎通过一个指向LuaJIT虚拟机Working列表的指针索引自定义DDoS攻击防护配置,当索引指针交换Working列表和Standby列表指向时,完成自定义DDoS防护规则的配置过程,实现自定义DDoS攻击防护配置的动态切换与管理。

工作线程在访问Working列表中的LuaJIT虚拟机周期过程中持有一个引用计数,并在访问周期结束时释放该引用计数。当配置线程收到一个自定义DDoS攻击防护配置动态变更请求时将检查Standby列表中LuaJIT虚拟机的引用计数,如果至少有一个LuaJIT虚拟机的引用计数大于0,则表明上一次配置变更(指针由指向Working切换到Standby)尚未完成,需要等待访问该LuaJIT虚拟机的工作线程完成剩余报文的处理后释放引用计数。否则,配置线程根据新的请求配置对Standby LuaJIT虚拟机列表中的每一个虚拟机环境进行变更处理(主要包括lua防护脚本的卸载与加载等),并切换指针的指向完成配置的动态变更。

四、应用实践

如图4所示,模拟的HTTP攻击报文从负载数据第25个字节开始具有32字节长度的固定攻击特征,编写简约高效的自定义DDoS攻击防护lua脚本,并通过配置平面将自定义防护规则下发到引擎,实现自定义DDoS攻击防护lua脚本动态生效防护功能。

图4 HTTP攻击报文

针对影响防护引擎性能的诸多潜在因素,结合DDoS攻击防护引擎性能数据,分析LuaJIT虚拟机自身运行机制,基于lua的DDoS攻击防护可能存在如下性能陷阱:

  • 使用正则表达式模式匹配报文数据将会导致引擎防护性能急速下降;
  • 控制台打印、文件系统、数据库及其他类型的I/O读写操作将会导致引擎防护性能急速下降;
  • 未知或不确定的函数接口、错误类型的函数参数会导致引擎防护性能明显下降;
  • 相比于局部变量,全局变量的使用也会导致防护引擎性能的下降;另一方面,作用域的大小也会对防护引擎的性能有影响,应尽可能缩小局部变量的作用域;
  • lua语言的高级特性(如协程、闭包等)会导致防护引擎的性能损耗;
  • 临界区访问等互斥操作会导致防护引擎性能的明显下降;

自定义DDoS攻击防护lua脚本应该避免上述性能陷阱,尽可能用lua语言最简单的语法结构和编程逻辑实现特定攻击特征报文的防护处理。另一方面,lua脚本中尽可能按需取报文数据,不取无关的数据、不重复获取相同的数据,并在合理的地方及时结束脚本任务。

五、总结

本文主要研究了基于lua语言的插件机制实现方法及其对DDoS攻击防护性能的影响,论证了基于lua的DDoS攻击防护是可行且有意义的。通过控制平面与数据平面的分离,结合自定义DDoS攻击防护规则lua脚本的预编译和高速缓存机制及用户开发的高效简约的lua防护脚本,可以使防护引擎的性能达到最佳程度。在性能要求不苛刻或非极端性能场景,基于lua语言的插件技术可以为DDoS攻击防护提供二次开发能力,提高DDoS攻击防护规则配置的灵活性和攻击防护业务场景的适应能力。

六、参考文献

[1]. https://luajit.org/index.html

[2]. http://www.lua.org/manual/

[3]. https://openresty.org/cn/

[4].https://www.wireshark.org/

[5]. Roberto lerusalimschy著,梅隆魁译.Program in Lua,Fourth Edition

[6]. Wireshark Developer’s Guide.pdf

版权声明

本站“技术博客”所有内容的版权持有者为绿盟科技集团股份有限公司(“绿盟科技”)。作为分享技术资讯的平台,绿盟科技期待与广大用户互动交流,并欢迎在标明出处(绿盟科技-技术博客)及网址的情形下,全文转发。
上述情形之外的任何使用形式,均需提前向绿盟科技(010-68438880-5462)申请版权授权。如擅自使用,绿盟科技保留追责权利。同时,如因擅自使用博客内容引发法律纠纷,由使用者自行承担全部法律责任,与绿盟科技无关。

Spread the word. Share this post!

Meet The Author

Leave Comment