我们使用nginx贯穿了我们的网络,做前线web服务,代理,流量过滤。在某些情况下,我们已经扩充了nginx上我们自己的模块的核心C代码,但近期我们做了一个重大举措,与nginx结合使用lua

差点儿所实用lua写的我们的一个项目是新的cloudflare WAF。这个我们另有博客。​http://blog.cloudflare.com/heuristics-and-rules-why-we-built-a-new-old-waf

Lua WAF使用nginx Lua模块来嵌入Lua代码,运行Lua code就像nginx 正常handling阶段的代码一样。WAF的整个运行实际上由下列nginx配置控制:

location / {
set $backend_waf "WAF_CORE";
default_type 'text/plain';
access_by_lua '
local waf = require "waf"
waf.execute()
';
}

这个access_by_lua指令告诉nginx,运行这些Lua code作为一个access 阶段的handler。然后,WAF中的Lua代码决定是否阻断请求,或将请求传递给原始server去处理。Waf模块通过调用ngx.exit()来终结,响应码或者为200(nginx继续处理),或者为403(阻断请求)

全部真实的WAF工作被用lua写的waf模块做了。实现这个WAF,我们希望可以读取为流行mod_security开源WAF开发的现有WAF配置和支持我们自己的简单的WAF语言。该mod_security的语言已经集成到了Apache配置文件,这样导致它是有点难以阅读,但也有一个庞大的规则使用它(如流行的OWASP规则集)撰写,我们希望可以在本机执行。

在写新的WAF之前,我们实际上还执行了Apache,仅仅是为了mod_security,但这个组合缓慢,繁琐,且不能随着CloudFlare的不断增长的业务扩展。我们已经做了妥协,仅仅是为了保持它执行。

一个用mod_security本地语言写的规则像下列所看到的,(这是一个我们落实过的真实客户的有点模糊的版本号)。第一个版本号用mod_security版本号书写,第二个等价于cloudflare自己的规则语言书写。

SecRule REQUEST_HEADERS:User-Agent "@beginsWith DataStore/"
"id:100000,phase:0,t:none,deny,chain,msg:'DataStore Attack'"
SecRule REQUEST_METHOD "@streq GET" "chain"
SecRule REQUEST_URI "\/\?-?\d+=-?\d+" "" rule 100000 DataStore Attack
REQUEST_HEADERS:User-Agent has-prefix DataStore/ and
REQUEST_METHOD is GET and
REQUEST_URI matches \/\?-?\d+=-?\d+
deny

我们将开放自己定义规则来拓展更广泛的能力,无论是用mod_security还是cloudflare风格来写waf规则。最重要的是cloudflare的WAF语言不是Lua,虽然其实这个WAF是用Lua实现的。

实际上,这个WAF首先通过将无论是用mod_security还是cloudflare风格书写的规则转化成通用的JSON格式,这个JSON格式编码了规则,而且添�了一些WAF UI的额外的信息(比如这个规则是否使能)

这个JSON格式,然后编译成WAF运行的Lua程序。这个编译步骤同意我们支持不同的输入语言(像以上说的两种),而且性能得到优化,这样WAF运行的更快。

举例说明,编译器运行下面任务:

  • 子句排序,这样当一个子条款不符合时,规则能够高速跳过
  • 正則表達式的优化和简化
  • 运算符更换,这样更快的运算符(比方更简单的字符串匹配)用在可能的地方
  • 关于WAF执行的线索,关于是否宏扩展是必要的。
  • 全局优化,如识别反复使用同样的字符串或变量,并确保他们仅仅计算一次
  • Lua的优化,比如使用全局函数的本地引用

上面的规则,结果转化为例如以下Lua代码:

if waf_begins(waf, v3_6, '3_6', t3_1, '3_1', 'DataStore/', false) then
waf.vars['RULE']['ID'] = '100000'
if waf_eq(waf, v3_7, '3_7', t3_1, '3_1', 'GET', false) then
if waf_regex(waf, v3_4, '3_4', t3_1, '3_1', [=[\/\?-?\d+=-?\d+]=], false, nil, false) then
waf_activate(waf, rulefile)
waf_msg(waf, 'DataStore Attack')
waf_deny(waf, rulefile)
end
end
end

生成的代码难以阅读,由于它本质上是WAF的汇编语言,并且是自己主动生成的。Waf执行实现了像waf_begins, waf_eq, and waf_regex这些用于规则匹配的函数。这些函数本身是被高度优化的。

总的执行目标是,在真实环境执行时,WAF做阻止/通过决定的时间的中位数小于1ms。

WAF执行的优化,来自于用一个有行级时序信息的測试工具測试WAF的性能,来自于在带有很具体的基于systemtap的工具的cloudflare的网络中执行WAF。

为了在測试环境得到行级时序信息,我们写了一个小的行级的代码分析器,在我们执行一个请求測试集时使用。这个分析器,叫做lulip,是一个开源项目。它输出哪些行被调用的最频繁,哪些行消耗了最多的执行时间这些信息。

比如,这儿是一个简化的输出的版本号:

file:line     count   elapsed (ms)   line
wr.lua:1129 2 822.455 hash = ngx_sha1_bin(value)
wr.lua:1172 428 470.849 captures, err = ngx_re_match(v, p)
wr.lua:1197 3762 207.487 x = string_find(v, f)
wr.lua:212 157 154.386 string_gsub(v, "//([^/]+)//", "%1")
wr.lua:1196 3788 87.475 for i=1,g() do
wr.lua:1158 1563 52.906 if not f() then

它显示了一个ngx_sha1_bin(实际上是一个对ngx.shal_bin函数的本地的的引用)被调用了2次,可是花费了823毫秒。第二个最耗时的行是第1172行,总共花了471号码,被调用了428次。使用这些细节信息,我们可以优化指定的热点代码。

来自systemtap或者堆栈跟踪的信息反馈到我们自己的收录引擎,分析它并自己主动生成火焰图,这展示了代码在哪里执行。 将鼠标停留在不论什么部分,将给出不论什么部分的代码花费时间的百分比。

在早期的WAF的优化,火焰图高速显示闭包的广泛使用导致缓慢,因为它们的花费在LuaJIT里。编译器的改动移除了它们的使用。

从同样的信息生成的还有一种视图显示一个函数中花费(忽略它本身调用的不论什么函数)的总时间。这使得能高速识别热点函数。在这里,能够非常easy地看到,正則表達式处理和串匹配是最昂贵的操作(这并不奇怪,由于这就是WAF做什么,主要是)。

检查这些跟踪信息,我们决定改善LuaJIT开源项目是值得赞助的。

优化WAF最关键的是两件事:可反复的測试数据和工具检查执行的代码。火焰图和lulip的结合意味着通过精确的检查时间花在哪里能够让WAF性能有一个巨大的飞跃。规则编译器的使用意味着优化能够迅速的应用到全部须要的规则上。不用去推測哪里是慢的:測量它!!

生成的代码大量使用局部变量(当中有很多是由编译器自己主动生成)和内存化。我们还使用Lua 字节码的nginx Lua的缓存,以加快自己定义规则的载入,一个两阶段的内存缓存,它使用lua_shared_dict和memcached作额外的载入加速。而我们的全球分布式数据存储意味着新的规则能够在几秒钟内铺开。

最后,衡量WAF在生产环境的运作,我们有一个全球的指标体系,收集cloudflare 网络全部部分的指标,这儿是一个图标显示了WAF几个小时的执行。它显示了处理一个请求的平均时间在毫秒内。这个waf执行每一个请求花费380us到480us之间,大大优于1ms的目标。

随着语言上各种优化,编译器和WAF核心表明我们拥有了一个非常快的纯Lua waf,这给了我们非常大的灵活性,而且执行在nginx核心里。这是又一个项目指出了Lua成为了一门极其优秀的嵌入式语言,在Lua里,我们能够写Cloudflare须要的各种可扩展的逻辑。

原文链接: http://blog.cloudflare.com/cloudflares-new-waf-compiling-to-lua   膜拜前淘宝大神 章亦春

-------- translate by 囧囧有神(814329735@qq.com)

cloudflare的新waf,用Lua实现的的更多相关文章

  1. [转]Web应用防火墙WAF详解

    通过nginx配置文件抵御攻击 0x00 前言 大家好,我们是OpenCDN团队的Twwy.这次我们来讲讲如何通过简单的配置文件来实现nginx防御攻击的效果. 其实很多时候,各种防攻击的思路我们都明 ...

  2. 基于ngx_lua模块的waf开发实践

    0x00 常见WAF简单分析 WAF主要分为硬件WAF和软件防火墙,硬件WAF如绿盟的NSFOCUS Web Application Firewall,软件防火墙比较有名的是ModSecurity,再 ...

  3. Nginx详解二十八:Nginx架构篇Nginx+Lua的安全waf防火墙

    Nginx+Lua的安全waf防火墙 看一下别人写好的:https://github.com/loveshell/ngx_lua_waf 先安装git:yum -y install git 在/opt ...

  4. Nginx + Lua 搭建网站WAF防火墙

    前言 对于项目里面只是使用代理等常用功能,在线安装即可,如需制定化模块,则推荐编译安装 PS:本文不仅仅包含Nginx相关的知识点,还包含了逆天学习方法(对待新事物的处理) 官方网站:https:// ...

  5. nginx+lua实现简单的waf网页防火墙功能

    原文:http://www.2cto.com/net/201608/534272.html 安装LuaJIT http://luajit.org/download/LuaJIT-2.0.4.tar.g ...

  6. 使用Nginx+Lua实现waf

    使用Nginx+Lua实现waf 技术内容来自:https://github.com/loveshell/ngx_lua_waf 软件包需求: 1 .Nginx兼容性[最后测试到1.13.6] [ro ...

  7. 使用Nginx+Lua实现自定义WAF

    使用Nginx+Lua实现自定义WAF 版权声明:全部抄自赵班长的GitHub上waf项目 功能列表: 支持IP白名单和黑名单功能,直接将黑名单的IP访问拒绝. 支持URL白名单,将不需要过滤的URL ...

  8. 使用NGINX+LUA实现WAF功能 和nginx 防盗链

    使用NGINX+LUA实现WAF功能 一.了解WAF 1.1 什么是WAF Web应用防护系统(也称:网站应用级入侵防御系统 .英文:Web Application Firewall,简称: WAF) ...

  9. Nginx基础 - Nginx+Lua实现灰度发布与WAF

    1.Nginx加载Lua环境默认情况下Nginx不支持Lua模块, 需要安装LuaJIT解释器, 并且需要重新编译Nginx, 建议使用openrestry 1)环境准备 [root@localhos ...

随机推荐

  1. Longest Substring Without Repeating Characters - 哈希与双指针

    题意很简单,就是寻找一个字符串中连续的最长包含不同字母的子串. 其实用最朴素的方法,从当前字符开始寻找,找到以当前字符开头的最长子串.这个方法猛一看是个n方的算法,但是要注意到由于字符数目的限制,其实 ...

  2. 条款20:宁以pass-by-reference-to-const替换pass-by-value

    本条款的要点: 1.尽量以pass-by-reference-to-const替换pass-by-value.前者更高效且可以避免切割问题. 2.这条规则并不适用于内建类型及STL中的迭代器和函数对象 ...

  3. Regex阅读笔记(一)之入门

    在检查一行文本时,^代表一行的开始,$代表结束. 字符数组:[],在里面列举任意多个字符,可以匹配其中任意一个字符,字符组元字符'-'表示一个范围. ^$表示一个空行(没有任何字符,包括空白字符) [ ...

  4. windows apache 配置多个服务 站点 Apache Service Monitor

    把Apache安装为多个Window NT服务 ~~~ 可以在 services.msc中查看到1. 在DOS下跳到Apache安装目录里的bin目录(~~~或者用path命令 把apache的安装目 ...

  5. VPN各种方案

    http://www.maimiaovpn.com 大家都是用什么方法FQ的?我原来用的XskyWalker浏览器 但我用的电信网现在不行了.大家用的什么方法可否告诉我一下我用yes-vpn,10元一 ...

  6. pkusc2015

    Mex 题目大意:给出一个序列\(a\),定义\(f(l,r)\)为集合{\(a_l, a_{l+1}, -, a_r\)}的sg值,求\(\sum_i \sum_{j(i\leq j)} f(i,j ...

  7. 《Clean Code》重点内容总结

    读书笔记请见Github博客:http://wuxichen.github.io/Myblog/reading/2014/10/06/CleanCode.html

  8. Swift--基本数据类型(一)

    不像更多语言中,X不要求你写一个分号(;)在你的代码中的每一个语句后,尽管能够这样做.然而,假设你想在一行中写入多个单独的语句分号是必需的: .    1  let cat = "" ...

  9. Linux 多线程通信

    摘自资料(linux 与Windows不同) 线程间无需特别的手段进行通信,由于线程间能够共享数据结构,也就是一个全局变量能够被两个线程同一时候使用.只是要注意的是线程间须要做好同步,一般用mutex ...

  10. ubuntu15.04更新软件源

    1,首先备份原来的源 sudo cp /etc/apt/sources.list /etc/apt/sources.list_backup2,编辑软件源的文件 sudo vim /etc/apt/so ...