发布于周五 15:035天前 **SafeLine扩展插件系统**(以下简称插件系统)采用Lua脚本语言(目前语法兼容Lua5.1),与雷驰WAF深度集成,为有闲暇定制WAF的用户提供了无需修改WAF本身即可扩展其功能的接口。 #什么是Lua Lua 是一种轻量级、紧凑的脚本语言。 Lua解释器包括标准库及其相关库在64位Linux下占用不到1M的空间。同时Lua成熟可靠,在解释型脚本语言中性能最好。另一方面,Lua也非常容易嵌入到其他语言实现的应用程序中,以扩展其可编程性,例如Redis、OpenResty等 # Lua扩展插件如何在雷驰WAF中运行 雷驰WAF流量检测的运行逻辑大致如下。客户端和服务器之间的流量在经过转发服务时会被劫持,然后发送到检测服务。检测完成后,检测服务会回复转发服务“是否拦截”结果。同时,检测服务也会将这个检测信息和一些流量的信息发送到日志服务。日志服务在检测过程中会异步处理检测信息。 Lua扩展插件也运行在这里。 为了平衡转发检测的稳定性和功能的实用性,我们选择在检测信息的处理过程中允许用户执行Lua。这样既保证了检测服务的性能不受Lua扩展插件的影响,又提供了足够的接口来完成各种统计任务、数据上报任务以及各种联动任务。即便如此,我们仍然希望Lua扩展插件能够有更好的处理性能,所以我们选择使用Luajit来获得更快的速度。 LuaJIT 是Lua 编程语言的即时编译器。 即时(JIT)技术在运行时记录和分析代码执行过程中的热点,并对热点进行额外的编译,形成相应的机器代码。后续执行时,将直接使用机器码处理相应的代码部分,以达到提高效率的目的。作为一个大流量处理设备,雷驰的Lua扩展插件会不断重复执行不同的请求流量。热点位置比较稳定,可以很好地发挥JIT的作用。 # Lua扩展插件使用方法 我们先来看一个简单的Lua扩展插件示例。 本地安全线=require(\'安全线\') -- arg_risk 的可能值: -- 安全线.RISK_NORMAL -- 安全线.RISK_LOW -- 安全线.RISK_MEDIUM -- 安全线.RISK_HIGH 本地arg_risk=safeline.RISK_MEDIUM 本地arg_range=60 * 30 本地arg_period=5 本地arg_threshold=3 本地查询=string.format([[ 选择源IP 来自检测日志 其中风险级别=%d 按幻灯片_窗口分组(NOW(), %d, %d), src_ip 计数(*)=%d ]]、arg_risk、arg_range、arg_period、arg_threshold) 函数过程(键,行) 本地total_num=0 本地err_num=0 对于行中的行做 err=safeline.action_ban(safeline.ACTION_SCOPE_ALL, { ip=row.src_ip }, 3600) 总数=总数+ 1 如果err ~=nil 那么 错误编号=错误编号+ 1 结束 结束 如果total_num ~=0 那么 safeline.log(\'信息\', string.format(\'本次需要屏蔽%d个IP,其中%d个IP屏蔽失败\',total_num, err_num)) 结束 结束 safeline.register(safeline.TYPE_QUERY,查询,处理) 该插件实现了“封禁30分钟内发起3次及以上攻击的IP地址,有效期5秒”的功能。 在Lua扩展插件的开发过程中,首先需要导入safeline模块,然后注册一个触发器(trigger),并实现触发器被触发时的处理功能。我们简单介绍一下这几个部分。 更多插件Demo和插件文档请参考:[https://github.com/chaitin/safeline-open-platform](https://github.com/chaitin/safeline-open-platform) ## 导入 编写插件时,首先需要导入safeline模块,该模块包含插件系统提供的所有接口。 | `localsafeline=require\'safeline\'` | | --- | 出于安全原因,插件脚本中仅允许使用有限的标准库函数。 IO库中的所有函数都被禁用,OS库中只保留`time, date, Clock, timediff`等函数。 ## 注册 每个插件都需要至少调用一次注册函数来获取触发器。调用注册函数时,通常会指定触发条件及其回调函数。当条件满足时,回调函数将被调用。 注册函数签名如下: | `safeline.register(type,)` | | --- | 第一个参数type代表触发器的类型。可能的值和用途如下表所示。后续变长参数的数量和类型随类型的不同而变化。 | **触发类型** | **使用** | | --- | --- | | `safeline.TYPE\\_TICKER` |每隔一段时间执行定时任务并调用指定的回调函数| | `safeline.TYPE\\_QUERY` |给定一个类似SQL的查询语句,与给定查询匹配的请求信息将被传递给指定的回调函数| | `safeline.TYPE\\_MATCH` |给定一系列匹配条件,满足匹配条件的请求信息将被传递给指定的回调函数| ### 匹配触发器 Match触发器要求用户提供描述请求特征(仅限于某些预定义条件)的匹配表和回调函数流程。当通过SafeLine 的请求满足匹配描述时,将在请求的上下文中调用回调函数过程。注册方法如下: | `localsafeline=require\'safeline\'` `localmatch={` `ip=\'0.0.0.0/0\',` `host=\\[\\[.\\*\\.chaitin\\.cn:80\\]\\],` `url\\_path=\\[\\[/.\\*safeline\\]\\],` `target=safeline.MATCH\\_TARGET\\_ALL,` `}` `functionprocess(ip,host,url\\_path)` `--在这里处理请求` `end` `safeline.register(safeline.TYPE\\_MATCH,match,process)` | | ---| ### 股票行情触发器 Ticker触发器会根据用户指定的周期定期调用回调函数。 **集群部署模式下也能保证定时器的正确性**。注册方法如下: | `localsafeline=require\'safeline\'` `localduration=10` `functiontick(dur)` `--在此处理计划任务` `end` `safeline.register(safeline.TYPE\\_TICKER,duration,tick)` | | ---| uration是一个整数,用于声明插件的触发间隔,单位为秒。 ticker 是插件的回调函数,在插件触发时调用。参数dur的值是插件的触发时间间隔,单位是秒。该函数没有返回值。 ### 查询触发器 查询触发器允许用户使用PlumberSQL对请求进行流式统计,每次生成统计结果都会传递给回调函数。注册方法如下: | `\\--导入safeline 包` `safeline=require(\'safeline\')` `\\--指定PlumberSQL` `query=\\[\\[SELECTip,timeFROMaccess\\_logWHEREtime0.01\\]\\]` `\\--处理PlumberSQL 生成的结果` `functionprocess(key,rows)` `forrowinrowsdo` `safeline.log(\'INFO\',\'IP:\'.row.ip.\',Time:\'.row.time)` `end` `end` `\\--注册查询触发器` `safeline.register(safeline.TYPE\\_QUERY,query,process)` | | ---| PlumberSQL是一种类似SQL的数据操作语言(DataManipulationLanguage),可以使用Safeline的访问日志和检测日志作为数据源,在周期性时间窗口或滑动窗口内对数据进行过滤、分组和聚合等操作。 ## 接口函数 ### 访问频率控制 | `err=safeline.action\\_ban(范围、键、持续时间)` | | ---| 满足关键约束的请求将被阻止持续时间秒。 持续时间是一个整数,以秒为单位。 当提交请求成功时该函数返回nil,当提交请求失败时返回一个包含错误信息的字符串。 ### 插件日志 | `safeline.log(标签,消息)` | | --- | 生成插件日志,可以在SafeLine管理界面**“日志管理”→“扩展插件日志”**查看日志。 ** `tag` 和`msg` 都是字符串类型。 tag 用于标记日志的类别。值为“system”的标签由插件系统保留并在内部使用。 `msg` 是日志内容。 `tag` 和`msg` 都不能为空。 该函数没有返回值。 # 总结 **SafeLine扩展插件系统**作为Web流量处理网关,在保证性能和稳定性的同时,提供了丰富的扩展接口,支持更多定制方式处理接收到的HTTP请求,为用户提供更自由的可编程性,提供更快捷的业务实现方法。
创建帐户或登录后发表意见