# 什么是雷池?
雷池(SafeLine)是长亭科技耗时近 10 年倾情打造的 WAF,核心检测能力由智能语义分析算法驱动。由于不使用规则进行检测,雷池WAF的误报率相对更低,拦截率与性能更高。在使用雷池前,我使用ModSecurity作为源服务器的WAF使用,。经过BASE64编码的攻击载荷未能被其识别,而雷池精准的拦截了此次请求。经过测试,Fortigate WAF(未测试FortiWEB)、宝塔WAF、NAXSI均不能很好的拦截类似请求。同时,NAXSI的误报率很高,类似......的省略号会被认为成目录穿越攻击
# 为什么要设置默认站点?
长亭雷池WAF社区版,使用反向代理接入站点,当使用443或8443等常见SSL端口提供服务时,SSL证书的信息可能会被「互联网空间搜索引擎」 记录,导致源站IP地址泄漏。「互联网空间搜索引擎」是一种特殊类型的搜索引擎,它通过特定的计算机程序从互联网上采集信息,然后对这些信息进行组织和处理,为用户提供检索服务,将检索的相关信息展示给用户。这种搜索引擎的目标主要在全球的IP地址上,即搜索范围在1.1.1.1-255.255.255.255的所有设备及服务上。例如,Shodan是全球第一个网络设备搜索引擎,它可以发现从电厂、手机、冰箱到Minecraft服务器等各种联网设备。ZoomEye(“钟馗之眼”)是知道创宇旗下404实验室驱动打造的中国第一款网站空间搜索引擎。FOFA是白帽汇推出的一款网络空间搜索引擎。Quake是360网络安全响应中心自主研发设计的全网空间测绘系统,而Censys.io和微步则被广泛用于安全数据分析。
攻击者会从「互联网空间搜索引擎」搜索与域名相关的IP地址,并尝试从中找出源服务器的地址,进行进一步的探测,绕过CDN/Cloud WAF的防护,甚至进行泛洪攻击,会对安全性造成严重影响。
通常情况下建议配置防火墙白名单仅允许CDN/Cloud WAF的IP地址段访问,但鉴于国内CDN特殊情况,IP地址段并非固定,所以大部分情况下无法完成此配置。
## 如何配置雷池的Tengine?
Tengine作为雷池WAF的7层服务器,我们需要在雷池的安装目录 (即第一次使用docker安装雷池时填写的目录)中,找到Tengine (Nginx)的目录,如”/www/safeline/resources/nginx“。找到Nginx目录后,在sites-enabled 下存放着各个站点的配置文件,打开其中一个,如IF_backend_1,在文件最后增加如下的配置文件:
server {
listen 80 default_server;
listen [::]:80 default_server;
listen 443 ssl default_server;
listen [::]:443 ssl default_server;
ssl_certificate /etc/nginx/certs/de.pem;
ssl_certificate_key /etc/nginx/certs/de.key;
#此处可更改为444或其他未定义代码,403会返回雷池拦截页面
location / {
return 418;
}
access_log /etc/nginx/logs/de.log;
}
接下来,你需要确保”/etc/nginx/certs/de.pem“和”/etc/nginx/certs/de.key“以及”/etc/nginx/logs“的存在。SafeLine的容器中,”/etc/nginx“ 被映射为安装目录,如”/www/safeline/resources/nginx“,所以你需要在”/www/safeline/resources/nginx“中创建logs目录,并在certs下放入默认证书。一张空的自签名证书示例如下,可以作为默认证书使用。密钥在前,证书在后。
-----BEGIN RSA PRIVATE KEY-----
MIICXQIBAAKBgQDXyF6m81zOeoOPvfk6nGKtyfczRG6/yeSkcc+66vGvq0s8oB7V
cCzLl1YcNsru3ixelPR2z1zvjKqa9/Aqh8+TvP1kGGbLD/mynjnj8l+0vVzZ+vnz
AH0RN9fpqzlpHmFBHQzQ25AtIAH8pXOL1541YN0TNPRA3kHUCL0FH8CkwwIDAQAB
AoGAQ4ejh6AV5VCWJ8AOZXdXsofIYzUBa+glNAmiNx8b8BwteZWq0KVAf56nBkFn
lQXW4OrA7wXKUfW11rXNZaIHJePJXv1swkN9+Em18Hon6BrtcqnKAwzAbhok3SzY
IVjI/zrgOABH6+ii77xCRBzI1itVPNN88DAUHC7PYLYiaaECQQD7PSoij37+kMc/
wPeEkl9r3vzU0OrsCsjU8Ev714OaoL/SIuAh6nsiRh9rcbUrrpGSSzIcmsk9HMDa
hXBNkNl5AkEA298yQvssaUc4tbEWxAVfd9DsHJdCdbXfgf9Dy5/tpCzYncY7T0du
VVHqKu3jXWoMc5XlesiCOerU/DIlMM8dGwJBANQn7GLO5iC1xWvS2bF7oVSIMtzL
pvW4jaszWBbNAPccc59RkA9T4LMqn/GtTZ4bhhYRpbl+BB21IC3nrNPzU5ECQG8T
Ln0QDruQs2F2eR3F6RjKfr1i3LxCiQtPPZycypzp2vS5tDS0zVRk8XuGehoy/N9X
lnqU2NURgU92tbsWpokCQQDdc9tU3B/OM/YfzUNwvOLmUVwrJX6PFSFsOn+XHrCC
q9LcGEAHyzaf5GEWje84ee4rkv5oaZcwll3dg4IioBnC
-----END RSA PRIVATE KEY-----
-----BEGIN CERTIFICATE-----
MIIBkjCB/AIJAI3bCYqa39hiMA0GCSqGSIb3DQEBBQUAMA0xCzAJBgNVBAYTAiAg
MCAXDTE4MTEyNDA5MDMzOFoYDzIwOTkxMjMxMDkwMzM4WjANMQswCQYDVQQGEwIg
IDCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA18hepvNcznqDj735Opxircn3
M0Ruv8nkpHHPuurxr6tLPKAe1XAsy5dWHDbK7t4sXpT0ds9c74yqmvfwKofPk7z9
ZBhmyw/5sp454/JftL1c2fr58wB9ETfX6as5aR5hQR0M0NuQLSAB/KVzi9eeNWDd
EzT0QN5B1Ai9BR/ApMMCAwEAATANBgkqhkiG9w0BAQUFAAOBgQBiqHZsuVP09ubT
GzBSlAFEoqbM63sU51nwQpzkVObgGm9v9nnxS8Atid4be0THsz8nVjWcDym3Tydp
lznrhoSrHyqAAlK3/WSMwyuPnDCNM5g1RdsV40TjZXk9/md8xWxGJ6n1MoBdlK8T
H6h2ROkf59bb096TttB8lxXiT0uiDQ==
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIBkjCB/AIJAI3bCYqa39hiMA0GCSqGSIb3DQEBBQUAMA0xCzAJBgNVBAYTAiAg
MCAXDTE4MTEyNDA5MDMzOFoYDzIwOTkxMjMxMDkwMzM4WjANMQswCQYDVQQGEwIg
IDCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA18hepvNcznqDj735Opxircn3
M0Ruv8nkpHHPuurxr6tLPKAe1XAsy5dWHDbK7t4sXpT0ds9c74yqmvfwKofPk7z9
ZBhmyw/5sp454/JftL1c2fr58wB9ETfX6as5aR5hQR0M0NuQLSAB/KVzi9eeNWDd
EzT0QN5B1Ai9BR/ApMMCAwEAATANBgkqhkiG9w0BAQUFAAOBgQBiqHZsuVP09ubT
GzBSlAFEoqbM63sU51nwQpzkVObgGm9v9nnxS8Atid4be0THsz8nVjWcDym3Tydp
lznrhoSrHyqAAlK3/WSMwyuPnDCNM5g1RdsV40TjZXk9/md8xWxGJ6n1MoBdlK8T
H6h2ROkf59bb096TttB8lxXiT0uiDQ==
-----END CERTIFICATE-----
# 可选| 配置替换真实IP请求头
注:该配置需要在CDN处配置连接IP header为connect-ip,不同cdn配置方式不同,如Cloudflare在托管转换中配置动态字段,具体请参考CDN官方文档。
为了防止假IP欺骗,除了可以在CDN处hide掉有关于IP的header,也可以使用自定义请求头记录IP(雷池控制台内设置connect-ip)。考虑到雷池后应用兼容性,可以把标准IP header覆盖替换。
在Tengine配置文件开始后插入:
#设置真实IP
map $http_connect_ip $custom_x_forwarded_for {
default $proxy_add_x_forwarded_for;
"~^(\d+\.\d+\.\d+\.\d+)$" $1;
"~^([0-9A-Fa-f:]+)$" $1;
}
map $http_connect_ip $custom_x_real_ip {
default $remote_addr;
"~^(\d+\.\d+\.\d+\.\d+)$" $1;
"~^([0-9A-Fa-f:]+)$" $1;
}
这段配置文件意思是,如果有connect-ip,则用connect-ip的值,如果没有,则用原来的header的值。
在location ^~ / { }块中,替换修改相关header的值
proxy_set_header X-Real-IP $custom_x_real_ip;
proxy_set_header X-Forwarded-For $custom_x_forwarded_for;
proxy_set_header REMOTE-HOST $custom_x_real_ip;
完成配置后,你需要重启Tengine使配置生效,值得注意的是,雷池的Tengine配置文件在容器重启后或更改了站点配置,会重新生成新的配置文件并覆盖,所以需要在雷池容器内执行nginx -t,检查无误后执行nginx -s reload命令重启nginx。建议备份配置文件至其他目录,在重启服务器、容器,或更改了站点配置后,需要重新覆盖配置文件并在容器内重启nginx。以下是如何操作的示例。
op@bj-0002-TS:~$ sudo docker ps -a
[sudo] op 的密码:
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
7ef59a03fe31 chaitin/safeline-tengine:latest "docker-entrypoint.s…" 4 days ago Up 4 days (healthy) safeline-tengine
ff8c5af19387 chaitin/safeline-mario:latest "/mario/entrypoint.sh" 4 days ago Up 2 days (healthy) safeline-mario
0172e26fe8f5 postgres:15.2 "docker-entrypoint.s…" 4 days ago Up 4 days 5432/tcp safeline-postgres
1b857054f8bd chaitin/safeline-fvm-manager:latest "/app/entrypoint.sh" 4 days ago Up 4 days safeline-fvm-manager
78f39efeb529 chaitin/safeline-mgt-api:latest "/app/entrypoint.sh" 4 days ago Up 4 days 0.0.0.0:9443->1443/tcp, :::9443->1443/tcp safeline-mgt-api
54b84762b2a6 chaitin/safeline-detector:latest "/detector/entrypoin…" 4 days ago Up 4 days (healthy) 8000-8001/tcp safeline-detector
op@bj-0002-TS:~$ sudo docker container exec -it 7ef59a03fe31 /bin/bash
root@bj-0002-TS:/# nginx -t
nginx: [warn] conflicting server name "" on 0.0.0.0:443, ignored
nginx: [warn] conflicting server name "" on 0.0.0.0:80, ignored
nginx: [warn] conflicting server name "" on [::]:80, ignored
nginx: [warn] conflicting server name "" on [::]:443, ignored
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
root@bj-0002-TS:/# nginx -s reload
nginx: [warn] conflicting server name "" on 0.0.0.0:443, ignored
nginx: [warn] conflicting server name "" on 0.0.0.0:80, ignored
nginx: [warn] conflicting server name "" on [::]:80, ignored
nginx: [warn] conflicting server name "" on [::]:443, ignored
root@bj-0002-TS:/# exit
exit
op@bj-0002-TS:~$
配置完毕后,直接访问IP地址或不存在的网站,则会返回一个空证书,并且拦截返回418状态码。
## 关于雷池人机验证的一些正则表达式
雷池的人机验证功能可以很好的防护机器人扫描以及HTTP Flood攻击,以下是一些针对User-Agent的验证规则。
匹配旧版本Chrome:
^Mozilla\/5\.0 \(.+?\) AppleWebKit\/.+? \(KHTML, like Gecko\) Chrome\/([1-7]\d|[1-9])\..+? Safari\/.+?$
匹配旧版本Firefox:
^Mozilla\/5\.0 \(.+?\) Gecko\/.+? Firefox\/([1-9]|[1-5]\d|6[0-3])\..+?$
匹配旧版本Safari:
^Mozilla\/5.0 (.+?) AppleWebKit\/.+? (KHTML, like Gecko) Version\/([1-9]|1[0-1])..+? Safari\/.+?$
匹配不包含Mozilla/5.0
^(?!.*Mozilla/5\.0).*$
匹配地区(如果CDN会返回IP属地信息的话):
(MX|SG|TW|NL|DE|PH|JP|...)
###
#按要求删除此段内容#
# Nginx自定义拦截记录日志
在我们的日常使用中,会直接在Nginx配置一些拦截规则,而被拦截的请求不会单独记录日志,例如我的香港中转服务器依然使用NAXSI进行基础过滤。如果规则有误则很难排查问题,在研究雷池的拦截页面后,我按照雷池的记录拦截ID的思路,使用LUA编写了一段代码以完成我的需求。需要注意,Nginx必须安装了LUA模块才能使用此代码,Tengine和Openresty已经默认安装LUA模块,执行nginx -V (大写) 检查是否安装了LUA模块。
## 代码部署
local function generate_unique_id()
-- 生成一个基于时间和随机数的唯一ID
local time_in_ms = ngx.now() * 1000
local random_num = math.random(10000, 99999)
return string.format("%s-%s", time_in_ms, random_num)
end
local function log_request_and_generate_hash()
-- 使用Nginx的变量获取请求IP
local client_ip = ngx.var.custom_x_real_ip
local request_time = os.date("%Y-%m-%d %H:%M:%S", ngx.time())
local request_url = ngx.var.request_uri
local user_agent = ngx.var.http_user_agent
local host = ngx.var.http_host
-- 生成唯一的错误ID
local error_id = generate_unique_id()
-- 使用Lua的table和concat函数生成一个简单的哈希
local hash_table = {host,client_ip, request_time, request_url, user_agent, error_id}
local hash_value = table.concat(hash_table, "|")
-- 返回请求信息、哈希值和错误ID
return host,client_ip, request_time, request_url, user_agent, hash_value, error_id
end
-- 获取当前状态码
local status = ngx.var.status
-- 检查状态码是否为418
if status == "418" then
-- 记录请求并生成哈希
local host,client_ip, request_time, request_url, user_agent, hash_value, error_id = log_request_and_generate_hash()
-- 打开文件以追加模式
local file, err = io.open("/www/err/418/error.log", "a")
if not file then
ngx.log(ngx.ERR, "无法打开文件 /www/err/418/error.log: ", err)
return
end
-- 记录请求信息、哈希值和错误ID
-- 记录哈希值和错误ID
local log_entry = string.format("%s\n", hash_value)
local success, err = file:write(log_entry)
if not success then
ngx.log(ngx.ERR, "无法写入文件 /www/err/418/error.log: ", err)
return
end
file:close()
-- 读取418.html文件内容
local error_file, err = io.open("/www/err/418.html", "r")
if not error_file then
ngx.log(ngx.ERR, "无法打开文件 /www/err/418.html: ", err)
return
end
local file_content = error_file:read("*a")
error_file:close()
-- 在错误页面中添加错误ID的注释
file_content = file_content .. "\n<!-- event_id: " .. error_id .. " -->"
-- 输出418.html文件内容和错误ID
ngx.say(file_content)
else
ngx.log(ngx.ERR, "状态码不是418,当前状态码为: ", status)
end
需要确保/www/err/418.html和日志目录/www/err/418/error.log真实存在,418状态码为我自定义的拦截代码,该代码为一个愚人节玩笑而非非,I'M A TEAPOT,虽然418状态码在RFC 7231中并未明确定义,但它仍然被4xx(客户端错误)类别所覆盖。然而,这个状态码并不是用来严肃对待的,也不会对客户端或SEO产生实质性影响。这个状态码在实际应用中很少使用,但在一些特定的情况下,开发者可能会使用它来进行一些特殊的处理。例如,如果服务器收到了一个无法处理的请求,它可能会返回418状态码,表示"我是茶壶,找咖啡壶去"。这就是说,这个请求应该由其他能够处理的服务器(咖啡壶)来处理。使用418状态码为了不影响403页面的正常响应。
在418.html中,使用如下JavaScript代码获取拦截ID:
<script>
//此处为获取访客IP
async function getIPInfo() {
const response = await fetch('https://api.gymxbl.com/ip/get');
const data = await response.json();
return data;
}
function ipinfo() {
getIPInfo().then(data => {
const li = document.getElementById('ip-info');
li.textContent += `${data.cip} Location: ${data.clo}`;
});
}
function setEventIDAndType() {
var nodes = document.getElementsByTagName("body")[0].childNodes;
var fit2inserts = null;
for (var i = 0; i < nodes.length; i++) {
if (
nodes[i].nodeType == 8 &&
nodes[i].data.trimLeft().startsWith("event_id")
) {
fit2inserts = nodes[i];
}
}
try {
var inserts =
document.getElementsByTagName("html")[0].nextSibling || fit2inserts;
var insertsData = inserts && (inserts.data || "");
var incertDataList = insertsData.split(" ");
var getVal = function (key) {
return incertDataList[incertDataList.indexOf(key + ":") + 1];
};
var event_id = getVal("event_id");
var type = getVal("type");
// var anymore = getVal('anymore') // 新增参数示例
} catch (e) {
console.log(e);
}
if (event_id) {
document.getElementById("EventID").innerText = "你的ID(•ω•):" + event_id;
}
if (type) {
document.getElementById("TYPE").innerText = "TYPE: " + type;
}
}
// 使用addEventListener添加事件监听器
window.addEventListener('load', function() {
ipinfo();
setEventIDAndType();
});
//这一段基本是从雷池的拦截页抄的
</script>
接下来在希望向访客展示错误的地方将ID填入: id="ip-info" id="EventID"
<div class="md:flex min-h-screen main-body">
<div class="w-full md:w-1/2 bg-white flex items-center justify-center left-sec">
<div class="max-w-sm m-8 content-body">
<div class="text-black text-5xl md:text-15xl font-black">访问被拦截了哦 ヽ(*。>Д<)o゜</div>
<p class="text-grey-darker text-2xl md:text-3xl mb-7 leading-normal">
</p>
<p class="sub-header">
<h1>好好反省为什么会被拦截叭!(ノ`Д)ノ</h1>
</p>
<br>
<br>
我是一个茶壶!I'm a teapot!
<div class="sub-footer">
<div class="w-full h-2 bg-grey-light my-3 md:my-6"></div>
<ul>
<p></p>
<li id="EventID"></li>
<br>
<li id="ip-info">你的IP: </li>
<br>
<li>发生时间: <script type="text/javascript">
document.write(Date())
</script>
</li>
<br>
<li>拦截由 Lua 脚本</li>
</ul>
</div>
</div>
</div>
<div class="relative pb-full md:flex md:pb-0 md:min-h-screen w-full md:w-1/2 right-sec">
</div>
</div>
此HTML仅为示例,使用时需要自行定制。
## 部署Nginx
在你希望应用该页面的域名所属Server块中添加:
location = /418.html
{
#交给LUA处理
content_by_lua_file /www/lua/418.lua;
#禁止外部访问,404错误码
error_page 404 /404.html;
#仅允许内部访问
internal;
}
#哦对了别忘了把errpage加上,特意回来加一句.....
error_page 418 /418.html;
重启Nginx使能生效。
# 总结
本文介绍了如何使用和配置雷池WAF,包括设置默认站点的重要性,配置Tengine的方法,以及一些有用的人机验证正则表达式。我们还讨论了如何自定义Nginx的拦截记录日志,并提供了代码部署的步骤。希望这些信息能帮助你更好地使用雷池WAF,提升你的网络安全防护能力。感谢你的阅读。
# 闲言碎语
关于今年一年没有正式更新,我很抱歉,因为身体抱恙,并且在深入了解了许多领域后,我发现我懂得不够多,很多内容是其他人做过的,所以我不需要在做一遍。目前仍然在深度了解学习商用设备,包括Fortinet,思科等厂商的商业设备,学习配置SSL-VPN和IPSec以及BGP路由,了解真正的UTM统一威胁管理是如何配置以及运作。
另外,好哥们送了我一台Lenovo SystemX3650M5 TYPE 8871的2U机架式服务器,我打算使用该服务器进行深度学习领域探索,将原先服务器上的Tesla P4计算卡安装在了该台服务器中,并使用iSCSI协议共享原服务器的存储空间。目前仍在了解GLM与RWKV等LLM模型,期待我能有更好的突破吧。
版权声明:转载时请以超链接形式标明文章原始出处和作者信息,来源孤影墨香本文链接: https://www.iloli.xin/3951.html
访问时间:2024-12-02 12:27:32
Comments | 15 条评论
博主 紗夕里
该评论为私密评论
博主 small_xu038
@紗夕里 可以
博主 久违了
大佬用的什么系统 我这centos7.6貌似不太行
nginx: [emerg] unknown directive "content_by_lua_file" in /etc/nginx/sites-enabled/IF_backend_1:24
nginx: configuration file /etc/nginx/nginx.conf test failed,用不了lua
博主 small_xu038
@久违了 unknown directive "content_by_lua_file" 因为Nginx的LUA模块未安装,你需要在编译Nginx时候带上LUA相关模块,或者使用Tengine以及Openresty这种自带LUA模块的Nginx发行版。并且确认系统的LuaJIT环境是否正常。
接下来我打算继续发布一些用LUA写的小玩具,所以如果不解决这个问题就无法继续使用。
现在你需要重新安装Nginx,在安装时编译选项加上Ngx-Lua模块,或者直接使用Tengine以及Openresty这种自带LUA模块的Nginx发行版。进行任何风险操作前,应备份服务器配置文件等重要文件,最好是打个快照或CheckPoint,方便恢复。
博主 久违了。
@small_xu038 雷池使用的就是Tengine,我也测试了nginx -V,但还是这样
博主 small_xu038
@久违了。 雷池的Tengine是雷池自己定制修改的,他没有安装LUA模块,你也不应该将这个脚本用在雷池。你的源站如果是宝塔面板安装的Nginx的话是应该是自带LUA的。
博主 small_xu038
@久违了 另外就是您的QQ个人资料为私密,QQ名称获取失败,如果您愿意的话可以使用评论提交QQ昵称,我来修改一下
博主 久违了。
@small_xu038 久违了。
博主 陈陈菌
学习了
博主 nuoyis
很好,看着这家庭存储我有点羡慕,有自己的住所就可以全屋试试
博主 small_xu038
@nuoyis emmm其实噪音还是有那么一点点的
真的
博主 misakabit
好
博主 small_xu038
@misakabit 好诶
博主 紗夕里
好!我也整一个雷池玩玩(性能本就有限的VPS变得更慢了)
博主 small_xu038
@紗夕里 好诶,但其实不会占用多少CPU性能,雷池更多的是占用内存。所以我雷池是单独一台服务器部署的。