我们使用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. 一种解决h5页面背景音乐不能自动播放的方案

    场景:微信.浏览器.App 普通解决方案:采用audio标签的autoplay属性 现象: 大部分IOS系统和少部分Android微信不支持自动播放 $解决方案:监听WeixinJSBridgeRea ...

  2. (Problem 57)Square root convergents

    It is possible to show that the square root of two can be expressed as an infinite continued fractio ...

  3. (IOS)签名Demo

    思路是将每一次按下屏幕的touch move时的点存到一个数组里,即一个数组相当于一个笔画:再将该代表笔画的数组保存到一个大数组中,每组每次touch的移动都历遍大数组和笔画数组,将点于点之间连接起来 ...

  4. Android项目增加混淆

    主要介绍向Android项目中添加混淆功能 增加混淆的原因 提高安全性,增加反编译的难度 减少APK的文件大小 实践 混淆的配置 一般情况下,app module 的 build.gradle 文件默 ...

  5. struts OGNL数据标签

    OGNL对象图导航语言,类似于el表达式,strut的底层就是用这个写的在导入struts-core的时候会导入ognl.jar public class Test { public static v ...

  6. [WPF疑难]如何禁用窗口上的关闭按钮

    原文 [WPF疑难]如何禁用窗口上的关闭按钮 [WPF疑难]如何禁用窗口上的关闭按钮                                           周银辉 哈哈,主要是调用Rem ...

  7. Poj 2499 Binary Tree(贪心)

    题目链接:http://poj.org/problem?id=2499 思路分析:结点向左边移动时结点(a, b)变为( a+b, b),向右边移动时( a, b )变为( a, a + b); 为求 ...

  8. 一、cocos2dx之如何优化内存使用(高级篇)

    本文由qinning199原创,转载请注明:http://www.cocos2dx.net/?p=93 一.内存优化原则 为了优化应用内存,你应该知道是什么消耗了你应用的大部分内存,答案就是Textu ...

  9. opencv kmeans 图像分割

    利用kmeans算法,将彩色图像的像素点作为样本,rgb值作为样本的属性, 对图像所有的像素点进行分类,从而实现对图像中目标的分割. c++代码(openCV 2.4.11) Scalar color ...

  10. Eclipse开启与关闭代码自动提示功能

        Eclipse代码里面的代码提示功能默认是关闭的,只有输入“.”的时候才会提示功能,用vs的用户可能不太习惯 这种,vs是输入任何字母都会提示,下面说一下如何修改eclipse配置,开启代码自 ...