在这里插入图片描述

在网站运营过程中,我们经常会遇到各种恶意扫描、爬虫或攻击行为。宝塔面板自带的防火墙(WAF)提供了基础的防护能力,但有时我们需要更灵活、更智能的IP封禁策略,例如基于自定义的访问行为或IP类型进行判断。

本文将介绍一种方法,通过修改宝塔WAF的配置文件 waf.lua,使其能够读取一个自定义的IP列表文件,并对列表中的IP进行自动封禁。结合您已有的IP检测逻辑(如识别假登录访问、高频访问、非蜘蛛的机房IP等),可以构建一个强大的自动化防御体系。

核心思路

  1. 自定义IP检测与写入: 假设您已经在网站层面实现了IP检测逻辑,能够识别出需要封禁的IP(例如访问特定假入口、访问频率过高、非蜘蛛的机房IP等)。这些被识别出的恶意IP将被写入到一个指定的文本文件,例如 /www/wwwroot/api/banned_ips.txt,每行一个IP。
  2. 修改宝塔WAF配置: 修改宝塔WAF的核心配置文件 waf.lua。在处理每个HTTP请求时,WAF会读取 /www/wwwroot/api/banned_ips.txt 文件,检查当前请求的客户端IP是否在该文件中。
  3. 执行封禁: 如果客户端IP存在于 banned_ips.txt 文件中,WAF将立即终止该请求,并返回一个特定的状态码(例如 444),从而实现自动拉黑。

这种方法的优点在于,IP检测逻辑可以完全自定义并在您的网站应用层面实现,而封禁的执行则下放到更底层的WAF层面,效率更高,且能拦截对网站任何资源的访问(包括静态文件)。

操作步骤

重要提示: 修改宝塔面板的核心配置文件存在风险,操作前请务必备份相关文件!如果操作不当可能导致网站无法访问或WAF功能失效。

  1. 生效方式:确保宝塔WAF以及站点防火墙已开启: 在宝塔面板中,进入“网站”菜单,选择您的网站,点击“设置”,找到“网站防火墙(WAF)”,确保其已开启。在站点设置中,开启状态的站点才会受到保护。如果nginx防火墙或站点没开启防火墙,不受封禁列表影响。

  2. 创建并维护封禁IP文件:

    • 创建您指定的封禁IP文件,例如 /www/wwwroot/api/banned_ips.txt。您可以使用SSH命令创建:
      touch /www/wwwroot/api/banned_ips.txt
      
    • 确保您的网站应用(例如PHP脚本)有权限向此文件写入内容。通常,将文件放在网站根目录下,并确保文件权限正确(例如 644666,取决于您的需求和安全设置,但需要确保Nginx用户有读取权限,您的写入脚本有写入权限)。
    • 您的IP检测脚本需要负责将需要封禁的IP按行写入此文件。例如,使用PHP的 file_put_contents 函数以追加模式写入,并在写入前检查IP是否已存在,避免重复。
  3. 备份 waf.lua 文件:

    • 通过宝塔面板的文件管理器或SSH进入 /www/server/btwaf/ 目录。
    • 找到 waf.lua 文件,将其复制一份作为备份,例如命名为 waf.lua.bak
  4. 修改 waf.lua 文件:

    • 修改waf.lua前需要先关闭Nginx防火墙。修改完再打开防火墙
    • 使用宝塔面板的文件编辑器或SSH编辑器打开 /www/server/btwaf/waf.lua 文件。
    • 找到获取客户端IP的代码行,通常是 local ip = IpInfo.get_client_ip_bylog()
    • 在获取客户端IP的代码之后,获取args参数的代码之前(或者根据您提供的代码片段,直接插入到获取IP和获取cookie信息之间),插入您提供的Lua代码。

    找到类似以下结构的代码位置:

    -- --获取客户端的IP
    local ip = IpInfo.get_client_ip_bylog()
    -- --获取args参数
    ngx.ctx.get_uri_args = ngx.req.get_uri_args(100000)
    
    -- ... 其他代码 ...
    
    --获取cookie的信息
    -- ... 获取cookie的代码 ...
    

    将代码插入到 ngx.ctx.get_uri_args 之前:

    -- --获取客户端的IP
    local ip = IpInfo.get_client_ip_bylog()
    -- --获取args参数
    ngx.ctx.get_uri_args = ngx.req.get_uri_args(100000)
    
    -- >>>>>>>>>>>>>>>>>>>>>>> 新增代码开始 (包含日志记录) <<<<<<<<<<<<<<<<<<<<<<<<<
    -- 定义封禁IP列表文件的路径
    local banned_ips_file = "/www/wwwroot/api/banned_ips.txt"
    
    -- 检查封禁IP文件是否存在
    local file = io.open(banned_ips_file, "r")
    if file then
        -- 文件存在,逐行读取并检查客户端IP是否在列表中
        for line in file:lines() do
            -- 移除行首尾的空白字符
            local banned_ip = string.match(line, "^%s*(.-)%s*$")
            -- 如果行不为空且与客户端IP匹配
            if banned_ip ~= "" and banned_ip == ip then
                -- 客户端IP在封禁列表中
                -- 记录封禁日志信息
                Public.logs("Blocked banned IP: " .. ip .. " from file " .. banned_ips_file .. " for URL: " .. ngx.var.request_uri)
                file:close() -- 在退出前关闭文件
                -- 返回444状态码
                ngx.exit(444)
            end
        end
        file:close() -- 如果循环结束仍未找到匹配,关闭文件
    end
    -- >>>>>>>>>>>>>>>>>>>>>>> 新增代码结束 <<<<<<<<<<<<<<<<<<<<<<<<<
    
    --获取cookie的信息
    -- ... 获取cookie的代码 ...
    

    代码解释:

    • local banned_ips_file = "/www/wwwroot/api/banned_ips.txt": 定义了存储封禁IP的文件路径。
    • local file = io.open(banned_ips_file, "r"): 尝试以只读模式打开指定的封禁IP文件。
    • if file then ... end: 检查文件是否成功打开。如果文件不存在或无法读取,则跳过封禁检查。
    • for line in file:lines() do ... end: 如果文件打开成功,则逐行读取文件内容。
    • local banned_ip = string.match(line, "^%s*(.-)%s*$"): 使用Lua的字符串匹配功能,提取当前行的内容,并去除行首尾的空白字符。
    • if banned_ip ~= "" and banned_ip == ip then ... end: 判断提取出的IP是否非空,并且是否与当前请求的客户端IP (ip) 相匹配。
    • Public.logs(...): 如果IP匹配,则调用宝塔WAF的日志函数记录一条封禁日志,方便后续排查。
    • file:close(): 关闭文件句柄。在找到匹配IP并退出前关闭,或者在遍历完整个文件后关闭。
    • ngx.exit(444): 这是OpenResty/Nginx Lua模块提供的函数,用于终止当前请求并返回指定的HTTP状态码。444是一个非标准的Nginx状态码,表示“无响应”,客户端会直接断开连接。
  5. 保存文件并重启Nginx:

    • 保存对 waf.lua 文件的修改。
    • 在宝塔面板中,进入“软件商店”,找到“Nginx”,点击“设置”,然后点击“重启”。重启Nginx服务会加载新的WAF配置。

测试

  1. /www/wwwroot/api/banned_ips.txt 文件中手动添加您当前的公网IP(确保每行只有一个IP)。
  2. 尝试访问您的网站。如果配置成功,您的浏览器应该会显示连接被重置或无法访问,并且在Nginx的错误日志或宝塔WAF的日志中应该能看到相关的封禁记录。
  3. 测试完成后,记得从 banned_ips.txt 文件中移除您的IP。

注意事项

  • 性能影响: 对于高流量网站,每次请求都需要读取并遍历 banned_ips.txt 文件。如果这个文件非常大(包含成千上万个IP),可能会对服务器性能产生一定影响。可以考虑优化文件读取逻辑,或者对于超大型列表,探索使用Lua共享内存或Redis等方式存储封禁IP。
  • 文件权限: 确保Nginx运行用户(通常是 www)对 /www/wwwroot/api/banned_ips.txt 文件有读取权限。您的IP写入脚本用户对该文件有写入权限。
  • 误杀: 您的IP检测逻辑是关键。请务必谨慎设计拉黑规则,避免误封正常用户或搜索引擎蜘蛛。
  • 宝塔更新: 宝塔面板或WAF插件更新时,可能会覆盖 waf.lua 文件。在更新前请再次备份,更新后检查并重新应用您的修改。
  • 日志: 代码中包含了日志记录,这对于排查问题和监控封禁情况非常有用。请定期查看相关日志。

通过以上步骤,您就成功地将宝塔WAF与您的自定义IP检测逻辑结合起来,实现了基于文件列表的自动化IP拉黑功能。


Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐