WAF 规则
Plus 提供的 WAF 功能也是基于 Edgelang 实现的,所以用户可以通过 Edgelang 编写高效的 WAF 规则集。
我们的 WAF 模块与其他 WAF 模块在使用相同规则集的情况下的性能对比图。
这里我们提供一个拦截 /root.exe 恶意请求的例子。
创建 WAF 模块
WAF 模块 与普通 Edgelang 模块的区别就是 WAF 模块需要使用 waf-mark-risk
标记恶意请求。我们创建一个名为 reject-root 的 WAF 模块,源码如下:
uri eq "/root.exe" =>
waf-mark-risk(msg: "reject root.exe");
一个 WAF 模块中也可以包含多条规则,例如:
uri eq "/root.exe" =>
waf-mark-risk(msg: "reject root.exe");
uri contains "/other.exe" =>
waf-mark-risk(msg: "reject other.exe");
导出 WAF 模块
点击保存并编译,然后可以从下面的编译历史中下载编译后的 zip 压缩包。
解压后将其中的 .ljbc
文件复制到 nginx.conf 中指定的 lua_package_path
目录下。
此外,在列表页面可以通过多选 WAF 模块的方式一次性导出多个 WAF 模块。
使用 WAF 模块
需要使用 orwaf:add_rule_set
添加规则集,然后在服务入口前使用 orwaf:run
运行指定的规则集。 如果请求命中了 WAF 规则集,orwaf:run
会返回命中信息。
orwaf:add_rule_set(rule_set_name, rule_set_module_name)
- rule_set_name: 给规则集定义一个名称,在后面将通过名称来选择要执行的规则集,可以和 WAF 模块名不同。
- rule_set_module_name: WAF 模块名。
orwaf:run(rule_set_names)
- rule_set_names: 需要运行的规则集列表
以下是一个完整的 nginx.conf 示例。
worker_processes auto;
events {
worker_connections 1024;
}
http {
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
lua_shared_dict dymetric_version 1m;
lua_shared_dymetrics dymetrics 10m;
init_worker_by_lua_block {
local orwaf = require "orwaf".new()
local res, err = orwaf:add_rule_set("reject-root")
if not res then
ngx.say("err: ", err)
return
end
}
server {
listen 127.0.0.1:80;
listen [::1]:80;
server_name localhost;
location / {
content_by_lua_block {
local matches, err = orwaf:run({"reject-root"})
if matches then
ngx.log(ngx.ERR, "ok: matches = ", require("cjson.safe").encode(matches))
ngx.exit(403)
end
}
}
}
}
内置规则集
除了可以通过 WAF 模块定义的规则集,我们也内置了 OWASP 的规则集。
- scanner_detection
- protocol_enforcement
- protocol_attack
- attack_lfi
- attack_rfi
- attack_rce
- attack_php
- attack_nodejs
- attack_xss
- attack_sqli
- attack_session_fixation
- attack_java
调用方法和自定义规则集一样。
location / {
content_by_lua_block {
local matches, err = orwaf:run({"scanner_detection", "protocol_enforcement", "protocol_attack"})
if matches then
ngx.log(ngx.ERR, "ok: matches = ", require("cjson.safe").encode(matches))
ngx.exit(403)
end
}
}